gpml2pvjson
Version:
convert GPML (XML) to pvjson (json)
337 lines • 25.4 kB
JavaScript
import { findIndex } from "lodash/fp";
import { getStartSideByOrientation } from "../geom-utils";
import { DEFAULT_STUB_LENGTH } from "./edge";
import { getOrientationOfHyperedgeStartPoint, getOrientationOfHyperedgeEndPoint, validateOrientation } from "./orientation";
/*
import {
Point,
PvjsonEdge,
AttachablePoint,
,
SegmentPoint
} from "../gpml2pvjson";
//*/
const INDEX_TO_DIMENSION = ["x", "y"];
function getActiveOrientationIndexAndDimension(orientation) {
const activeOrientationIndex = findIndex((orientationScalar) => orientationScalar !== 0, orientation);
const activeOrientationDimension = INDEX_TO_DIMENSION[activeOrientationIndex];
const otherOrientationDimension = activeOrientationDimension === "x" ? "y" : "x";
return {
activeOrientationIndex,
activeOrientationDimension,
otherOrientationDimension
};
}
/**
* calculateAllPoints for edges of type Elbow and Curved
*
* PathVisio-Java does not always specify all the points needed to draw edges
* of type Elbow and Curved. Unless the user drags one or more of the
* waypoints, PathVisio-Java will only specify the first and last points,
* leaving implicit one or more additional points that are required to draw
* the edge.
*
* Kaavio requires that a PvjsonEdge specifies ALL the points required for
* drawing the edge, so this function calculates any implicit points required
* to unambiguously specify an edge and returns the full set of points
* (implicit points are made explicit).
*
* @param explicitPoints {Array}
* @param [sourceEntity] {Object} entity from which the EDGE emanates
* (never an Anchor)
* @param [targetEntity] {Object} entity into which the EDGE terminates
* (never an Anchor)
* @return {Array} Full set of points required to render the edge
*/
export function calculateAllPoints(explicitPoints, sourceEntity, targetEntity) {
let firstPoint = explicitPoints[0];
let lastPoint = explicitPoints[explicitPoints.length - 1];
// NOTE: we need at least one of the first point or the last point to have a
// valid orientation. If that's not the case already, we try setting it here,
// based on other information available to us.
if (!validateOrientation(firstPoint.orientation)) {
if (firstPoint.hasOwnProperty("isAttachedTo")) {
// It is correct to specify <PvjsonEdge> as the type for
// sourceEntity/targetEntity when calculating the orientation of a point
// attached to another edge below, because we get into there if neither
// the first nor last point have a valid orientation. If a point is
// attached to a SingleFreeNode, a Group or a GPML State, it would already
// have a valid orientation calculated by this point, so the point must
// be either attached to nothing or else attached to an edge.
firstPoint.orientation = getOrientationOfHyperedgeStartPoint(sourceEntity, firstPoint, lastPoint);
}
else {
firstPoint.orientation = [-1, 0];
}
}
if (!validateOrientation(lastPoint.orientation)) {
if (lastPoint.hasOwnProperty("isAttachedTo")) {
// It is correct to specify <PvjsonEdge> as the type for
// sourceEntity/targetEntity when calculating the orientation of a point
// attached to another edge below, because we get into there if neither
// the first nor last point have a valid orientation. If a point is
// attached to a SingleFreeNode, a Group or a GPML State, it would already
// have a valid orientation calculated by this point, so the point must
// be either attached to nothing or else attached to an edge.
lastPoint.orientation = getOrientationOfHyperedgeEndPoint(targetEntity, lastPoint, firstPoint);
}
else {
const { x: x0, y: y0 } = firstPoint;
const { x: x1, y: y1 } = lastPoint;
const firstSide = getStartSideByOrientation(firstPoint.orientation);
if (firstSide === "left") {
if (x0 >= x1 && x0 < x1 + DEFAULT_STUB_LENGTH) {
lastPoint.orientation = [1, 0];
}
else {
lastPoint.orientation = [-1, 0];
}
}
else if (firstSide === "right") {
if (x0 + DEFAULT_STUB_LENGTH <= x1) {
lastPoint.orientation = [1, 0];
}
else {
lastPoint.orientation = [-1, 0];
}
}
else {
lastPoint.orientation = [-1, 0];
}
}
}
if (explicitPoints.length > 2) {
return explicitPoints;
}
let startPoint;
let endPoint;
let endEntity;
let pointOrderReversed;
if (validateOrientation(firstPoint.orientation)) {
pointOrderReversed = false;
startPoint = firstPoint;
endPoint = lastPoint;
endEntity = targetEntity;
}
else if (validateOrientation(lastPoint.orientation)) {
pointOrderReversed = true;
startPoint = lastPoint;
endPoint = firstPoint;
endEntity = sourceEntity;
}
else {
throw new Error(`Either first or last point (or both) should have a valid
orientation by now in
calculateAllPoints(
${JSON.stringify(explicitPoints)},
${JSON.stringify(sourceEntity)},
${JSON.stringify(targetEntity)}
)`);
}
const startOrientation = startPoint.orientation;
const endOrientation = endPoint.orientation;
const vectorSumOrientation = [
Math.sign(endPoint.x - startPoint.x),
Math.sign(endPoint.y - startPoint.y)
];
const { activeOrientationIndex: activeStartOrientationIndex, activeOrientationDimension: activeStartOrientationDimension, otherOrientationDimension: otherStartOrientationDimension } = getActiveOrientationIndexAndDimension(startOrientation);
const { activeOrientationIndex: activeEndOrientationIndex, activeOrientationDimension: activeEndOrientationDimension, otherOrientationDimension: otherEndOrientationDimension } = getActiveOrientationIndexAndDimension(endOrientation);
const pvjsonPoints = [];
pvjsonPoints.push(startPoint);
// Calculate intermediate data points, which are implicit.
// Remember that this refers to the minimum number of points required to
// define the path, so 3 points could mean this:
//
// -------------------*-------------------
// | |
// | |
// * *
//
// or this:
// *
// |
// |
// -------------------*-------------------
// |
// |
// *
//
// or several other possible configurations
// NOTE: when an edge is connected to a SingleFreeNode or a Group (how about a State?),
// PathVisio-Java will route the edge around the side from which the edge
// emanates, if needed.
// But when an edge is connected to another edge, PathVisio-Java
// does not do any special re-routing for that connection.
if (activeStartOrientationIndex === activeEndOrientationIndex) {
// Start and end orientations are parallel, e.g.,
// starts at right and ends on either right or left side, or
// starts on top and ends on either top or bottom side.
const activeOrientationIndex = activeStartOrientationIndex;
const activeOrientationDimension = activeStartOrientationDimension;
const otherOrientationDimension = otherStartOrientationDimension;
const otherOrientationDimensionDisplacement = endPoint[otherOrientationDimension] -
startPoint[otherOrientationDimension];
if (startOrientation[activeOrientationIndex] ===
vectorSumOrientation[activeOrientationIndex]) {
// we don't have to avoid the start side
pvjsonPoints[1] = {};
pvjsonPoints[1][otherOrientationDimension] =
startPoint[otherOrientationDimension] +
otherOrientationDimensionDisplacement / 2;
if (startOrientation[activeOrientationIndex] ===
endOrientation[activeOrientationIndex]) {
// *---
// |
// |
// *
// |
// |
// ---------------------*
pvjsonPoints[1][activeOrientationDimension] =
startPoint[activeOrientationDimension] +
startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
}
else {
// *-------------------------
// |
// |
// *
// |
// |
// *---
pvjsonPoints[1][activeOrientationDimension] =
endPoint[activeOrientationDimension] -
endOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
}
}
else {
// must initially route around start side
if (startOrientation[activeOrientationIndex] ===
endOrientation[activeOrientationIndex]) {
// *---
// |
// |
// *
// |
// |
// -----------*-----------
// |
// |
// *
// |
// |
// ---*
pvjsonPoints[1] = {};
pvjsonPoints[1][activeOrientationDimension] =
startPoint[activeOrientationDimension] +
startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
pvjsonPoints[1][otherOrientationDimension] =
startPoint[otherOrientationDimension] +
otherOrientationDimensionDisplacement / 4;
pvjsonPoints[2] = {};
pvjsonPoints[2][activeOrientationDimension] =
(startPoint[activeOrientationDimension] +
endPoint[activeOrientationDimension]) /
2;
pvjsonPoints[2][otherOrientationDimension] =
startPoint[otherOrientationDimension] +
otherOrientationDimensionDisplacement / 2;
pvjsonPoints[3] = {};
pvjsonPoints[3][activeOrientationDimension] =
endPoint[activeOrientationDimension] -
endOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
pvjsonPoints[3][otherOrientationDimension] =
startPoint[otherOrientationDimension] +
(3 * otherOrientationDimensionDisplacement) / 4;
}
else {
// *---
// |
// |
// *
// |
// |
// *---------------------
pvjsonPoints[1] = {};
pvjsonPoints[1][activeOrientationDimension] =
startPoint[activeOrientationDimension] +
startOrientation[activeOrientationIndex] * DEFAULT_STUB_LENGTH;
pvjsonPoints[1][otherOrientationDimension] =
startPoint[otherOrientationDimension] +
otherOrientationDimensionDisplacement / 2;
}
}
}
else {
// Start and end orientations are perpendicular
if (startOrientation[activeStartOrientationIndex] ===
vectorSumOrientation[activeStartOrientationIndex] &&
endOrientation[activeEndOrientationIndex] ===
vectorSumOrientation[activeEndOrientationIndex]) {
// *
// |
// |
// |
// |
// |
// ---------------------*
//
// Do nothing.
}
else {
// ---*
// |
// |
// |
// *
// * |
// | |
// | |
// --------*--------
//
// or *---
// |
// |
// |
// *
// * |
// | |
// | |
// --------*--------
//
// or
//
// ----*
// |
// |
// *
// |
// |
// ---*---
// |
// |
// *
const otherStartOrientationDimensionDisplacement = endPoint[otherStartOrientationDimension] -
endOrientation[activeEndOrientationIndex] * DEFAULT_STUB_LENGTH -
startPoint[otherStartOrientationDimension];
pvjsonPoints[1] = {};
pvjsonPoints[1][activeStartOrientationDimension] =
startPoint[activeStartOrientationDimension] +
startOrientation[activeStartOrientationIndex] * DEFAULT_STUB_LENGTH;
pvjsonPoints[1][otherStartOrientationDimension] =
startPoint[otherStartOrientationDimension] +
otherStartOrientationDimensionDisplacement / 2;
pvjsonPoints[2] = {};
pvjsonPoints[2][activeEndOrientationDimension] =
endPoint[activeEndOrientationDimension] -
endOrientation[activeEndOrientationIndex] * DEFAULT_STUB_LENGTH;
pvjsonPoints[2][otherEndOrientationDimension] =
(pvjsonPoints[1][otherEndOrientationDimension] +
endPoint[otherEndOrientationDimension]) /
2;
}
}
pvjsonPoints.push(endPoint);
return pointOrderReversed ? pvjsonPoints.reverse() : pvjsonPoints;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsY3VsYXRlQWxsUG9pbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VkZ2UvY2FsY3VsYXRlQWxsUG9pbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBUSxTQUFTLEVBQTRCLE1BQU0sV0FBVyxDQUFDO0FBQ3RFLE9BQU8sRUFNTCx5QkFBeUIsRUFJMUIsTUFBTSxlQUFlLENBQUM7QUFTdkIsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzdDLE9BQU8sRUFDTCxtQ0FBbUMsRUFDbkMsaUNBQWlDLEVBQ2pDLG1CQUFtQixFQUNwQixNQUFNLGVBQWUsQ0FBQztBQUN2Qjs7Ozs7Ozs7SUFRSTtBQUVKLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7QUFFdEMsU0FBUyxxQ0FBcUMsQ0FBQyxXQUE2QjtJQUMxRSxNQUFNLHNCQUFzQixHQUFHLFNBQVMsQ0FDdEMsQ0FBQyxpQkFBeUIsRUFBRSxFQUFFLENBQUMsaUJBQWlCLEtBQUssQ0FBQyxFQUN0RCxXQUFXLENBQ1osQ0FBQztJQUNGLE1BQU0sMEJBQTBCLEdBQUcsa0JBQWtCLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUM5RSxNQUFNLHlCQUF5QixHQUM3QiwwQkFBMEIsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQ2pELE9BQU87UUFDTCxzQkFBc0I7UUFDdEIsMEJBQTBCO1FBQzFCLHlCQUF5QjtLQUMxQixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUNILE1BQU0sVUFBVSxrQkFBa0IsQ0FDaEMsY0FBc0MsRUFDdEMsWUFBc0MsRUFDdEMsWUFBc0M7SUFFdEMsSUFBSSxVQUFVLEdBQUcsY0FBYyxDQUFDLENBQUMsQ0FBaUMsQ0FBQztJQUNuRSxJQUFJLFNBQVMsR0FBRyxjQUFjLENB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