Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide JSON coordinate options #1071

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
915fa24
Target platform changes?
skieffer Aug 24, 2024
d07e112
Update .gitignore
skieffer Aug 24, 2024
d34db90
Supply missing map clear
skieffer Aug 25, 2024
9976add
Add maps to support coordinate adjustments
skieffer Aug 25, 2024
3e63089
Add comments
skieffer Aug 25, 2024
7208ee3
Add `org.eclipse.elk.json.edgeCoords` property
skieffer Aug 25, 2024
4d49d8b
Adjust edge coordinates according to mode
skieffer Aug 25, 2024
4f76fa0
Use extension methods
skieffer Aug 25, 2024
3683032
Add unit tests
skieffer Aug 25, 2024
0300a97
Use do-while loop
skieffer Aug 25, 2024
f72a435
Remove diagnostic output
skieffer Aug 25, 2024
6d152c9
Revert incidental changes
skieffer Aug 25, 2024
1cdd859
Use static method instead of deprecated json parser constructor
skieffer Aug 26, 2024
b1a02bc
Avoid NPE
skieffer Aug 26, 2024
331b06a
Remove additional cases of deprecated json parser constructor
skieffer Aug 26, 2024
8c03b80
Use `PlainJavaInitialization` in test
skieffer Aug 27, 2024
9a4d24f
Determine edge coord modes more efficiently
skieffer Aug 28, 2024
5e581f5
Simplify adjustment method signature
skieffer Aug 28, 2024
0f8a544
Make edge labels use same coord system as edge
skieffer Aug 28, 2024
81e082b
Add EOF newline
skieffer Aug 28, 2024
52fed6d
Support `org.eclipse.elk.json.shapeCoords` property
skieffer Aug 29, 2024
5d7cf1a
Update docs to cover coordinate options
skieffer Aug 29, 2024
2312415
Write `container` property into edges only in CONTAINER mode
skieffer Aug 29, 2024
82ea83d
Improve property descriptions
skieffer Aug 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions plugins/org.eclipse.elk.core/src/org/eclipse/elk/core/Core.melk
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,19 @@ advanced option omitNodeMicroLayout: boolean {
targets parents
}

// --- JSON
group json {

option edgeCoords: EdgeCoords {
label "Edge Coords"
description
"Specify the coordinate system for edge route points."
default = EdgeCoords.INHERIT
targets parents
}

}

