X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.modeling%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2FSCLScenegraph.java;h=e0c198388e41f20a0f6848c22b2e70ae34b0ea2f;hb=694cdd2bbccb545e74d77befd83f1bdcb79bda5e;hp=bfab7fc6c0f7f8472a4c4158f547a0cf6acce68e;hpb=241a1dddfbaa9c46832f443884ca1bbfd1beb2c9;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLScenegraph.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLScenegraph.java index bfab7fc6c..e0c198388 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLScenegraph.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/SCLScenegraph.java @@ -18,6 +18,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.UUID; +import java.util.function.Function; import java.util.stream.Collectors; import javax.xml.transform.OutputKeys; @@ -30,11 +31,16 @@ import org.apache.batik.dom.GenericDOMImplementation; import org.apache.batik.svggen.SVGGeneratorContext; import org.apache.batik.svggen.SVGGraphics2D; import org.simantics.Simantics; +import org.simantics.datatypes.literal.GUID; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; +import org.simantics.db.common.request.IndexRoot; +import org.simantics.db.common.request.ResourceRead; import org.simantics.db.common.request.UnaryRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.RuntimeDatabaseException; +import org.simantics.db.layer0.variable.Variables; +import org.simantics.diagram.elements.DecorationSVGNode; import org.simantics.diagram.elements.DiagramNodeUtil; import org.simantics.diagram.elements.TextGridNode; import org.simantics.diagram.elements.TextNode; @@ -60,7 +66,6 @@ import org.simantics.scenegraph.g2d.nodes.BackgroundNode; import org.simantics.scenegraph.g2d.nodes.BoundsNode; import org.simantics.scenegraph.g2d.nodes.ConnectionNode; import org.simantics.scenegraph.g2d.nodes.DataNode; -import org.simantics.scenegraph.g2d.nodes.DecorationSVGNode; import org.simantics.scenegraph.g2d.nodes.NavigationNode; import org.simantics.scenegraph.g2d.nodes.SVGNode; import org.simantics.scenegraph.g2d.nodes.SelectionNode; @@ -69,6 +74,7 @@ import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode; import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode; import org.simantics.scenegraph.utils.NodeUtil; import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.tuple.Tuple2; import org.simantics.trend.impl.ItemNode; import org.simantics.utils.threads.ThreadUtils; import org.slf4j.Logger; @@ -81,16 +87,54 @@ import org.w3c.dom.NodeList; public class SCLScenegraph { private static final Logger LOGGER = LoggerFactory.getLogger(SCLScenegraph.class); + + private static final String MAIN_SECTION = "main"; + private static final String SELECTION_SECTION = "selection"; + private static final String SELECTION_MASK_SECTION = "selectionMask"; + + private static final String[] ALL_SECTIONS = { MAIN_SECTION, SELECTION_SECTION, SELECTION_MASK_SECTION }; + @Deprecated public static ICanvasSceneGraphProvider getICanvasSceneGraphProvider(Resource model, Resource diagram, String diagramRVI) throws DatabaseException, InterruptedException { ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(model, diagram, diagramRVI); return provider; } + @Deprecated public static void disposeSceneGraphProvider(ICanvasSceneGraphProvider provider) { provider.dispose(); } - + + public static T doWithICanvasSceneGraphProvider(Resource diagram, Function1 func) throws DatabaseException { + return doWithICanvasSceneGraphProvider(diagram, (Function) provider -> func.apply(provider)); + } + + public static T doWithICanvasSceneGraphProvider(Resource diagram, Function func) throws DatabaseException { + Tuple2 result = Simantics.getSession().syncRequest(new ResourceRead(diagram) { + + @Override + public Tuple2 perform(ReadGraph graph) throws DatabaseException { + Resource indexRoot = graph.syncRequest(new IndexRoot(resource)); + String diagramRVI = Variables.getRVI(graph, resource); + return new Tuple2(indexRoot, diagramRVI); + } + }); + ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider((Resource) result.c0, diagram, (String) result.c1); + try { + return func.apply(provider); + } finally { + provider.dispose(); + } + } + + public static T doWithCanvasContext(Resource diagram, Function1 func) throws DatabaseException { + return doWithCanvasContext(diagram, (Function) canvasContext -> func.apply(canvasContext)); + } + + public static T doWithCanvasContext(Resource diagram, Function func) throws DatabaseException { + return doWithICanvasSceneGraphProvider(diagram, (Function) provider -> func.apply(provider.getCanvasContext())); + } + public static String getNodeTransform(ICanvasContext ctx, String name) { Set texts = NodeUtil.collectNodes(ctx.getSceneGraph(), TextNode.class); @@ -498,29 +542,27 @@ public class SCLScenegraph { try { if (p instanceof Resource) { Resource element = (Resource) p; - if (graph.isInstanceOf(element, DIA.Connection) || graph.isInstanceOf(element, DIA.Terminal)) { - // Ok, lets create a hashcode for connections and terminals as they do not have identifiers - return graph.getURI(element).hashCode(); - } else if (graph.isInstanceOf(element, DIA.Element)) { + if (graph.isInstanceOf(element, DIA.Element)) { Resource component = graph.getPossibleObject(element, MOD.ElementToComponent); if (component != null) { - Object relatedValue = graph.getPossibleRelatedValue(component, L0.identifier); - if (relatedValue != null) { - if (relatedValue instanceof Object[]) { - // OK, found guid, lets generate new based on URI - return Arrays.toString(createURIBasedL0Identifier(graph, component)); - } else { - System.err.println("Component " + component + " identifeir is not normal: " + relatedValue); - } + GUID identifier = graph.getPossibleRelatedValue(component, L0.identifier, GUID.BINDING); + if (identifier != null) { + return Arrays.toString(createURIBasedL0Identifier(graph, component)); } else { - System.err.println("Compoennt " + component + " dooes not have identifier"); + LOGGER.error("Component {} does not have GUID identifier!", component); } + } else if (graph.isInstanceOf(element, DIA.Connection) || graph.isInstanceOf(element, DIA.Terminal)) { + // Ok, lets create a hashcode for connections and terminals as they do not have identifiers + return graph.getURI(element).hashCode(); } else { - System.err.println("Element " + element + " does not have component"); + // Ok, lets create a hashcode or either return empty string in cases where no ID is required + if (graph.hasStatement(element, L0.HasName)) + return graph.getURI(element).hashCode(); + return ""; } } } else { - System.err.println("p is not resource but is " + p); + LOGGER.error("Parameter p {} is not resource but it is {}", p, p.getClass()); } return p; } catch (DatabaseException e) { @@ -537,6 +579,37 @@ public class SCLScenegraph { }); } + static class RenderSVGContext { + + Map documents = new HashMap<>(); + + public void append(String[] keys, String svgText) { + for(String key : keys) append(key, svgText); + } + + public void append(String key, String svgText) { + StringBuilder builder = documents.get(key); + if(builder == null) { + builder = new StringBuilder(); + documents.put(key, builder); + } + builder.append(svgText); + } + + public void append(RenderSVGContext other) { + for(String key : other.documents.keySet()) { + append(key, other.get(key)); + } + } + + public String get(String key) { + StringBuilder builder = documents.get(key); + if(builder == null) return ""; + else return builder.toString(); + } + + } + private static String renderSVG0(ICanvasContext ctx, Function1, Map> mappingFunction) { // Get a DOMImplementation. @@ -549,7 +622,7 @@ public class SCLScenegraph { // Create an instance of the SVG Generator. SVGGraphics2D svgGenerator = new Generator(document); - StringBuilder result = new StringBuilder(); + RenderSVGContext result = new RenderSVGContext(); try { @@ -562,6 +635,7 @@ public class SCLScenegraph { } G2DSceneGraph sg = ctx.getSceneGraph(); + sg.performCleanup(); G2DParentNode root = (G2DParentNode) sg.getRootNode(); // rtree is the actual content of the diagram @@ -594,9 +668,22 @@ public class SCLScenegraph { double trX = -1 * content.getX(); double trY = -1 * content.getY(); + + // NaNs + if(!Double.isFinite(trX)) trX = 0; + if(!Double.isFinite(trY)) trY = 0; + + result.append(MAIN_SECTION, ""); + result.append(SELECTION_SECTION, ""); + result.append(SELECTION_MASK_SECTION, ""); - result.append(""); + result.append(ALL_SECTIONS, ""); + KeyVisitor keyVisitor = new KeyVisitor(); sg.accept(keyVisitor); @@ -605,16 +692,28 @@ public class SCLScenegraph { Map mappings = mappingFunction.apply(keys); IG2DNodeVisitor visitor = new PrintingVisitor(result, mappings); + sg.accept(visitor); } catch (Throwable t) { LOGGER.error("Problems rendering canvas context to SVG", t); } - result.append(""); - //System.err.println(" == FINAL RESULT == "); - //System.err.println(b); - return result.toString(); + + result.append(ALL_SECTIONS, ""); + + StringBuilder res = new StringBuilder(); + res.append(""); + res.append(result.get(MAIN_SECTION)); + res.append(result.get(SELECTION_SECTION)); + res.append(result.get(SELECTION_MASK_SECTION)); + res.append(""); + +// System.err.println(" == FINAL RESULT == "); +// System.err.println(res.toString()); + + return res.toString(); + } @@ -647,30 +746,34 @@ public class SCLScenegraph { int indent = 0; - HashMap senBuilders = new HashMap<>(); + HashMap senBuilders = new HashMap<>(); - private StringBuilder result; + private RenderSVGContext result; private Map mappings; - public PrintingVisitor(StringBuilder result, Map mappings) { + public PrintingVisitor(RenderSVGContext result, Map mappings) { this.result = result; this.mappings = mappings; } private String getKey(SingleElementNode node) { String key; - if (mappings.containsKey(node.getKey())) - key = mappings.get(node.getKey()).toString(); - else - key = node.getKey().toString(); + if(node.getKey() != null) { + if (mappings.containsKey(node.getKey())) + key = mappings.get(node.getKey()).toString(); + else + key = node.getKey().toString(); + } else { + key = Long.toString(node.getId()); + } return key; } @Override public void enter(IG2DNode node) { - StringBuilder parentBuilder = getParentBuilder(node); + RenderSVGContext parentBuilder = getParentBuilder(node); indent++; if(node instanceof ConnectionNode) { @@ -680,79 +783,89 @@ public class SCLScenegraph { } String key = getKey((ConnectionNode) node); - parentBuilder.append("\n"); + parentBuilder.append(MAIN_SECTION, "\n"); + parentBuilder.append(SELECTION_SECTION, "\n"); + parentBuilder.append(SELECTION_MASK_SECTION, "\n"); + Element doc = renderSVGNode((IG2DNode)node); String svg = printSVGDocument(doc); - parentBuilder.append(svg); + parentBuilder.append(MAIN_SECTION, svg); for(RouteGraphNode n : NodeUtil.collectNodes(node, RouteGraphNode.class)) { n.setIgnoreSelection(false); } - parentBuilder.append("\n"); doc = renderSVGNode((IG2DNode)node); svg = printSVGDocument(doc); - parentBuilder.append(svg); - parentBuilder.append("\n"); + parentBuilder.append(SELECTION_SECTION, svg); - BasicStroke bs = new BasicStroke(5f); + BasicStroke bs = new BasicStroke(10f); for(RouteGraphNode n : NodeUtil.collectNodes(node, RouteGraphNode.class)) { n.setDynamicStroke(bs); } - parentBuilder.append("\n"); doc = renderSVGNode((IG2DNode)node); svg = printSVGDocument(doc); - parentBuilder.append(svg); - parentBuilder.append("\n"); + parentBuilder.append(SELECTION_MASK_SECTION, svg); - parentBuilder.append("\n"); + parentBuilder.append(SELECTION_MASK_SECTION, "\n"); + parentBuilder.append(SELECTION_SECTION, "\n"); + parentBuilder.append(MAIN_SECTION, "\n"); } else if (node instanceof SelectionNode) { SelectionNode n = (SelectionNode)node; SingleElementNode parentSEN = (SingleElementNode)NodeUtil.getNearestParentOfType(node, SingleElementNode.class); - if(parentSEN != null && parentSEN.getKey() != null) { + if(parentSEN != null) { - StringBuilder parentBuilder2 = getParentBuilder(parentSEN); + RenderSVGContext parentBuilder2 = getParentBuilder(parentSEN); String key = getKey(parentSEN); + n.setIgnore(false); Element doc = renderSVGNode((IG2DNode)node); + n.setIgnore(true); String svg = printSVGDocument(doc); - parentBuilder2.append("\n"); - parentBuilder2.append(svg); - parentBuilder2.append("\n"); - parentBuilder2.append("\n"); + parentBuilder2.append(SELECTION_SECTION, "\n"); + parentBuilder2.append(SELECTION_SECTION, svg); + parentBuilder2.append(SELECTION_SECTION, "\n"); + parentBuilder2.append(SELECTION_MASK_SECTION, "\n"); Rectangle2D rect = n.getRect(); - parentBuilder2.append(""); - parentBuilder2.append("\n"); + // NaN + if(rect.getHeight() == rect.getHeight() && rect.getWidth() == rect.getWidth()) { + parentBuilder2.append(SELECTION_MASK_SECTION,""); + } + parentBuilder2.append(SELECTION_MASK_SECTION,"\n"); + } } else if (node instanceof SVGNode) { SVGNode svg = (SVGNode)node; - parentBuilder.append(svg.getSVGText()); + parentBuilder.append(MAIN_SECTION, svg.getSVGText()); } else if (node instanceof G2DParentNode) { AffineTransform at = node.getTransform(); if(node instanceof SingleElementNode) { SingleElementNode sen = (SingleElementNode)node; - if(sen.getKey() != null) { - String key = getKey(sen); - parentBuilder.append("\n"); - } - senBuilders.put(sen, new StringBuilder()); + String key = getKey(sen); + String typeClass = sen.getTypeClass(); + String clazz = "definedElement"; + if(typeClass != null && !typeClass.isEmpty()) + clazz = clazz + " " + typeClass; + + parentBuilder.append(MAIN_SECTION, "\n"); + senBuilders.put(sen, new RenderSVGContext()); } if(!at.isIdentity()) { if(at.getScaleX() == 1.0 && at.getScaleY() == 1.0 && at.getShearX() == 0.0 && at.getShearY() == 0.0) { String m = "translate(" + at.getTranslateX() + " " + at.getTranslateY() + ")"; - parentBuilder.append("\n"); + parentBuilder.append(ALL_SECTIONS, "\n"); } else { double[] ds = new double[6]; at.getMatrix(ds); String m = "matrix(" + ds[0] + " " + ds[1] + " " + ds[2] + " " + ds[3] + " " + ds[4] + " " + ds[5] + ")"; - parentBuilder.append("\n"); + parentBuilder.append(ALL_SECTIONS, "\n"); } } } @@ -761,12 +874,12 @@ public class SCLScenegraph { } - private StringBuilder getParentBuilder(IG2DNode node) { + private RenderSVGContext getParentBuilder(IG2DNode node) { INode parentSEN = NodeUtil.getNearestParentOfType(node, SingleElementNode.class); if(parentSEN instanceof G2DSceneGraph) return result; - StringBuilder parentBuilder = senBuilders.get(parentSEN); + RenderSVGContext parentBuilder = senBuilders.get(parentSEN); if(parentBuilder == null) return result; return parentBuilder; @@ -780,40 +893,33 @@ public class SCLScenegraph { // We are done } else if (node instanceof G2DParentNode) { - StringBuilder parentBuilder = getParentBuilder(node); + RenderSVGContext parentBuilder = getParentBuilder(node); if(node instanceof SingleElementNode) { - SingleElementNode sen = (SingleElementNode)node; -// if(sen.getKey() != null) { - StringBuilder b = senBuilders.get(sen); - String content = b.toString(); - if(content.isEmpty()) { - if(sen.getKey() != null) { - - for(SelectionNode n : NodeUtil.collectNodes(node, SelectionNode.class)) { - n.setIgnore(true); - } - - Element doc = renderSVGNode((IG2DNode)node); - String svg = printSVGDocument(doc); - parentBuilder.append(svg); - } - } else { - parentBuilder.append(content); - } -// } + SingleElementNode sen = (SingleElementNode)node; + RenderSVGContext b = senBuilders.get(sen); + String content = b.get(MAIN_SECTION); + if(content.isEmpty()) { + for(SelectionNode n : NodeUtil.collectNodes(node, SelectionNode.class)) { + n.setIgnore(true); + } + Element doc = renderSVGNode((IG2DNode)node); + String svg = printSVGDocument(doc); + parentBuilder.append(MAIN_SECTION, svg); + } else { + parentBuilder.append(b); + } } - AffineTransform at = node.getTransform(); if(!at.isIdentity()) { - parentBuilder.append(""); + parentBuilder.append(ALL_SECTIONS, ""); } if(node instanceof SingleElementNode) { SingleElementNode sen = (SingleElementNode)node; - if(sen.getKey() != null) { - parentBuilder.append(""); - } + //if(sen.getKey() != null) { + parentBuilder.append(MAIN_SECTION, ""); + //} } } indent --;