// --- SPACING
group spacing {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2010, 2015 Kiel University and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.elk.core.options;

/**
* Definition of edge coordinate systems. To be accessed using {@link CoreOptions#JSON_EDGE_COORDS}.
*/
public enum EdgeCoords {

/**
* Inherit the parent node's coordinate system. The root node has no parent node; here, this setting defaults to
* {@link #CONTAINER}.
*/
INHERIT,
/** relative to the edge's proper container node. */
CONTAINER,
/** relative to the edge's JSON parent node. */
PARENT,
/** relative to the root node, a.k.a. global coordinates. */
ROOT;

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.google.common.collect.Multimap
import java.util.Map
import org.eclipse.elk.core.data.LayoutMetaDataService
import org.eclipse.elk.core.options.CoreOptions
import org.eclipse.elk.core.options.EdgeCoords
import org.eclipse.elk.core.util.IndividualSpacings
import org.eclipse.elk.graph.ElkEdge
import org.eclipse.elk.graph.ElkEdgeSection
Expand Down Expand Up @@ -58,6 +59,11 @@ final class JsonImporter {
val Map<ElkEdge, Object> edgeJsonMap = Maps.newHashMap
val Map<ElkEdgeSection, Object> edgeSectionJsonMap = Maps.newHashMap
val Map<ElkLabel, Object> labelJsonMap = Maps.newHashMap

/* Maps to help in adjusting coordinates */
val Map<ElkEdge, ElkNode> edgeOriginalParentMap = Maps.newHashMap
val Map<ElkNode, Double> nodeGlobalXMap = Maps.newHashMap
val Map<ElkNode, Double> nodeGlobalYMap = Maps.newHashMap

var Object inputModel

Expand Down Expand Up @@ -91,10 +97,16 @@ final class JsonImporter {
portIdMap.clear
edgeIdMap.clear
edgeSectionIdMap.clear

nodeJsonMap.clear
portJsonMap.clear
edgeJsonMap.clear
edgeSectionJsonMap.clear
edgeSectionJsonMap.clear
labelJsonMap.clear

edgeOriginalParentMap.clear
nodeGlobalXMap.clear
nodeGlobalYMap.clear
}

private def transformChildNodes(Object jsonNodeA, ElkNode parent) {
Expand Down Expand Up @@ -525,22 +537,34 @@ final class JsonImporter {
* Transfer the layout back to the formerly imported graph, using {@link #transform(Object)}.
*/
def transferLayout(ElkNode graph) {
// transfer layout of all elements (including root)
// First pass handles everything except edges, and computes global coordinates for all nodes.
ElkGraphUtil.propertiesSkippingIteratorFor(graph, true).forEach [ element |
element.transferLayoutInt
element.transferLayoutInt1
]

// Second pass handles edges.
ElkGraphUtil.propertiesSkippingIteratorFor(graph, true).forEach [ element |
element.transferLayoutInt2
]
}

private def dispatch transferLayoutInt(ElkNode node) {
private def dispatch transferLayoutInt1(ElkNode node) {
val jsonObj = nodeJsonMap.get(node)
if (jsonObj === null) {
throw formatError("Node did not exist in input.")
}
// Compute global coordinates, to support coordinate adjustments.
val parent = node.getParent
val dx = parent.globalX ?: 0
val dy = parent.globalY ?: 0
nodeGlobalXMap.put(node, node.x + dx)
nodeGlobalYMap.put(node, node.y + dy)

// transfer positions and dimension
node.transferShapeLayout(jsonObj)
}

private def dispatch transferLayoutInt(ElkPort port) {
private def dispatch transferLayoutInt1(ElkPort port) {
val jsonObj = portJsonMap.get(port)
if (jsonObj === null) {
throw formatError("Port did not exist in input.")
Expand All @@ -549,14 +573,46 @@ final class JsonImporter {
// transfer positions and dimension
port.transferShapeLayout(jsonObj)
}

private def EdgeCoords getEdgeCoordsMode(ElkNode node) {
var ancestor = node
var ecm = EdgeCoords.INHERIT
do {
if (ancestor !== null) {
ecm = ancestor.getProperty(CoreOptions.JSON_EDGE_COORDS) ?: EdgeCoords.INHERIT
} else {
ecm = EdgeCoords.CONTAINER
}
ancestor = ancestor.getParent
skieffer marked this conversation as resolved.
Show resolved Hide resolved
skieffer marked this conversation as resolved.
Show resolved Hide resolved
} while (ecm === EdgeCoords.INHERIT)
return ecm
}

private def Double adjustX(ElkEdge edge, EdgeCoords mode, Double x) {
switch mode {
case EdgeCoords.ROOT: x + edge.getContainingNode.globalX
case EdgeCoords.PARENT: x + edge.getContainingNode.globalX - edge.originalParent.globalX
default: x
}
}

private def Double adjustY(ElkEdge edge, EdgeCoords mode, Double y) {
switch mode {
case EdgeCoords.ROOT: y + edge.getContainingNode.globalY
case EdgeCoords.PARENT: y + edge.getContainingNode.globalY - edge.originalParent.globalY
default: y
}
}

private def dispatch transferLayoutInt(ElkEdge edge) {
private def dispatch transferLayoutInt2(ElkEdge edge) {
val jsonObj = edgeJsonMap.get(edge).toJsonObject
if (jsonObj === null) {
throw formatError("Edge did not exist in input.")
}

val edgeId = jsonObj.id

val ecm = edge.originalParent.getEdgeCoordsMode

// what we need to transfer are the edge sections
if (!edge.sections.nullOrEmpty) {
Expand All @@ -576,23 +632,23 @@ final class JsonImporter {

// Start Point
val startPoint = newJsonObject
startPoint.addJsonObj("x", elkSection.startX)
startPoint.addJsonObj("y", elkSection.startY)
startPoint.addJsonObj("x", edge.adjustX(ecm, elkSection.startX))
startPoint.addJsonObj("y", edge.adjustY(ecm, elkSection.startY))
jsonSection.addJsonObj("startPoint", startPoint)

// End Point
val endPoint = newJsonObject
endPoint.addJsonObj("x", elkSection.endX)
endPoint.addJsonObj("y", elkSection.endY)
endPoint.addJsonObj("x", edge.adjustX(ecm, elkSection.endX))
endPoint.addJsonObj("y", edge.adjustY(ecm, elkSection.endY))
jsonSection.addJsonObj("endPoint", endPoint)

// Bend Points
if (!elkSection.bendPoints.nullOrEmpty) {
val bendPoints = newJsonArray
elkSection.bendPoints.forEach [ pnt |
val jsonPnt = newJsonObject
jsonPnt.addJsonObj("x", pnt.x)
jsonPnt.addJsonObj("y", pnt.y)
jsonPnt.addJsonObj("x", edge.adjustX(ecm, pnt.x))
jsonPnt.addJsonObj("y", edge.adjustY(ecm, pnt.y))
bendPoints.addJsonArr(jsonPnt)
]
jsonSection.addJsonObj("bendPoints", bendPoints)
Expand Down Expand Up @@ -637,25 +693,29 @@ final class JsonImporter {
val jsonJPs = newJsonArray
jps.forEach[ jp |
val jsonPnt = newJsonObject
jsonPnt.addJsonObj("x", jp.x)
jsonPnt.addJsonObj("y", jp.y)
jsonPnt.addJsonObj("x", edge.adjustX(ecm, jp.x))
jsonPnt.addJsonObj("y", edge.adjustY(ecm, jp.y))
jsonJPs.addJsonArr(jsonPnt)
]
jsonObj.addJsonObj("junctionPoints", jsonJPs)
}
}

jsonObj.addJsonObj("container", edge.getContainingNode().identifier)
jsonObj.addJsonObj("container", edge.getContainingNode.identifier)
}

private def dispatch transferLayoutInt(ElkLabel label) {
private def dispatch transferLayoutInt1(ElkLabel label) {
val jsonObj = labelJsonMap.get(label)

// transfer positions and dimension
label.transferShapeLayout(jsonObj)
}

private def dispatch transferLayoutInt(Object obj) {
private def dispatch transferLayoutInt1(Object obj) {
// don't care about the rest
}

private def dispatch transferLayoutInt2(Object obj) {
// don't care about the rest
}

Expand Down Expand Up @@ -708,6 +768,7 @@ final class JsonImporter {

edgeIdMap.put(id, edge)
edgeJsonMap.put(edge, obj)
edgeOriginalParentMap.put(edge, edge.getContainingNode)

return edge
}
Expand All @@ -720,5 +781,17 @@ final class JsonImporter {

return edgeSection
}

private def ElkNode originalParent(ElkEdge edge) {
return edgeOriginalParentMap.get(edge)
}

private def Double globalX(ElkNode node) {
return nodeGlobalXMap.get(node)
}

private def Double globalY(ElkNode node) {
return nodeGlobalYMap.get(node)
}

}
Loading
Loading