]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/DiagramGraphUtil.java
IConnectionPoint and canBeConnected-checking util to SCL
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / synchronization / graph / DiagramGraphUtil.java
index 61660d5de32645536f4ca994080a014ba829377f..3a38654e396db46a900b6eb6d1271fba122ec2b8 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.diagram.synchronization.graph;\r
-\r
-import gnu.trove.set.hash.THashSet;\r
-\r
-import java.awt.geom.AffineTransform;\r
-import java.lang.reflect.Array;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.List;\r
-import java.util.Set;\r
-\r
-import org.simantics.Simantics;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.datatypes.literal.Vec2d;\r
-import org.simantics.db.AsyncReadGraph;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Statement;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.CommentMetadata;\r
-import org.simantics.db.common.primitiverequest.OrderedSet;\r
-import org.simantics.db.common.request.IndexRoot;\r
-import org.simantics.db.common.request.Queries;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.common.utils.OrderedSetUtils;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.DoesNotContainValueException;\r
-import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
-import org.simantics.db.exception.NoSingleResultException;\r
-import org.simantics.db.exception.ServiceException;\r
-import org.simantics.db.exception.ValidationException;\r
-import org.simantics.db.layer0.request.PossibleModel;\r
-import org.simantics.db.procedure.AsyncProcedure;\r
-import org.simantics.diagram.connection.ConnectionSegmentEnd;\r
-import org.simantics.diagram.connection.ConnectionVisuals;\r
-import org.simantics.diagram.content.ConnectionUtil;\r
-import org.simantics.diagram.content.DesignatedTerminal;\r
-import org.simantics.diagram.content.ElementContext;\r
-import org.simantics.diagram.content.ResourceTerminal;\r
-import org.simantics.diagram.content.TerminalMap;\r
-import org.simantics.diagram.internal.DebugPolicy;\r
-import org.simantics.diagram.query.DiagramRequests;\r
-import org.simantics.diagram.stubs.DiagramResource;\r
-import org.simantics.diagram.stubs.G2DResource;\r
-import org.simantics.g2d.connection.EdgeVisualsConfigurer;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.diagram.handler.DataElementMap;\r
-import org.simantics.g2d.diagram.handler.Topology.Terminal;\r
-import org.simantics.g2d.element.ElementHints;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.g2d.element.handler.EdgeVisuals;\r
-import org.simantics.g2d.element.handler.EdgeVisuals.ArrowType;\r
-import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;\r
-import org.simantics.g2d.element.handler.FillColor;\r
-import org.simantics.g2d.element.handler.TerminalTopology;\r
-import org.simantics.g2d.elementclass.FlagClass;\r
-import org.simantics.g2d.elementclass.FlagClass.Type;\r
-import org.simantics.g2d.page.DiagramDesc;\r
-import org.simantics.g2d.routing.IRouter2;\r
-import org.simantics.g2d.svg.LineCap;\r
-import org.simantics.g2d.svg.LineJoin;\r
-import org.simantics.g2d.utils.Alignment;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.layer0.utils.binaryPredicates.OrderedSetElementsPredicate;\r
-import org.simantics.modeling.ModelingResources;\r
-import org.simantics.scl.commands.Commands;\r
-import org.simantics.structural.stubs.StructuralResource2;\r
-import org.simantics.structural2.modelingRules.CPTerminal;\r
-import org.simantics.structural2.modelingRules.IAttachmentRelationMap;\r
-import org.simantics.structural2.modelingRules.IConnectionPoint;\r
-import org.simantics.structural2.modelingRules.IModelingRules;\r
-import org.simantics.ui.selection.WorkbenchSelectionElement;\r
-import org.simantics.utils.page.MarginUtils.Margin;\r
-import org.simantics.utils.page.MarginUtils.Margins;\r
-import org.simantics.utils.page.PageCentering;\r
-import org.simantics.utils.page.PageDesc;\r
-import org.simantics.utils.page.PageOrientation;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-\r
-/**\r
- * @author Tuukka Lehtonen\r
- */\r
-public final class DiagramGraphUtil {\r
-\r
-    public static double[] validateAffineTransform(Resource resource, double[] matrix) {\r
-        if (matrix != null) {\r
-            if (matrix.length < 4) {\r
-                ErrorLogger.defaultLogError("resource " + resource + " matrix too small for AffineTransform: " + Arrays.toString(matrix), new Exception("trace"));\r
-                return null;\r
-            }\r
-\r
-            // Validate scale/rotation part\r
-            if (DebugPolicy.DEBUG_TRANSFORM_LOAD) {\r
-                double det = new AffineTransform(matrix).getDeterminant();\r
-                double detabs = Math.abs(det);\r
-                if (detabs < DebugPolicy.DETERMINANT_LIMIT_LOW)\r
-                    ErrorLogger.defaultLogWarning("resource " + resource + " transform determinant absolute value is close to zero: " + detabs + "(transform=" + Arrays.toString(matrix) + ")", new Exception("trace"));\r
-                if (detabs > DebugPolicy.DETERMINANT_LIMIT_HIGH)\r
-                    ErrorLogger.defaultLogWarning("resource " + resource + " transform determinant absolute value is suspiciously large: " + detabs + "(transform=" + Arrays.toString(matrix) + ")", new Exception("trace"));\r
-            }\r
-\r
-            if (matrix.length > 5) {\r
-                // Validate translation\r
-                double xabs = Math.abs(matrix[4]);\r
-                double yabs = Math.abs(matrix[5]);\r
-                double limit = DebugPolicy.TRANSLATION_LIMIT_HIGH;\r
-                boolean largeX = xabs > limit;\r
-                boolean largeY = yabs > limit;\r
-                if (largeX || largeY)\r
-                    ErrorLogger.defaultLogWarning("resource " + resource + " transform translation is suspiciously large: " + Arrays.toString(matrix), new Exception("trace"));\r
-                return matrix;\r
-            }\r
-        }\r
-        return matrix;\r
-    }\r
-\r
-    public static AffineTransform getAffineTransform(ReadGraph graph, Resource resource) throws DatabaseException {\r
-        G2DResource g2d = G2DResource.getInstance(graph);\r
-        return getAffineTransform(graph, resource, g2d.HasTransform, true);\r
-    }\r
-\r
-    public static Vec2d getOffset(ReadGraph graph, Resource resource) throws DatabaseException {\r
-       DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        Vec2d offset = graph.getPossibleRelatedValue(resource, DIA.Element_profileMonitorOffset, Vec2d.BINDING);\r
-        if(offset != null) return offset;\r
-        else return new Vec2d(0, 0);\r
-    }\r
-    \r
-    public static boolean getProfileMonitorsHidden(ReadGraph graph, Resource resource) throws DatabaseException {\r
-       DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        Boolean value = graph.getPossibleRelatedValue(resource, DIA.Element_hideProfileMonitors, Bindings.BOOLEAN);\r
-        if(value == null) value = false;\r
-        return value;\r
-    }\r
-\r
-    public static boolean getProfileMonitorsUp(ReadGraph graph, Resource resource) throws DatabaseException {\r
-       DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        Boolean value = graph.getPossibleRelatedValue(resource, DIA.Element_upProfileMonitors, Bindings.BOOLEAN);\r
-        if(value == null) value = true;\r
-        return value;\r
-    }\r
-\r
-    public static double getProfileMonitorSpacing(ReadGraph graph, Resource resource) throws DatabaseException {\r
-       DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        Double value = graph.getPossibleRelatedValue(resource, DIA.Element_profileMonitorSpacing, Bindings.DOUBLE);\r
-        if(value == null) value = 0.0;\r
-        return value;\r
-    }\r
-\r
-    public static AffineTransform getDynamicAffineTransform(ReadGraph graph, Resource runtime, Resource element) throws DatabaseException {\r
-        DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        return getDynamicAffineTransform(graph, runtime, element, DIA.HasDynamicTransform, true);\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param element\r
-     * @return\r
-     * @throws DatabaseException\r
-     */\r
-    public static AffineTransform getWorldTransform(ReadGraph graph, Resource element) throws DatabaseException {\r
-        ModelingResources MOD = ModelingResources.getInstance(graph);\r
-        AffineTransform result = DiagramGraphUtil.getAffineTransform(graph, element);\r
-        while (true) {\r
-            Resource parentComponent = graph.getPossibleObject(element, MOD.HasParentComponent);\r
-            if (parentComponent == null)\r
-                return result;\r
-            element = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);\r
-            if (element == null)\r
-                return result;\r
-            AffineTransform tr = DiagramGraphUtil.getAffineTransform(graph, element);\r
-            tr.setToTranslation(tr.getTranslateX(), tr.getTranslateY());\r
-            result.preConcatenate(tr);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param runtime\r
-     * @param element\r
-     * @return\r
-     * @throws DatabaseException\r
-     */\r
-    public static AffineTransform getDynamicWorldTransform(ReadGraph graph, Resource runtime, Resource element) throws DatabaseException {\r
-        ModelingResources MOD = ModelingResources.getInstance(graph);\r
-        AffineTransform result = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, element);\r
-        while (true) {\r
-            Resource parentComponent = graph.getPossibleObject(element, MOD.HasParentComponent);\r
-            if (parentComponent == null)\r
-                return result;\r
-            element = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);\r
-            if (element == null)\r
-                return result;\r
-            AffineTransform tr = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, element);\r
-            tr.setToTranslation(tr.getTranslateX(), tr.getTranslateY());\r
-            result.preConcatenate(tr);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param resource\r
-     * @param relation\r
-     * @param invalidAsIdentity true to return invalid transforms as identity\r
-     *        transforms, <code>false</code> to return <code>null</code>\r
-     * @return\r
-     * @throws DatabaseException\r
-     */\r
-    public static AffineTransform getAffineTransform(ReadGraph graph, Resource resource, Resource relation, boolean invalidAsIdentity) throws DatabaseException {\r
-        double mat[] = getPossibleRelatedDoubleArray(graph, resource, relation);\r
-        mat = validateAffineTransform(resource, mat);\r
-        return mat != null ? new AffineTransform(mat) :\r
-            invalidAsIdentity ? new AffineTransform() : null;\r
-    }\r
-\r
-    public static AffineTransform getDynamicAffineTransform(ReadGraph graph, Resource runtime, Resource element, Resource relation, boolean invalidAsIdentity) throws DatabaseException {\r
-        double mat[] = graph.getPossibleRelatedValue2(element, relation, new ElementContext(runtime, element), Bindings.DOUBLE_ARRAY);\r
-        mat = validateAffineTransform(element, mat);\r
-        return mat != null ? new AffineTransform(mat) :\r
-            invalidAsIdentity ? new AffineTransform() : null;\r
-    }\r
-    \r
-    public static double[] getPossibleRelatedDoubleArray(ReadGraph graph, Resource resource, Resource relation) throws DatabaseException {\r
-        Resource res = graph.getPossibleObject(resource, relation);\r
-        if (res == null)\r
-            return null;\r
-        return graph.getValue(res, Bindings.getBindingUnchecked(double[].class));\r
-    }\r
-    \r
-    public static AffineTransform getTransform(ReadGraph graph, Resource resource) throws DatabaseException {\r
-        DiagramResource DIA = DiagramResource.getInstance(graph);\r
-\r
-        double[] matrix = graph.getPossibleRelatedValue(resource, DIA.HasTransform, Bindings.DOUBLE_ARRAY);\r
-        if (matrix == null)\r
-            return new AffineTransform();\r
-        if (matrix.length < 4)\r
-            return new AffineTransform();\r
-        return new AffineTransform(matrix);\r
-    }\r
-\r
-    public static void setTransform(WriteGraph graph, Resource resource, AffineTransform at) throws DatabaseException {\r
-        double[] matrix = new double[6];\r
-        at.getMatrix(matrix);\r
-        changeTransform(graph, resource, matrix);\r
-    }\r
-    \r
-    public static void setTransform(WriteGraph graph, Resource resource, double[] matrix) throws DatabaseException {\r
-        DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        G2DResource G2D = G2DResource.getInstance(graph);\r
-\r
-        setRelatedValue(graph, resource, DIA.HasTransform, G2D.Transform, matrix, Bindings.DOUBLE_ARRAY);\r
-    }\r
-    \r
-    public static void changeTransform(WriteGraph graph, Resource resource, AffineTransform at) throws DatabaseException {\r
-        double[] matrix = new double[6];\r
-        at.getMatrix(matrix);\r
-        changeTransform(graph, resource, matrix);\r
-    }\r
-    \r
-    public static void changeTransform(WriteGraph graph, Resource resource, double[] matrix) throws DatabaseException {\r
-        Commands.get(graph, "Simantics/Diagram/setTransform")\r
-                .execute(graph, graph.syncRequest(new IndexRoot(resource)), resource, matrix);\r
-    }\r
-\r
-    public static void setRelatedValue(WriteGraph graph, Resource resource, Resource relation, Resource valueType, Object arrayValue, Binding binding) throws DatabaseException {\r
-        Statement stm = graph.getPossibleStatement(resource, relation);\r
-        if (stm == null) {\r
-            addRelatedValue(graph, resource, relation, valueType, arrayValue, binding);\r
-        } else {\r
-            // statement might be asserted, check this before overwriting\r
-            if (!stm.getSubject().equals(resource)) {\r
-                // Asserted, just add a new related value\r
-                addRelatedValue(graph, resource, relation, valueType, arrayValue, binding);\r
-            } else {\r
-                //Object old = graph.getValue2(p);\r
-                //if (!Arrays.equals(old, arrayValue))\r
-                graph.claimValue(stm.getObject(), arrayValue, binding);\r
-            }\r
-        }\r
-    }\r
-\r
-    public static Resource addRelatedValue(WriteGraph graph, Resource resource, Resource relation, Resource valueType, Object arrayValue, Binding binding) throws DatabaseException {\r
-        Resource d = graph.newResource();\r
-       Layer0 b = Layer0.getInstance(graph);\r
-        graph.claim(d, b.InstanceOf, null, valueType);\r
-        graph.claimValue(d, arrayValue);\r
-        graph.claim(resource, relation, d);\r
-        return d;\r
-    }\r
-\r
-    public static <T> T getPossibleRelatedValue(ReadGraph graph, Resource r, Resource relation, Class<T> valueClass, T defaultValue) throws DatabaseException {\r
-        Resource object = graph.getPossibleObject(r, relation);\r
-        if (object == null)\r
-            return defaultValue;\r
-        T t = graph.getPossibleValue(object, Bindings.getBindingUnchecked(valueClass));\r
-        if (t != null && valueClass.isArray()) {\r
-            if (defaultValue != null) {\r
-                int defaultValueLength = Array.getLength(defaultValue);\r
-                int valueLength = Array.getLength(t);\r
-                if (valueLength < defaultValueLength)\r
-                    return defaultValue;\r
-            }\r
-        }\r
-        return t == null ? defaultValue : t;\r
-    }\r
-\r
-    public static Resource getConnectionPointOfTerminal(ReadGraph g, Terminal forTerminal) throws DatabaseException {\r
-        if (forTerminal instanceof ResourceTerminal)\r
-            return getConnectionPointOfTerminal(g, ((ResourceTerminal) forTerminal).getResource());\r
-        return null;\r
-    }\r
-\r
-    public static Resource tryGetBindingRelation(ReadGraph g, Terminal forTerminal) throws DatabaseException {\r
-        if (forTerminal instanceof ResourceTerminal)\r
-            return getPossibleConnectionPointOfTerminal(g, ((ResourceTerminal) forTerminal).getResource());\r
-        return null;\r
-    }\r
-\r
-    public static LineJoin toLineJoin(G2DResource g2d, Resource lineJoin) {\r
-        if (lineJoin != null) {\r
-            if (lineJoin.equals(g2d.LineJoin_BevelJoin))\r
-                return LineJoin.bevel;\r
-            if (lineJoin.equals(g2d.LineJoin_RoundJoin))\r
-                return LineJoin.round;\r
-        }\r
-        return LineJoin.miter;\r
-    }\r
-\r
-    public static LineCap toLineCap(G2DResource g2d, Resource lineCap) {\r
-        if (lineCap != null) {\r
-            if (lineCap.equals(g2d.LineCap_ButtCap))\r
-                return LineCap.butt;\r
-            if (lineCap.equals(g2d.LineCap_RoundCap))\r
-                return LineCap.round;\r
-        }\r
-        return LineCap.square;\r
-    }\r
-\r
-    public static Resource toLineJoin(G2DResource g2d, LineJoin lineJoin) {\r
-        if (lineJoin != null) {\r
-            if (lineJoin.equals(LineJoin.bevel))\r
-                return g2d.LineJoin_BevelJoin;\r
-            if (lineJoin.equals(LineJoin.round))\r
-                return g2d.LineJoin_RoundJoin;\r
-        }\r
-        return g2d.LineJoin_MiterJoin;\r
-    }\r
-\r
-    public static Resource toLineCap(G2DResource g2d, LineCap lineCap) {\r
-        if (lineCap != null) {\r
-            if (lineCap.equals(LineCap.butt))\r
-                return g2d.LineCap_ButtCap;\r
-            if (lineCap.equals(LineCap.round))\r
-                return g2d.LineCap_RoundCap;\r
-        }\r
-        return g2d.LineCap_SquareCap;\r
-    }\r
-\r
-    public static Alignment toAlignment(Resource align, G2DResource g2d, Alignment defaultValue) {\r
-        if (align == null)\r
-            return defaultValue;\r
-        if (align.equals(g2d.Alignment_Leading))\r
-            return Alignment.LEADING;\r
-        if (align.equals(g2d.Alignment_Trailing))\r
-            return Alignment.TRAILING;\r
-        if (align.equals(g2d.Alignment_Center))\r
-            return Alignment.CENTER;\r
-        return defaultValue;\r
-    }\r
-\r
-    public static Alignment toVerticalAlignment(Resource align, G2DResource g2d, Alignment defaultValue) {\r
-        if (align == null)\r
-            return defaultValue;\r
-        if (align.equals(g2d.Alignment_Leading))\r
-            return Alignment.LEADING;\r
-        if (align.equals(g2d.Alignment_Trailing))\r
-            return Alignment.TRAILING;\r
-        if (align.equals(g2d.Alignment_Center))\r
-            return Alignment.CENTER;\r
-        if (align.equals(g2d.Alignment_Baseline))\r
-            return Alignment.BASELINE;\r
-        return defaultValue;\r
-    }\r
-\r
-\r
-    public static Resource toFlagTypeResource(DiagramResource dr, FlagClass.Type type) {\r
-        switch (type) {\r
-            case In: return dr.FlagType_InputFlag;\r
-            case Out: return dr.FlagType_OutputFlag;\r
-            default: throw new IllegalArgumentException("unsupported flag type: " + type);\r
-        }\r
-    }\r
-\r
-    public static FlagClass.Type toFlagType(DiagramResource dr, Resource type) {\r
-        return toFlagType(dr, type, Type.In);\r
-    }\r
-\r
-    public static FlagClass.Type toFlagType(DiagramResource dr, Resource type, FlagClass.Type defaultValue) {\r
-        if (type != null) {\r
-            if (dr.FlagType_InputFlag.equals(type))\r
-                return Type.In;\r
-            if (dr.FlagType_OutputFlag.equals(type))\r
-                return Type.Out;\r
-        }\r
-        return defaultValue;\r
-    }\r
-\r
-    public static void tag(WriteGraph g, Resource object, Resource tag, boolean set) throws DatabaseException {\r
-        if (set)\r
-            g.claim(object, tag, tag, object);\r
-        else\r
-            g.deny(object, tag, tag, object);\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param diagram the diagram from which to look for a page description\r
-     *        property\r
-     * @return if the diagram does not have a page desc definition,\r
-     *         <code>defaultValue</code> is returned\r
-     * @throws DatabaseException\r
-     */\r
-    public static PageDesc getPageDesc(ReadGraph graph, Resource diagram, PageDesc defaultValue) throws DatabaseException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        Resource pd = graph.getPossibleObject(diagram, dr.HasPageDescription);\r
-        if (pd == null)\r
-            return defaultValue;\r
-        return readPageDesc(graph, pd);\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param diagram\r
-     *            the diagram from which to look for a page description property\r
-     * @return PageDesc for the specified diagram\r
-     * @throws DatabaseException\r
-     *             if DIA.HasPageDescription can't be read\r
-     */\r
-    public static PageDesc getPageDesc(ReadGraph graph, Resource diagram) throws DatabaseException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        Resource pd = graph.getSingleObject(diagram, dr.HasPageDescription);\r
-        return readPageDesc(graph, pd);\r
-    }\r
-\r
-    public static PageDesc readPageDesc(ReadGraph graph, Resource pageDesc) throws DatabaseException {\r
-        Layer0 l0 = Layer0.getInstance(graph);\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        Resource orientation = graph.getSingleObject(pageDesc, dr.PageDescription_Orientation);\r
-        double[] size = graph.getRelatedValue(pageDesc, dr.PageDescription_Size, Bindings.getBindingUnchecked(double[].class));\r
-        Resource margins = graph.getSingleObject(pageDesc, dr.PageDescription_Margins);\r
-        Margins m = readMargins(graph, margins);\r
-        //PageDesc pd = PageDesc.getDescription(toOrientation(orientation, dr), size[0], size[1]);\r
-        String name = graph.getPossibleRelatedValue(pageDesc, l0.HasName);\r
-        if (name == null)\r
-            name = "";\r
-        PageDesc pd = new PageDesc(name, toOrientation(orientation, dr), PageCentering.TopLeftAtOrigin, size[0], size[1], m);\r
-        return pd;\r
-    }\r
-\r
-    public static Margins readMargins(ReadGraph graph, Resource margins) throws NoSingleResultException, DoesNotContainValueException, ServiceException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        double t = graph.getRelatedValue(margins, dr.PageDescription_Margins_Top);\r
-        double b = graph.getRelatedValue(margins, dr.PageDescription_Margins_Bottom);\r
-        double l = graph.getRelatedValue(margins, dr.PageDescription_Margins_Left);\r
-        double r = graph.getRelatedValue(margins, dr.PageDescription_Margins_Right);\r
-        Margin mt = new Margin(0, 0, t);\r
-        Margin mb = new Margin(0, 0, b);\r
-        Margin ml = new Margin(0, 0, l);\r
-        Margin mr = new Margin(0, 0, r);\r
-        return new Margins(mt, mb, ml, mr);\r
-    }\r
-\r
-    public static void setPageDesc(WriteGraph graph, Resource diagram, String pageDescRepr) throws DatabaseException {\r
-        setPageDesc(graph, diagram, PageDesc.fromRepr(pageDescRepr));\r
-    }\r
-    \r
-    public static void setPageDesc(WriteGraph graph, Resource diagram, PageDesc pageDesc) throws DatabaseException {\r
-       Layer0 b = Layer0.getInstance(graph);\r
-        G2DResource g2d = G2DResource.getInstance(graph);\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        Resource pd = graph.getPossibleObject(diagram, dr.HasPageDescription);\r
-        if(pd != null && graph.isImmutable(pd)) {\r
-               graph.deny(diagram, dr.HasPageDescription);\r
-               pd = null;\r
-        }\r
-        if (pd == null) {\r
-            pd = graph.newResource();\r
-            graph.claim(pd, b.InstanceOf, null, dr.PageDescription);\r
-            graph.claim(diagram, dr.HasPageDescription, pd);\r
-        }\r
-        graph.deny(pd, dr.PageDescription_Size);\r
-        Resource pageSize = graph.newResource();\r
-        graph.claim(pageSize, b.InstanceOf, null, g2d.Point2D);\r
-        graph.claimValue(pageSize, new double[] { pageDesc.getWidth(), pageDesc.getHeight() });\r
-        graph.claim(pd, dr.PageDescription_Size, pageSize);\r
-        graph.deny(pd, dr.PageDescription_Orientation);\r
-        graph.claim(pd, dr.PageDescription_Orientation, toOrientationResource(pageDesc.getOrientation(), dr));\r
-        Resource margins = graph.getPossibleObject(pd, dr.PageDescription_Margins);\r
-        if (margins == null) {\r
-            margins = graph.newResource();\r
-            graph.claim(margins, b.InstanceOf, null, dr.Margins);\r
-            graph.claim(pd, dr.PageDescription_Margins, margins);\r
-        }\r
-        setMargins(graph,pageDesc.getMargins(),margins, dr);\r
-        graph.claimLiteral(pd, b.HasName,pageDesc.getText());\r
-    }\r
-\r
-    private static PageOrientation toOrientation(Resource orientation, DiagramResource dr) {\r
-        if (orientation != null) {\r
-            if (orientation.equals(dr.Orientation_Portrait))\r
-                return PageOrientation.Portrait;\r
-            if (orientation.equals(dr.Orientation_Landscape))\r
-                return PageOrientation.Landscape;\r
-        }\r
-        return PageOrientation.Portrait;\r
-    }\r
-\r
-    public static Resource toOrientationResource(PageOrientation orientation, DiagramResource dr) {\r
-        if (PageOrientation.Portrait.equals(orientation))\r
-            return dr.Orientation_Portrait;\r
-        if (PageOrientation.Landscape.equals(orientation))\r
-            return dr.Orientation_Landscape;\r
-        return dr.Orientation_Portrait;\r
-    }\r
-\r
-    private static void setMargins(WriteGraph g, Margins margins, Resource marginsR,DiagramResource dr) throws ServiceException, ManyObjectsForFunctionalRelationException {\r
-\r
-        g.claimLiteral(marginsR, dr.PageDescription_Margins_Top,margins.top.diagramAbsolute);\r
-        g.claimLiteral(marginsR, dr.PageDescription_Margins_Bottom,margins.bottom.diagramAbsolute);\r
-        g.claimLiteral(marginsR, dr.PageDescription_Margins_Left,margins.left.diagramAbsolute);\r
-        g.claimLiteral(marginsR, dr.PageDescription_Margins_Right,margins.right.diagramAbsolute);\r
-\r
-    }\r
-\r
-    public static Double getGridSize(ReadGraph graph, Resource diagram, Double defaultValue) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        Double gridSize = graph.getPossibleRelatedValue(diagram, dr.HasGridSize);\r
-        return gridSize == null ? defaultValue : gridSize;\r
-    }\r
-\r
-    public static void setGridSize(WriteGraph graph, Resource diagram, double gridSize) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        graph.claimLiteral(diagram, dr.HasGridSize, gridSize);\r
-    }\r
-\r
-    public static boolean isPageBordersVisible(ReadGraph graph, Resource diagram) throws DatabaseException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        return graph.hasStatement(diagram, dr.DisplayPageSize);\r
-    }\r
-\r
-    public static boolean isMarginsVisible(ReadGraph graph, Resource diagram) throws DatabaseException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        return graph.hasStatement(diagram, dr.DisplayMargins);\r
-    }\r
-\r
-    public static void setPageBordersVisible(WriteGraph graph, Resource diagram, boolean visible) throws DatabaseException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        tag(graph, diagram, dr.DisplayPageSize, visible);\r
-    }\r
-\r
-    public static void setMarginsVisible(WriteGraph graph, Resource diagram, boolean visible) throws DatabaseException {\r
-        DiagramResource dr = DiagramResource.getInstance(graph);\r
-        tag(graph, diagram, dr.DisplayMargins, visible);\r
-    }\r
-\r
-    public static void setDiagramDesc(WriteGraph graph, Resource diagram, DiagramDesc desc) throws DatabaseException {\r
-        DiagramGraphUtil.setPageDesc(graph, diagram, desc.getPageDesc());\r
-        DiagramGraphUtil.setGridSize(graph, diagram, desc.getGridSize());\r
-        DiagramGraphUtil.setPageBordersVisible(graph, diagram, desc.isPageBordersVisible());\r
-        DiagramGraphUtil.setMarginsVisible(graph, diagram, desc.isMarginsVisible());\r
-        // Add comment to change set.\r
-        CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
-        graph.addMetadata(cm.add("Set diagram description for diagram resource " + diagram));\r
-    }\r
-\r
-    /**\r
-     * Potentially returns the connection connected to the element with the\r
-     * given connectionRelation.\r
-     */\r
-    public static Resource getRelatedConnection(ReadGraph g, Resource element, Resource connectionRelation) throws DatabaseException {\r
-        StructuralResource2 sr = StructuralResource2.getInstance(g);\r
-        for(Resource connector : g.getObjects(element, connectionRelation))\r
-            for(Resource connection : g.getObjects(connector, sr.Connects))\r
-                if(!connection.equals(element))\r
-                    return connection;\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * Returns the connection type of a potential connection connected to the\r
-     * element with the given connectionRelation.\r
-     */\r
-    public static Resource getRelatedConnectionType(ReadGraph g, Resource element, Resource connectionRelation) throws DatabaseException {\r
-        StructuralResource2 sr = StructuralResource2.getInstance(g);\r
-        for(Resource connector : g.getObjects(element, connectionRelation))\r
-            for(Resource connection : g.getObjects(connector, sr.Connects))\r
-                if(!connection.equals(element))\r
-                    for(Resource connectionType : g.getObjects(connection, sr.HasConnectionType))\r
-                        return connectionType;\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * Returns a flag that is joined to this flag with a ConnectionJoin.\r
-     */\r
-    public static Resource getJoinedFlag(ReadGraph g, Resource flag) throws DatabaseException {\r
-        DiagramResource dr = DiagramResource.getInstance(g);\r
-        for(Resource join : g.getObjects(flag, dr.FlagIsJoinedBy))\r
-            for(Resource otherFlag : g.getObjects(join, dr.JoinsFlag))\r
-                if(!otherFlag.equals(flag))\r
-                    return otherFlag;\r
-        return null;\r
-    }\r
-\r
-    public static Resource getConnectionTypeForFlag(ReadGraph g, Resource flag) throws DatabaseException {\r
-        DiagramResource dr = DiagramResource.getInstance(g);\r
-\r
-        Resource connectionType = getRelatedConnectionType(g, flag, dr.Flag_ConnectionPoint);\r
-        if(connectionType != null)\r
-            return connectionType;\r
-\r
-        Resource otherFlag = getJoinedFlag(g, flag);\r
-        if(otherFlag == null)\r
-            return null;\r
-\r
-        return getRelatedConnectionType(g, otherFlag, dr.Flag_ConnectionPoint);\r
-    }\r
-\r
-    /**\r
-     * Checks if the two specified diagram elements exist on the same diagram.\r
-     */\r
-    public static boolean onSameDiagram(ReadGraph graph, Resource element1, Resource element2) throws DatabaseException {\r
-        return !Collections.disjoint(\r
-                OrderedSetElementsPredicate.INSTANCE.getSubjects(graph, element1),\r
-                OrderedSetElementsPredicate.INSTANCE.getSubjects(graph, element2));\r
-    }\r
-\r
-    /**\r
-     * Checks whether a diagram element has a <code>DIAGRAM.Routing</code> tag\r
-     * that is adaptable to {@link IRouter2}.\r
-     * \r
-     * @param graph\r
-     * @param element\r
-     * @param procedure\r
-     */\r
-    public static void getPossibleRouter(AsyncReadGraph graph, final Resource element, final AsyncProcedure<IRouter2> procedure) {\r
-        DiagramResource dr = graph.getService(DiagramResource.class);\r
-        graph.forPossibleStatement(element, dr.Routing, new AsyncProcedure<Statement>() {\r
-            @Override\r
-            public void exception(AsyncReadGraph graph, Throwable throwable) {\r
-                procedure.exception(graph, throwable);\r
-            }\r
-            @Override\r
-            public void execute(AsyncReadGraph graph, Statement result) {\r
-                if (result != null)\r
-                    graph.forPossibleAdapted(result.getPredicate(), IRouter2.class, procedure);\r
-                else\r
-                    procedure.execute(graph, null);\r
-            }\r
-        });\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param modelingRules\r
-     * @param connection\r
-     * @param diagram\r
-     * @param edge\r
-     * @param firstTerminal\r
-     * @param secondTerminal\r
-     * @throws DatabaseException\r
-     */\r
-    public static void loadConnectionVisuals(ReadGraph graph, IModelingRules modelingRules, Resource connection,\r
-            IDiagram diagram, IElement edge, DesignatedTerminal firstTerminal, DesignatedTerminal secondTerminal)\r
-    throws DatabaseException {\r
-        List<EdgeVisuals> evs = edge.getElementClass().getItemsByClass(EdgeVisuals.class);\r
-        if (evs.isEmpty())\r
-            return;\r
-\r
-        IAttachmentRelationMap attachmentRelations = modelingRules.getAttachmentRelations(graph, connection);\r
-\r
-        IConnectionPoint firstCp = ConnectionUtil.toConnectionPoint(graph, firstTerminal);\r
-        IConnectionPoint secondCp = ConnectionUtil.toConnectionPoint(graph, secondTerminal);\r
-\r
-        Resource firstAttachment = null;\r
-        Resource secondAttachment = null;\r
-\r
-        if (firstCp instanceof CPTerminal)\r
-            firstAttachment = attachmentRelations.get(graph, (CPTerminal) firstCp);\r
-        if (secondCp instanceof CPTerminal)\r
-            secondAttachment = attachmentRelations.get(graph, (CPTerminal) secondCp);\r
-\r
-        if (DebugPolicy.DEBUG_CONNECTION_VISUALS_LOAD) {\r
-            System.out.println("first attachment relation : " + NameUtils.getSafeName(graph, firstAttachment));\r
-            System.out.println("second attachment relation : " + NameUtils.getSafeName(graph, secondAttachment));\r
-        }\r
-\r
-        // 1. Configure edge ends\r
-        loadEdgeEnds(graph, modelingRules, connection, edge, firstAttachment, secondAttachment);\r
-\r
-        // 2. Configure edge line style\r
-        loadLineStyle(graph, modelingRules, connection, edge);\r
-    }\r
-\r
-    public static void loadEdgeEnds(ReadGraph graph, IModelingRules modelingRules, Resource connection, IElement edge,\r
-            Resource firstAttachment, Resource secondAttachment) throws DatabaseException {\r
-        EdgeVisualsConfigurer startConfig = (firstAttachment != null) ? graph.syncRequest(Queries.adapt(\r
-                firstAttachment, EdgeVisualsConfigurer.class, true)) : null;\r
-        EdgeVisualsConfigurer endConfig = (secondAttachment != null) ? graph.syncRequest(Queries.adapt(\r
-                secondAttachment, EdgeVisualsConfigurer.class, true)) : null;\r
-\r
-        for (EdgeVisuals ev : edge.getElementClass().getItemsByClass(EdgeVisuals.class)) {\r
-            if (startConfig != null)\r
-                startConfig.configure(edge, ev, EdgeVisuals.BEGIN);\r
-            else\r
-                ev.setArrowType(edge, EdgeEnd.Begin, ArrowType.None);\r
-            if (endConfig != null)\r
-                endConfig.configure(edge, ev, EdgeVisuals.END);\r
-            else\r
-                ev.setArrowType(edge, EdgeEnd.End, ArrowType.None);\r
-        }\r
-    }\r
-\r
-    public static void loadLineStyle(ReadGraph graph, IModelingRules modelingRules, Resource connection, IElement edge)\r
-    throws DatabaseException {\r
-        Resource connectionType = modelingRules.getConnectionType(graph, connection);\r
-        if (connectionType != null) {\r
-            loadLineStyleFromConnectionType(graph, modelingRules, connectionType, edge);\r
-        }\r
-    }\r
-\r
-    public static void loadLineStyleFromConnectionType(ReadGraph graph, IModelingRules modelingRules, Resource connectionType, IElement edge)\r
-    throws DatabaseException {\r
-        edge.setHint(ElementHints.KEY_CONNECTION_TYPE, connectionType);\r
-        if (DebugPolicy.DEBUG_CONNECTION_VISUALS_LOAD)\r
-            System.out.println("Connection type : " + NameUtils.getSafeName(graph, connectionType));\r
-\r
-        // Load standard visual aspects of the specified edge\r
-        ConnectionVisuals cv = graph.syncRequest(DiagramRequests.getConnectionVisuals(connectionType));\r
-\r
-        if (cv.color != null) {\r
-            for (FillColor fc : edge.getElementClass().getItemsByClass(FillColor.class)) {\r
-                fc.setFillColor(edge, cv.toColor());\r
-            }\r
-        }\r
-        for (EdgeVisuals ev : edge.getElementClass().getItemsByClass(EdgeVisuals.class)) {\r
-            if (cv.stroke != null)\r
-                ev.setStroke(edge, cv.stroke);\r
-            if (cv.strokeType != null)\r
-                ev.setStrokeType(edge, cv.strokeType);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param connectionPart\r
-     * @return\r
-     * @throws DatabaseException\r
-     */\r
-    public static ConnectionSegmentEnd resolveConnectionSegmentEnd(ReadGraph graph, Resource connectionPart)\r
-    throws DatabaseException {\r
-        BasicResources br = BasicResources.getInstance(graph);\r
-        if (graph.isInstanceOf(connectionPart, br.DIA.BranchPoint))\r
-            return ConnectionSegmentEnd.BRANCH;\r
-        if (graph.isInstanceOf(connectionPart, br.DIA.Connector))\r
-            return ConnectionSegmentEnd.CONNECTOR;\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param diagram\r
-     * @param segmentEnd\r
-     * @param endType\r
-     * @return\r
-     * @throws DatabaseException\r
-     */\r
-    public static DesignatedTerminal findDesignatedTerminal(ReadGraph graph, IDiagram diagram, Resource segmentEnd, ConnectionSegmentEnd endType)\r
-    throws DatabaseException {\r
-        if (DebugPolicy.DEBUG_TERMINAL_SEARCH)\r
-            System.out.println("findDesignatedTerminal: " + NameUtils.getSafeName(graph, segmentEnd) + " : " + endType);\r
-\r
-        BasicResources br = BasicResources.getInstance(graph);\r
-        DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);\r
-\r
-        switch (endType) {\r
-            case CONNECTOR: {\r
-                List<Terminal> ts = new ArrayList<Terminal>();\r
-                for (Statement stm : graph.getStatements(segmentEnd, br.STR.Connects)) {\r
-                    // Ignore the Is Connector Of relation that goes to the\r
-                    // owner :Connection\r
-                    if (graph.isSubrelationOf(stm.getPredicate(), br.DIA.IsConnectorOf))\r
-                        continue;\r
-\r
-                    Resource connectionRelation = graph.getInverse(stm.getPredicate());\r
-                    if (DebugPolicy.DEBUG_TERMINAL_SEARCH)\r
-                        System.out.println("CONNECTION RELATION: " + NameUtils.getSafeName(graph, connectionRelation));\r
-                    Resource elementResource = stm.getObject();\r
-                    if (DebugPolicy.DEBUG_TERMINAL_SEARCH)\r
-                        System.out.println("ELEMENT RESOURCE: " + NameUtils.getSafeName(graph, elementResource));\r
-                    IElement e = dem.getElement(diagram, elementResource);\r
-                    if (e == null) {\r
-                        return null;\r
-//                        throw new ValidationException("connector "\r
-//                                + NameUtils.getSafeName(graph, segmentEnd)\r
-//                                + " is connected to an entity that has not (yet) been loaded as an IElement: "\r
-//                                + NameUtils.getSafeName(graph, elementResource));\r
-                    }\r
-\r
-                    TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);\r
-                    ts.clear();\r
-                    tt.getTerminals(e, ts);\r
-                    for (Terminal t : ts) {\r
-                        if (t instanceof ResourceTerminal) {\r
-                            ResourceTerminal rt = (ResourceTerminal) t;\r
-                            Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, rt.getResource());\r
-                            if (DebugPolicy.DEBUG_TERMINAL_SEARCH) {\r
-                                System.out.println("connection relation: "\r
-                                        + NameUtils.getSafeName(graph, connectionRelation) + " " + connectionRelation.getResourceId());\r
-                                System.out.println("  terminal: " + NameUtils.getSafeName(graph, rt.getResource()) + " " + rt.getResource().getResourceId());\r
-                                System.out.println("  binds:    " + NameUtils.getSafeName(graph, binds) + " " + binds.getResourceId());\r
-                            }\r
-                            if (graph.isSubrelationOf(connectionRelation, binds)) {\r
-                                return new DesignatedTerminal(e, t);\r
-                            }\r
-                        }\r
-                    }\r
-\r
-                    throw new ValidationException("connector "\r
-                            + NameUtils.getSafeName(graph, segmentEnd)\r
-                            + " is connected using a relation that is not its own: "\r
-                            + NameUtils.getSafeName(graph, connectionRelation));\r
-                }\r
-                // throw new\r
-                // ValidationException("connector " +\r
-                // NameUtils.getSafeName(g, segmentEnd) +\r
-                // " is not connected to anything");\r
-                return null;\r
-            }\r
-            case BRANCH: {\r
-                List<Terminal> ts = new ArrayList<Terminal>();\r
-                IElement e = dem.getElement(diagram, segmentEnd);\r
-                if (e == null) {\r
-//                    throw new ValidationException("branch point "\r
-//                            + NameUtils.getSafeName(graph, segmentEnd)\r
-//                            + " has not (yet) been loaded as an IElement");\r
-                    return null;\r
-                }\r
-\r
-                TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);\r
-                tt.getTerminals(e, ts);\r
-                if (ts.size() != 1)\r
-                    throw new IllegalStateException("branch point element has " + ts.size()\r
-                            + " terminals, expected 1");\r
-                return new DesignatedTerminal(e, ts.get(0));\r
-            }\r
-            default:\r
-                throw new IllegalArgumentException("unexpected connection segment end: " + endType);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param diagram\r
-     * @param terminalStm the statement that goes from the connection\r
-     *        connector to the node with inverse relation of the terminal\r
-     *        relation.\r
-     * @return\r
-     * @throws DatabaseException\r
-     */\r
-    public static DesignatedTerminal getDesignatedTerminalForConnector(ReadGraph graph, IDiagram diagram, Resource elementResource, Resource terminalRelation, Resource connector)\r
-    throws DatabaseException {\r
-        if (DebugPolicy.DEBUG_TERMINAL_SEARCH)\r
-            System.out.println("getDesignatedTerminalForConnector: ("\r
-                    + NameUtils.getSafeName(graph, elementResource) + ", "\r
-                    + NameUtils.getSafeName(graph, terminalRelation) + ", "\r
-                    + NameUtils.getSafeName(graph, connector) + ")"\r
-                    );\r
-\r
-        DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);\r
-        IElement e = dem.getElement(diagram, elementResource);\r
-        if (e == null)\r
-            return null;\r
-\r
-        TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);\r
-        List<Terminal> ts = new ArrayList<Terminal>();\r
-        tt.getTerminals(e, ts);\r
-        for (Terminal t : ts) {\r
-            if (t instanceof ResourceTerminal) {\r
-                ResourceTerminal rt = (ResourceTerminal) t;\r
-                Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, rt.getResource());\r
-                if (DebugPolicy.DEBUG_TERMINAL_SEARCH) {\r
-                    System.out.println("connection relation: "\r
-                            + NameUtils.getSafeName(graph, terminalRelation, true));\r
-                    System.out.println("  terminal: " + NameUtils.getSafeName(graph, rt.getResource(), true));\r
-                    System.out.println("  binds:    " + NameUtils.getSafeName(graph, binds, true));\r
-                }\r
-                if (graph.isSubrelationOf(terminalRelation, binds)) {\r
-                    return new DesignatedTerminal(e, t);\r
-                }\r
-            }\r
-        }\r
-\r
-        throw new ValidationException("terminal connection statement ("\r
-                + NameUtils.getSafeName(graph, elementResource) + ", "\r
-                + NameUtils.getSafeName(graph, terminalRelation) + ", "\r
-                + NameUtils.getSafeName(graph, connector) + ")"\r
-                + " is using using a terminal relation that is not its own: "\r
-                + NameUtils.getSafeName(graph, terminalRelation));\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @return\r
-     * @throws DatabaseException\r
-     */\r
-    public static TerminalMap getElementTerminals(ReadGraph graph, Resource element)\r
-    throws DatabaseException {\r
-        DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        Resource elementType = graph.getPossibleType(element, DIA.Element);\r
-        return elementType != null ? getElementTypeTerminals(graph, elementType) : TerminalMap.EMPTY;\r
-    }\r
-\r
-    private static final boolean DEBUG_GET_ELEMENT_TYPE_TERMINALS = false;\r
-\r
-    /**\r
-     * @param graph\r
-     * @param elementType\r
-     * @return\r
-     * @throws DatabaseException\r
-     */\r
-    public static TerminalMap getElementTypeTerminals(ReadGraph graph, Resource elementType) throws DatabaseException {\r
-        StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
-        DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)\r
-            System.out.println("getElementTypeTerminals: " + NameUtils.getSafeName(graph, elementType));\r
-        Resource definedBy = graph.getSingleObject(elementType, STR.IsDefinedBy);\r
-        Collection<Resource> parts = OrderedSetUtils.toList(graph, definedBy);\r
-        if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)\r
-            System.out.println("\tdefining part count: " + parts.size());\r
-        TerminalMap result = null;\r
-        for (Resource part : parts) {\r
-            if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)\r
-                System.out.println("\t\tpart: " + NameUtils.getSafeName(graph, part));\r
-            if (graph.isInstanceOf(part, DIA.Terminal)) {\r
-                Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, part);\r
-                if (result == null)\r
-                    result = new TerminalMap(parts.size());\r
-                if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)\r
-                    System.out.println("\t\t\tFOUND TERMINAL <-> BINDING RELATION: " + NameUtils.getSafeName(graph, part) + " <-> " + NameUtils.getSafeName(graph, binds));\r
-                result.put(part, binds);\r
-            }\r
-        }\r
-        return result != null ? result : TerminalMap.EMPTY;\r
-    }\r
-\r
-    /**\r
-     * Get the value of a specified on/off diagram preference setting (=tag)\r
-     * where the tag may be stored in:\r
-     * <ol>\r
-     * <li>The diagram itself</li>\r
-     * <li>The model</li>\r
-     * <li>The project</li>\r
-     * </ol>\r
-     * \r
-     * @param graph database access\r
-     * @param diagram the diagram to look for the tag in\r
-     * @param preference the tag relation of the boolean preference to check for\r
-     * @return value of the preference\r
-     * @throws DatabaseException\r
-     */\r
-    public static boolean getDiagramTagPreference(ReadGraph graph, Resource diagram, Resource preference) throws DatabaseException {\r
-        boolean result = graph.hasStatement(diagram, preference);\r
-        if (!result) {\r
-            Resource model = graph.sync(new PossibleModel(diagram));\r
-            if (model != null)\r
-                result = graph.hasStatement(model, preference);\r
-            if (!result)\r
-                result = graph.hasStatement(Simantics.getProjectResource(), preference);\r
-        }\r
-        return result;\r
-    }\r
-\r
-    public static void rotateConnection(WriteGraph graph, Resource r, \r
-            double cx, double cy, boolean clockwise) throws DatabaseException {\r
-        DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        for(Resource node : graph.getObjects(r, DIA.HasInteriorRouteNode))\r
-            if(graph.isInstanceOf(node, DIA.RouteLine)) {\r
-                boolean isHorizontal = (Boolean)graph.getRelatedValue(node, DIA.IsHorizontal);\r
-                double position = (Double)graph.getRelatedValue(node, DIA.HasPosition);\r
-                \r
-                if(isHorizontal) {\r
-                    position -= cy;\r
-                    if(clockwise)\r
-                        position = -position;\r
-                    position += cx;\r
-                }\r
-                else {\r
-                    position -= cx;\r
-                    if(!clockwise)\r
-                        position = -position;\r
-                    position += cy;\r
-                }\r
-                isHorizontal = !isHorizontal;                \r
-                \r
-                graph.claimLiteral(node, DIA.IsHorizontal, isHorizontal);\r
-                graph.claimLiteral(node, DIA.HasPosition, position);\r
-            }\r
-    }\r
-\r
-    public static void flipConnection(WriteGraph graph, Resource r,\r
-            boolean xAxis, double c) throws DatabaseException {\r
-        DiagramResource DIA = DiagramResource.getInstance(graph);\r
-        for(Resource node : graph.getObjects(r, DIA.HasInteriorRouteNode))\r
-            if(graph.isInstanceOf(node, DIA.RouteLine)) {\r
-                boolean isHorizontal = (Boolean)graph.getRelatedValue(node, DIA.IsHorizontal);\r
-\r
-                if(isHorizontal == xAxis) {\r
-                    double position = (Double)graph.getRelatedValue(node, DIA.HasPosition);\r
-                    position = 2*c-position;\r
-                    graph.claimLiteral(node, DIA.HasPosition, position);\r
-                }\r
-            }\r
-    }\r
-    \r
-    /*public static void addConnectionPoint(WriteGraph g, Resource symbol, Resource terminal, \r
-            Resource diagramConnectionRelation) throws DatabaseException {\r
-        Layer0 L0 = Layer0.getInstance(g);\r
-        StructuralResource2 STR = StructuralResource2.getInstance(g);\r
-        DiagramResource DIA = DiagramResource.getInstance(g);\r
-        \r
-        Resource variable = g.newResource();\r
-        g.claim(variable, L0.InstanceOf, null, STR.ConnectionVariable);\r
-        g.claim(terminal, DIA.HasConnectionVariable, variable);\r
-        g.claim(variable, STR.Binds, diagramConnectionRelation);\r
-        g.claim(variable, STR.IsParameterOf, symbol);\r
-    }\r
-    \r
-\r
-    public static Resource getConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {\r
-        return g.getSingleObject(\r
-                g.getSingleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionVariable),\r
-                StructuralResource2.getInstance(g).Binds);\r
-    }\r
-\r
-    public static Resource getPossibleConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {\r
-        Resource connectionVariable = g.getPossibleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionVariable);\r
-        return (connectionVariable == null) ? null : g.getPossibleObject(connectionVariable, StructuralResource2.getInstance(g).Binds);\r
-    }*/\r
-    \r
-    public static void addConnectionPoint(WriteGraph g, Resource symbol, Resource terminal, \r
-            Resource diagramConnectionRelation) throws DatabaseException {\r
-        Layer0 L0 = Layer0.getInstance(g);\r
-        DiagramResource DIA = DiagramResource.getInstance(g);\r
-        \r
-        g.claim(terminal, DIA.HasConnectionPoint, diagramConnectionRelation);\r
-        g.claim(diagramConnectionRelation, L0.HasDomain, symbol);\r
-    }\r
-    \r
-\r
-    public static Resource getConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {\r
-        return g.getSingleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionPoint);\r
-    }\r
-\r
-    public static Resource getPossibleConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {\r
-        return g.getPossibleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionPoint);\r
-    }\r
-\r
-    public static Collection<Resource> getTerminals(ReadGraph g, Resource symbol) throws DatabaseException {\r
-//        Layer0 L0 = Layer0.getInstance(g);\r
-        StructuralResource2 STR = StructuralResource2.getInstance(g);\r
-        DiagramResource DIA = DiagramResource.getInstance(g);\r
-        List<Resource> terminals = null;\r
-        for (Resource definedBy : g.getObjects(symbol, STR.IsDefinedBy)) {\r
-            Collection<Resource> elements = g.syncRequest( new OrderedSet(definedBy) );\r
-            if (terminals == null)\r
-                terminals = new ArrayList<Resource>( elements.size() );\r
-            for (Resource element : elements)\r
-                if (g.isInstanceOf(element, DIA.Terminal))\r
-                    terminals.add(element);\r
-        }\r
-//        Collection<Resource> definedBy = g.getObjects(symbol, STR.IsDefinedBy);\r
-//        if (!definedBy.isEmpty()) {\r
-//            Collection<Resource> relations = g.getObjects(symbol, L0.DomainOf);\r
-//            terminals = new ArrayList<Resource>(relations.size());\r
-//            for(Resource relation : relations) {\r
-//                for (Resource element : g.getObjects(relation, DIA.HasConnectionPoint_Inverse)) {\r
-//                    Collection<Resource> owners = OrderedSetUtils.getOwnerLists(g, element, DIA.Diagram);\r
-//                    if (!Collections.disjoint(definedBy, owners))\r
-//                        terminals.add(element);\r
-//                }\r
-//            }\r
-//        }\r
-        return terminals == null ? Collections.<Resource>emptyList() : terminals;\r
-    }\r
-       \r
-    /**\r
-     * Determines the connection type of the given diagram connection. Uses the modeling rules\r
-     * specified in the diagram the connection belongs to.\r
-     */\r
-       public static Resource determineConnectionType(ReadGraph graph, Resource diagramConnection) throws DatabaseException {\r
-               Layer0 L0 = Layer0.getInstance(graph);\r
-               Resource diagram = graph.getPossibleObject(diagramConnection, L0.PartOf);\r
-               if (diagram == null)\r
-                       // Invalid diagram connection resource, not a part of any diagram.\r
-                       return null;\r
-               IModelingRules modelingRules = graph.syncRequest(DiagramRequests.getModelingRules(diagram, null));\r
-               if (modelingRules == null)\r
-                       return null;\r
-               return determineConnectionType(graph, diagramConnection, modelingRules);\r
-       }\r
-\r
-       /**\r
-     * Determines the connection type of the given diagram connection assuming the given modeling rules.\r
-     */\r
-       public static Resource determineConnectionType(ReadGraph graph, Resource diagramConnection, IModelingRules modelingRules) throws DatabaseException {\r
-\r
-               Set<IConnectionPoint> cps = new THashSet<IConnectionPoint>();\r
-               DiagramRequests.expandConnections(graph, diagramConnection, new THashSet<Resource>(), cps);\r
-               return modelingRules.computeConnectionType(graph, cps);\r
-               \r
-       }\r
-       \r
-       public static void defaultSymbolDropHandler(WriteGraph graph, List<WorkbenchSelectionElement> drop) throws DatabaseException {\r
-               System.err.println("dropped " + drop);\r
-       }\r
-    \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.synchronization.graph;
+
+import gnu.trove.set.hash.THashSet;
+
+import java.awt.geom.AffineTransform;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.datatypes.literal.Vec2d;
+import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.CommentMetadata;
+import org.simantics.db.common.primitiverequest.OrderedSet;
+import org.simantics.db.common.request.IndexRoot;
+import org.simantics.db.common.request.Queries;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.common.utils.OrderedSetUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.DoesNotContainValueException;
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
+import org.simantics.db.exception.NoSingleResultException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.db.layer0.request.PossibleModel;
+import org.simantics.db.procedure.AsyncProcedure;
+import org.simantics.diagram.connection.ConnectionSegmentEnd;
+import org.simantics.diagram.connection.ConnectionVisuals;
+import org.simantics.diagram.content.ConnectionUtil;
+import org.simantics.diagram.content.DesignatedTerminal;
+import org.simantics.diagram.content.ElementContext;
+import org.simantics.diagram.content.ResourceTerminal;
+import org.simantics.diagram.content.TerminalMap;
+import org.simantics.diagram.internal.DebugPolicy;
+import org.simantics.diagram.query.DiagramRequests;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.diagram.stubs.G2DResource;
+import org.simantics.g2d.connection.EdgeVisualsConfigurer;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.DataElementMap;
+import org.simantics.g2d.diagram.handler.Topology.Terminal;
+import org.simantics.g2d.element.ElementHints;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.element.handler.EdgeVisuals;
+import org.simantics.g2d.element.handler.EdgeVisuals.ArrowType;
+import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
+import org.simantics.g2d.element.handler.FillColor;
+import org.simantics.g2d.element.handler.TerminalTopology;
+import org.simantics.g2d.elementclass.FlagClass;
+import org.simantics.g2d.elementclass.FlagClass.Type;
+import org.simantics.g2d.page.DiagramDesc;
+import org.simantics.g2d.routing.IRouter2;
+import org.simantics.g2d.svg.LineCap;
+import org.simantics.g2d.svg.LineJoin;
+import org.simantics.g2d.utils.Alignment;
+import org.simantics.layer0.Layer0;
+import org.simantics.layer0.utils.binaryPredicates.OrderedSetElementsPredicate;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.scl.commands.Commands;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.structural2.modelingRules.CPTerminal;
+import org.simantics.structural2.modelingRules.IAttachmentRelationMap;
+import org.simantics.structural2.modelingRules.IConnectionPoint;
+import org.simantics.structural2.modelingRules.IModelingRules;
+import org.simantics.ui.selection.WorkbenchSelectionElement;
+import org.simantics.utils.page.MarginUtils.Margin;
+import org.simantics.utils.page.MarginUtils.Margins;
+import org.simantics.utils.page.PageCentering;
+import org.simantics.utils.page.PageDesc;
+import org.simantics.utils.page.PageOrientation;
+import org.simantics.utils.ui.ErrorLogger;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public final class DiagramGraphUtil {
+
+    public static double[] validateAffineTransform(Resource resource, double[] matrix) {
+        if (matrix != null) {
+            if (matrix.length < 4) {
+                ErrorLogger.defaultLogError("resource " + resource + " matrix too small for AffineTransform: " + Arrays.toString(matrix), new Exception("trace"));
+                return null;
+            }
+
+            // Validate scale/rotation part
+            if (DebugPolicy.DEBUG_TRANSFORM_LOAD) {
+                double det = new AffineTransform(matrix).getDeterminant();
+                double detabs = Math.abs(det);
+                if (detabs < DebugPolicy.DETERMINANT_LIMIT_LOW)
+                    ErrorLogger.defaultLogWarning("resource " + resource + " transform determinant absolute value is close to zero: " + detabs + "(transform=" + Arrays.toString(matrix) + ")", new Exception("trace"));
+                if (detabs > DebugPolicy.DETERMINANT_LIMIT_HIGH)
+                    ErrorLogger.defaultLogWarning("resource " + resource + " transform determinant absolute value is suspiciously large: " + detabs + "(transform=" + Arrays.toString(matrix) + ")", new Exception("trace"));
+            }
+
+            if (matrix.length > 5) {
+                // Validate translation
+                double xabs = Math.abs(matrix[4]);
+                double yabs = Math.abs(matrix[5]);
+                double limit = DebugPolicy.TRANSLATION_LIMIT_HIGH;
+                boolean largeX = xabs > limit;
+                boolean largeY = yabs > limit;
+                if (largeX || largeY)
+                    ErrorLogger.defaultLogWarning("resource " + resource + " transform translation is suspiciously large: " + Arrays.toString(matrix), new Exception("trace"));
+                return matrix;
+            }
+        }
+        return matrix;
+    }
+
+    public static AffineTransform getAffineTransform(ReadGraph graph, Resource resource) throws DatabaseException {
+        G2DResource g2d = G2DResource.getInstance(graph);
+        return getAffineTransform(graph, resource, g2d.HasTransform, true);
+    }
+
+    public static Vec2d getOffset(ReadGraph graph, Resource resource) throws DatabaseException {
+       DiagramResource DIA = DiagramResource.getInstance(graph);
+        Vec2d offset = graph.getPossibleRelatedValue(resource, DIA.Element_profileMonitorOffset, Vec2d.BINDING);
+        if(offset != null) return offset;
+        else return new Vec2d(0, 0);
+    }
+    
+    public static boolean getProfileMonitorsHidden(ReadGraph graph, Resource resource) throws DatabaseException {
+       DiagramResource DIA = DiagramResource.getInstance(graph);
+        Boolean value = graph.getPossibleRelatedValue(resource, DIA.Element_hideProfileMonitors, Bindings.BOOLEAN);
+        if(value == null) value = false;
+        return value;
+    }
+
+    public static boolean getProfileMonitorsUp(ReadGraph graph, Resource resource) throws DatabaseException {
+       DiagramResource DIA = DiagramResource.getInstance(graph);
+        Boolean value = graph.getPossibleRelatedValue(resource, DIA.Element_upProfileMonitors, Bindings.BOOLEAN);
+        if(value == null) value = true;
+        return value;
+    }
+
+    public static double getProfileMonitorSpacing(ReadGraph graph, Resource resource) throws DatabaseException {
+       DiagramResource DIA = DiagramResource.getInstance(graph);
+        Double value = graph.getPossibleRelatedValue(resource, DIA.Element_profileMonitorSpacing, Bindings.DOUBLE);
+        if(value == null) value = 0.0;
+        return value;
+    }
+
+    public static AffineTransform getDynamicAffineTransform(ReadGraph graph, Resource runtime, Resource element) throws DatabaseException {
+        DiagramResource DIA = DiagramResource.getInstance(graph);
+        return getDynamicAffineTransform(graph, runtime, element, DIA.HasDynamicTransform, true);
+    }
+
+    /**
+     * @param graph
+     * @param element
+     * @return
+     * @throws DatabaseException
+     */
+    public static AffineTransform getWorldTransform(ReadGraph graph, Resource element) throws DatabaseException {
+        ModelingResources MOD = ModelingResources.getInstance(graph);
+        AffineTransform result = DiagramGraphUtil.getAffineTransform(graph, element);
+        while (true) {
+            Resource parentComponent = graph.getPossibleObject(element, MOD.HasParentComponent);
+            if (parentComponent == null)
+                return result;
+            element = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);
+            if (element == null)
+                return result;
+            AffineTransform tr = DiagramGraphUtil.getAffineTransform(graph, element);
+            tr.setToTranslation(tr.getTranslateX(), tr.getTranslateY());
+            result.preConcatenate(tr);
+        }
+    }
+
+    /**
+     * @param graph
+     * @param runtime
+     * @param element
+     * @return
+     * @throws DatabaseException
+     */
+    public static AffineTransform getDynamicWorldTransform(ReadGraph graph, Resource runtime, Resource element) throws DatabaseException {
+        ModelingResources MOD = ModelingResources.getInstance(graph);
+        AffineTransform result = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, element);
+        while (true) {
+            Resource parentComponent = graph.getPossibleObject(element, MOD.HasParentComponent);
+            if (parentComponent == null)
+                return result;
+            element = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);
+            if (element == null)
+                return result;
+            AffineTransform tr = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, element);
+            tr.setToTranslation(tr.getTranslateX(), tr.getTranslateY());
+            result.preConcatenate(tr);
+        }
+    }
+
+    /**
+     * @param graph
+     * @param resource
+     * @param relation
+     * @param invalidAsIdentity true to return invalid transforms as identity
+     *        transforms, <code>false</code> to return <code>null</code>
+     * @return
+     * @throws DatabaseException
+     */
+    public static AffineTransform getAffineTransform(ReadGraph graph, Resource resource, Resource relation, boolean invalidAsIdentity) throws DatabaseException {
+        double mat[] = getPossibleRelatedDoubleArray(graph, resource, relation);
+        mat = validateAffineTransform(resource, mat);
+        return mat != null ? new AffineTransform(mat) :
+            invalidAsIdentity ? new AffineTransform() : null;
+    }
+
+    public static AffineTransform getDynamicAffineTransform(ReadGraph graph, Resource runtime, Resource element, Resource relation, boolean invalidAsIdentity) throws DatabaseException {
+        double mat[] = graph.getPossibleRelatedValue2(element, relation, new ElementContext(runtime, element), Bindings.DOUBLE_ARRAY);
+        mat = validateAffineTransform(element, mat);
+        return mat != null ? new AffineTransform(mat) :
+            invalidAsIdentity ? new AffineTransform() : null;
+    }
+    
+    public static double[] getPossibleRelatedDoubleArray(ReadGraph graph, Resource resource, Resource relation) throws DatabaseException {
+        Resource res = graph.getPossibleObject(resource, relation);
+        if (res == null)
+            return null;
+        return graph.getValue(res, Bindings.getBindingUnchecked(double[].class));
+    }
+    
+    public static AffineTransform getTransform(ReadGraph graph, Resource resource) throws DatabaseException {
+        DiagramResource DIA = DiagramResource.getInstance(graph);
+
+        double[] matrix = graph.getPossibleRelatedValue(resource, DIA.HasTransform, Bindings.DOUBLE_ARRAY);
+        if (matrix == null)
+            return new AffineTransform();
+        if (matrix.length < 4)
+            return new AffineTransform();
+        return new AffineTransform(matrix);
+    }
+
+    public static void setTransform(WriteGraph graph, Resource resource, AffineTransform at) throws DatabaseException {
+        double[] matrix = new double[6];
+        at.getMatrix(matrix);
+        changeTransform(graph, resource, matrix);
+    }
+    
+    public static void setTransform(WriteGraph graph, Resource resource, double[] matrix) throws DatabaseException {
+        DiagramResource DIA = DiagramResource.getInstance(graph);
+        G2DResource G2D = G2DResource.getInstance(graph);
+
+        setRelatedValue(graph, resource, DIA.HasTransform, G2D.Transform, matrix, Bindings.DOUBLE_ARRAY);
+    }
+    
+    public static void changeTransform(WriteGraph graph, Resource resource, AffineTransform at) throws DatabaseException {
+        double[] matrix = new double[6];
+        at.getMatrix(matrix);
+        changeTransform(graph, resource, matrix);
+    }
+    
+    public static void changeTransform(WriteGraph graph, Resource resource, double[] matrix) throws DatabaseException {
+        Commands.get(graph, "Simantics/Diagram/setTransform")
+                .execute(graph, graph.syncRequest(new IndexRoot(resource)), resource, matrix);
+    }
+
+    public static void setRelatedValue(WriteGraph graph, Resource resource, Resource relation, Resource valueType, Object arrayValue, Binding binding) throws DatabaseException {
+        Statement stm = graph.getPossibleStatement(resource, relation);
+        if (stm == null) {
+            addRelatedValue(graph, resource, relation, valueType, arrayValue, binding);
+        } else {
+            // statement might be asserted, check this before overwriting
+            if (!stm.getSubject().equals(resource)) {
+                // Asserted, just add a new related value
+                addRelatedValue(graph, resource, relation, valueType, arrayValue, binding);
+            } else {
+                //Object old = graph.getValue2(p);
+                //if (!Arrays.equals(old, arrayValue))
+                graph.claimValue(stm.getObject(), arrayValue, binding);
+            }
+        }
+    }
+
+    public static Resource addRelatedValue(WriteGraph graph, Resource resource, Resource relation, Resource valueType, Object arrayValue, Binding binding) throws DatabaseException {
+        Resource d = graph.newResource();
+       Layer0 b = Layer0.getInstance(graph);
+        graph.claim(d, b.InstanceOf, null, valueType);
+        graph.claimValue(d, arrayValue);
+        graph.claim(resource, relation, d);
+        return d;
+    }
+
+    public static <T> T getPossibleRelatedValue(ReadGraph graph, Resource r, Resource relation, Class<T> valueClass, T defaultValue) throws DatabaseException {
+        Resource object = graph.getPossibleObject(r, relation);
+        if (object == null)
+            return defaultValue;
+        T t = graph.getPossibleValue(object, Bindings.getBindingUnchecked(valueClass));
+        if (t != null && valueClass.isArray()) {
+            if (defaultValue != null) {
+                int defaultValueLength = Array.getLength(defaultValue);
+                int valueLength = Array.getLength(t);
+                if (valueLength < defaultValueLength)
+                    return defaultValue;
+            }
+        }
+        return t == null ? defaultValue : t;
+    }
+
+    public static Resource getConnectionPointOfTerminal(ReadGraph g, Terminal forTerminal) throws DatabaseException {
+        if (forTerminal instanceof ResourceTerminal)
+            return getConnectionPointOfTerminal(g, ((ResourceTerminal) forTerminal).getResource());
+        return null;
+    }
+
+    public static Resource tryGetBindingRelation(ReadGraph g, Terminal forTerminal) throws DatabaseException {
+        if (forTerminal instanceof ResourceTerminal)
+            return getPossibleConnectionPointOfTerminal(g, ((ResourceTerminal) forTerminal).getResource());
+        return null;
+    }
+
+    public static LineJoin toLineJoin(G2DResource g2d, Resource lineJoin) {
+        if (lineJoin != null) {
+            if (lineJoin.equals(g2d.LineJoin_BevelJoin))
+                return LineJoin.bevel;
+            if (lineJoin.equals(g2d.LineJoin_RoundJoin))
+                return LineJoin.round;
+        }
+        return LineJoin.miter;
+    }
+
+    public static LineCap toLineCap(G2DResource g2d, Resource lineCap) {
+        if (lineCap != null) {
+            if (lineCap.equals(g2d.LineCap_ButtCap))
+                return LineCap.butt;
+            if (lineCap.equals(g2d.LineCap_RoundCap))
+                return LineCap.round;
+        }
+        return LineCap.square;
+    }
+
+    public static Resource toLineJoin(G2DResource g2d, LineJoin lineJoin) {
+        if (lineJoin != null) {
+            if (lineJoin.equals(LineJoin.bevel))
+                return g2d.LineJoin_BevelJoin;
+            if (lineJoin.equals(LineJoin.round))
+                return g2d.LineJoin_RoundJoin;
+        }
+        return g2d.LineJoin_MiterJoin;
+    }
+
+    public static Resource toLineCap(G2DResource g2d, LineCap lineCap) {
+        if (lineCap != null) {
+            if (lineCap.equals(LineCap.butt))
+                return g2d.LineCap_ButtCap;
+            if (lineCap.equals(LineCap.round))
+                return g2d.LineCap_RoundCap;
+        }
+        return g2d.LineCap_SquareCap;
+    }
+
+    public static Alignment toAlignment(Resource align, G2DResource g2d, Alignment defaultValue) {
+        if (align == null)
+            return defaultValue;
+        if (align.equals(g2d.Alignment_Leading))
+            return Alignment.LEADING;
+        if (align.equals(g2d.Alignment_Trailing))
+            return Alignment.TRAILING;
+        if (align.equals(g2d.Alignment_Center))
+            return Alignment.CENTER;
+        return defaultValue;
+    }
+
+    public static Alignment toVerticalAlignment(Resource align, G2DResource g2d, Alignment defaultValue) {
+        if (align == null)
+            return defaultValue;
+        if (align.equals(g2d.Alignment_Leading))
+            return Alignment.LEADING;
+        if (align.equals(g2d.Alignment_Trailing))
+            return Alignment.TRAILING;
+        if (align.equals(g2d.Alignment_Center))
+            return Alignment.CENTER;
+        if (align.equals(g2d.Alignment_Baseline))
+            return Alignment.BASELINE;
+        return defaultValue;
+    }
+
+
+    public static Resource toFlagTypeResource(DiagramResource dr, FlagClass.Type type) {
+        switch (type) {
+            case In: return dr.FlagType_InputFlag;
+            case Out: return dr.FlagType_OutputFlag;
+            default: throw new IllegalArgumentException("unsupported flag type: " + type);
+        }
+    }
+
+    public static FlagClass.Type toFlagType(DiagramResource dr, Resource type) {
+        return toFlagType(dr, type, Type.In);
+    }
+
+    public static FlagClass.Type toFlagType(DiagramResource dr, Resource type, FlagClass.Type defaultValue) {
+        if (type != null) {
+            if (dr.FlagType_InputFlag.equals(type))
+                return Type.In;
+            if (dr.FlagType_OutputFlag.equals(type))
+                return Type.Out;
+        }
+        return defaultValue;
+    }
+
+    public static void tag(WriteGraph g, Resource object, Resource tag, boolean set) throws DatabaseException {
+        if (set)
+            g.claim(object, tag, tag, object);
+        else
+            g.deny(object, tag, tag, object);
+    }
+
+    /**
+     * @param graph
+     * @param diagram the diagram from which to look for a page description
+     *        property
+     * @return if the diagram does not have a page desc definition,
+     *         <code>defaultValue</code> is returned
+     * @throws DatabaseException
+     */
+    public static PageDesc getPageDesc(ReadGraph graph, Resource diagram, PageDesc defaultValue) throws DatabaseException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        Resource pd = graph.getPossibleObject(diagram, dr.HasPageDescription);
+        if (pd == null)
+            return defaultValue;
+        return readPageDesc(graph, pd);
+    }
+
+    /**
+     * @param graph
+     * @param diagram
+     *            the diagram from which to look for a page description property
+     * @return PageDesc for the specified diagram
+     * @throws DatabaseException
+     *             if DIA.HasPageDescription can't be read
+     */
+    public static PageDesc getPageDesc(ReadGraph graph, Resource diagram) throws DatabaseException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        Resource pd = graph.getSingleObject(diagram, dr.HasPageDescription);
+        return readPageDesc(graph, pd);
+    }
+
+    public static PageDesc readPageDesc(ReadGraph graph, Resource pageDesc) throws DatabaseException {
+        Layer0 l0 = Layer0.getInstance(graph);
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        Resource orientation = graph.getSingleObject(pageDesc, dr.PageDescription_Orientation);
+        double[] size = graph.getRelatedValue(pageDesc, dr.PageDescription_Size, Bindings.getBindingUnchecked(double[].class));
+        Resource margins = graph.getSingleObject(pageDesc, dr.PageDescription_Margins);
+        Margins m = readMargins(graph, margins);
+        //PageDesc pd = PageDesc.getDescription(toOrientation(orientation, dr), size[0], size[1]);
+        String name = graph.getPossibleRelatedValue(pageDesc, l0.HasName);
+        if (name == null)
+            name = "";
+        PageDesc pd = new PageDesc(name, toOrientation(orientation, dr), PageCentering.TopLeftAtOrigin, size[0], size[1], m);
+        return pd;
+    }
+
+    public static Margins readMargins(ReadGraph graph, Resource margins) throws NoSingleResultException, DoesNotContainValueException, ServiceException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        double t = graph.getRelatedValue(margins, dr.PageDescription_Margins_Top);
+        double b = graph.getRelatedValue(margins, dr.PageDescription_Margins_Bottom);
+        double l = graph.getRelatedValue(margins, dr.PageDescription_Margins_Left);
+        double r = graph.getRelatedValue(margins, dr.PageDescription_Margins_Right);
+        Margin mt = new Margin(0, 0, t);
+        Margin mb = new Margin(0, 0, b);
+        Margin ml = new Margin(0, 0, l);
+        Margin mr = new Margin(0, 0, r);
+        return new Margins(mt, mb, ml, mr);
+    }
+
+    public static void setPageDesc(WriteGraph graph, Resource diagram, String pageDescRepr) throws DatabaseException {
+        setPageDesc(graph, diagram, PageDesc.fromRepr(pageDescRepr));
+    }
+    
+    public static void setPageDesc(WriteGraph graph, Resource diagram, PageDesc pageDesc) throws DatabaseException {
+       Layer0 b = Layer0.getInstance(graph);
+        G2DResource g2d = G2DResource.getInstance(graph);
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        Resource pd = graph.getPossibleObject(diagram, dr.HasPageDescription);
+        if(pd != null && graph.isImmutable(pd)) {
+               graph.deny(diagram, dr.HasPageDescription);
+               pd = null;
+        }
+        if (pd == null) {
+            pd = graph.newResource();
+            graph.claim(pd, b.InstanceOf, null, dr.PageDescription);
+            graph.claim(diagram, dr.HasPageDescription, pd);
+        }
+        graph.deny(pd, dr.PageDescription_Size);
+        Resource pageSize = graph.newResource();
+        graph.claim(pageSize, b.InstanceOf, null, g2d.Point2D);
+        graph.claimValue(pageSize, new double[] { pageDesc.getWidth(), pageDesc.getHeight() });
+        graph.claim(pd, dr.PageDescription_Size, pageSize);
+        graph.deny(pd, dr.PageDescription_Orientation);
+        graph.claim(pd, dr.PageDescription_Orientation, toOrientationResource(pageDesc.getOrientation(), dr));
+        Resource margins = graph.getPossibleObject(pd, dr.PageDescription_Margins);
+        if (margins == null) {
+            margins = graph.newResource();
+            graph.claim(margins, b.InstanceOf, null, dr.Margins);
+            graph.claim(pd, dr.PageDescription_Margins, margins);
+        }
+        setMargins(graph,pageDesc.getMargins(),margins, dr);
+        graph.claimLiteral(pd, b.HasName,pageDesc.getText());
+    }
+
+    private static PageOrientation toOrientation(Resource orientation, DiagramResource dr) {
+        if (orientation != null) {
+            if (orientation.equals(dr.Orientation_Portrait))
+                return PageOrientation.Portrait;
+            if (orientation.equals(dr.Orientation_Landscape))
+                return PageOrientation.Landscape;
+        }
+        return PageOrientation.Portrait;
+    }
+
+    public static Resource toOrientationResource(PageOrientation orientation, DiagramResource dr) {
+        if (PageOrientation.Portrait.equals(orientation))
+            return dr.Orientation_Portrait;
+        if (PageOrientation.Landscape.equals(orientation))
+            return dr.Orientation_Landscape;
+        return dr.Orientation_Portrait;
+    }
+
+    private static void setMargins(WriteGraph g, Margins margins, Resource marginsR,DiagramResource dr) throws ServiceException, ManyObjectsForFunctionalRelationException {
+
+        g.claimLiteral(marginsR, dr.PageDescription_Margins_Top,margins.top.diagramAbsolute);
+        g.claimLiteral(marginsR, dr.PageDescription_Margins_Bottom,margins.bottom.diagramAbsolute);
+        g.claimLiteral(marginsR, dr.PageDescription_Margins_Left,margins.left.diagramAbsolute);
+        g.claimLiteral(marginsR, dr.PageDescription_Margins_Right,margins.right.diagramAbsolute);
+
+    }
+
+    public static Double getGridSize(ReadGraph graph, Resource diagram, Double defaultValue) throws ManyObjectsForFunctionalRelationException, ServiceException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        Double gridSize = graph.getPossibleRelatedValue(diagram, dr.HasGridSize);
+        return gridSize == null ? defaultValue : gridSize;
+    }
+
+    public static void setGridSize(WriteGraph graph, Resource diagram, double gridSize) throws ManyObjectsForFunctionalRelationException, ServiceException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        graph.claimLiteral(diagram, dr.HasGridSize, gridSize);
+    }
+
+    public static boolean isPageBordersVisible(ReadGraph graph, Resource diagram) throws DatabaseException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        return graph.hasStatement(diagram, dr.DisplayPageSize);
+    }
+
+    public static boolean isMarginsVisible(ReadGraph graph, Resource diagram) throws DatabaseException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        return graph.hasStatement(diagram, dr.DisplayMargins);
+    }
+
+    public static void setPageBordersVisible(WriteGraph graph, Resource diagram, boolean visible) throws DatabaseException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        tag(graph, diagram, dr.DisplayPageSize, visible);
+    }
+
+    public static void setMarginsVisible(WriteGraph graph, Resource diagram, boolean visible) throws DatabaseException {
+        DiagramResource dr = DiagramResource.getInstance(graph);
+        tag(graph, diagram, dr.DisplayMargins, visible);
+    }
+
+    public static void setDiagramDesc(WriteGraph graph, Resource diagram, DiagramDesc desc) throws DatabaseException {
+        DiagramGraphUtil.setPageDesc(graph, diagram, desc.getPageDesc());
+        DiagramGraphUtil.setGridSize(graph, diagram, desc.getGridSize());
+        DiagramGraphUtil.setPageBordersVisible(graph, diagram, desc.isPageBordersVisible());
+        DiagramGraphUtil.setMarginsVisible(graph, diagram, desc.isMarginsVisible());
+        // Add comment to change set.
+        CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
+        graph.addMetadata(cm.add("Set diagram description for diagram resource " + diagram));
+    }
+
+    /**
+     * Potentially returns the connection connected to the element with the
+     * given connectionRelation.
+     */
+    public static Resource getRelatedConnection(ReadGraph g, Resource element, Resource connectionRelation) throws DatabaseException {
+        StructuralResource2 sr = StructuralResource2.getInstance(g);
+        for(Resource connector : g.getObjects(element, connectionRelation))
+            for(Resource connection : g.getObjects(connector, sr.Connects))
+                if(!connection.equals(element))
+                    return connection;
+        return null;
+    }
+
+    /**
+     * Returns the connection type of a potential connection connected to the
+     * element with the given connectionRelation.
+     */
+    public static Resource getRelatedConnectionType(ReadGraph g, Resource element, Resource connectionRelation) throws DatabaseException {
+        StructuralResource2 sr = StructuralResource2.getInstance(g);
+        for(Resource connector : g.getObjects(element, connectionRelation))
+            for(Resource connection : g.getObjects(connector, sr.Connects))
+                if(!connection.equals(element))
+                    for(Resource connectionType : g.getObjects(connection, sr.HasConnectionType))
+                        return connectionType;
+        return null;
+    }
+
+    /**
+     * Returns a flag that is joined to this flag with a ConnectionJoin.
+     */
+    public static Resource getJoinedFlag(ReadGraph g, Resource flag) throws DatabaseException {
+        DiagramResource dr = DiagramResource.getInstance(g);
+        for(Resource join : g.getObjects(flag, dr.FlagIsJoinedBy))
+            for(Resource otherFlag : g.getObjects(join, dr.JoinsFlag))
+                if(!otherFlag.equals(flag))
+                    return otherFlag;
+        return null;
+    }
+
+    public static Resource getConnectionTypeForFlag(ReadGraph g, Resource flag) throws DatabaseException {
+        DiagramResource dr = DiagramResource.getInstance(g);
+
+        Resource connectionType = getRelatedConnectionType(g, flag, dr.Flag_ConnectionPoint);
+        if(connectionType != null)
+            return connectionType;
+
+        Resource otherFlag = getJoinedFlag(g, flag);
+        if(otherFlag == null)
+            return null;
+
+        return getRelatedConnectionType(g, otherFlag, dr.Flag_ConnectionPoint);
+    }
+
+    /**
+     * Checks if the two specified diagram elements exist on the same diagram.
+     */
+    public static boolean onSameDiagram(ReadGraph graph, Resource element1, Resource element2) throws DatabaseException {
+        return !Collections.disjoint(
+                OrderedSetElementsPredicate.INSTANCE.getSubjects(graph, element1),
+                OrderedSetElementsPredicate.INSTANCE.getSubjects(graph, element2));
+    }
+
+    /**
+     * Checks whether a diagram element has a <code>DIAGRAM.Routing</code> tag
+     * that is adaptable to {@link IRouter2}.
+     * 
+     * @param graph
+     * @param element
+     * @param procedure
+     */
+    public static void getPossibleRouter(AsyncReadGraph graph, final Resource element, final AsyncProcedure<IRouter2> procedure) {
+        DiagramResource dr = graph.getService(DiagramResource.class);
+        graph.forPossibleStatement(element, dr.Routing, new AsyncProcedure<Statement>() {
+            @Override
+            public void exception(AsyncReadGraph graph, Throwable throwable) {
+                procedure.exception(graph, throwable);
+            }
+            @Override
+            public void execute(AsyncReadGraph graph, Statement result) {
+                if (result != null)
+                    graph.forPossibleAdapted(result.getPredicate(), IRouter2.class, procedure);
+                else
+                    procedure.execute(graph, null);
+            }
+        });
+    }
+
+    /**
+     * @param graph
+     * @param modelingRules
+     * @param connection
+     * @param diagram
+     * @param edge
+     * @param firstTerminal
+     * @param secondTerminal
+     * @throws DatabaseException
+     */
+    public static void loadConnectionVisuals(ReadGraph graph, IModelingRules modelingRules, Resource connection,
+            IDiagram diagram, IElement edge, DesignatedTerminal firstTerminal, DesignatedTerminal secondTerminal)
+    throws DatabaseException {
+        List<EdgeVisuals> evs = edge.getElementClass().getItemsByClass(EdgeVisuals.class);
+        if (evs.isEmpty())
+            return;
+
+        IAttachmentRelationMap attachmentRelations = modelingRules.getAttachmentRelations(graph, connection);
+
+        IConnectionPoint firstCp = ConnectionUtil.toConnectionPoint(graph, firstTerminal);
+        IConnectionPoint secondCp = ConnectionUtil.toConnectionPoint(graph, secondTerminal);
+
+        Resource firstAttachment = null;
+        Resource secondAttachment = null;
+
+        if (firstCp instanceof CPTerminal)
+            firstAttachment = attachmentRelations.get(graph, (CPTerminal) firstCp);
+        if (secondCp instanceof CPTerminal)
+            secondAttachment = attachmentRelations.get(graph, (CPTerminal) secondCp);
+
+        if (DebugPolicy.DEBUG_CONNECTION_VISUALS_LOAD) {
+            System.out.println("first attachment relation : " + NameUtils.getSafeName(graph, firstAttachment));
+            System.out.println("second attachment relation : " + NameUtils.getSafeName(graph, secondAttachment));
+        }
+
+        // 1. Configure edge ends
+        loadEdgeEnds(graph, modelingRules, connection, edge, firstAttachment, secondAttachment);
+
+        // 2. Configure edge line style
+        loadLineStyle(graph, modelingRules, connection, edge);
+    }
+
+    public static void loadEdgeEnds(ReadGraph graph, IModelingRules modelingRules, Resource connection, IElement edge,
+            Resource firstAttachment, Resource secondAttachment) throws DatabaseException {
+        EdgeVisualsConfigurer startConfig = (firstAttachment != null) ? graph.syncRequest(Queries.adapt(
+                firstAttachment, EdgeVisualsConfigurer.class, true)) : null;
+        EdgeVisualsConfigurer endConfig = (secondAttachment != null) ? graph.syncRequest(Queries.adapt(
+                secondAttachment, EdgeVisualsConfigurer.class, true)) : null;
+
+        for (EdgeVisuals ev : edge.getElementClass().getItemsByClass(EdgeVisuals.class)) {
+            if (startConfig != null)
+                startConfig.configure(edge, ev, EdgeVisuals.BEGIN);
+            else
+                ev.setArrowType(edge, EdgeEnd.Begin, ArrowType.None);
+            if (endConfig != null)
+                endConfig.configure(edge, ev, EdgeVisuals.END);
+            else
+                ev.setArrowType(edge, EdgeEnd.End, ArrowType.None);
+        }
+    }
+
+    public static void loadLineStyle(ReadGraph graph, IModelingRules modelingRules, Resource connection, IElement edge)
+    throws DatabaseException {
+        Resource connectionType = modelingRules.getConnectionType(graph, connection);
+        if (connectionType != null) {
+            loadLineStyleFromConnectionType(graph, modelingRules, connectionType, edge);
+        }
+    }
+
+    public static void loadLineStyleFromConnectionType(ReadGraph graph, IModelingRules modelingRules, Resource connectionType, IElement edge)
+    throws DatabaseException {
+        edge.setHint(ElementHints.KEY_CONNECTION_TYPE, connectionType);
+        if (DebugPolicy.DEBUG_CONNECTION_VISUALS_LOAD)
+            System.out.println("Connection type : " + NameUtils.getSafeName(graph, connectionType));
+
+        // Load standard visual aspects of the specified edge
+        ConnectionVisuals cv = graph.syncRequest(DiagramRequests.getConnectionVisuals(connectionType));
+
+        if (cv.color != null) {
+            for (FillColor fc : edge.getElementClass().getItemsByClass(FillColor.class)) {
+                fc.setFillColor(edge, cv.toColor());
+            }
+        }
+        for (EdgeVisuals ev : edge.getElementClass().getItemsByClass(EdgeVisuals.class)) {
+            if (cv.stroke != null)
+                ev.setStroke(edge, cv.stroke);
+            if (cv.strokeType != null)
+                ev.setStrokeType(edge, cv.strokeType);
+        }
+    }
+
+    /**
+     * @param graph
+     * @param connectionPart
+     * @return
+     * @throws DatabaseException
+     */
+    public static ConnectionSegmentEnd resolveConnectionSegmentEnd(ReadGraph graph, Resource connectionPart)
+    throws DatabaseException {
+        BasicResources br = BasicResources.getInstance(graph);
+        if (graph.isInstanceOf(connectionPart, br.DIA.BranchPoint))
+            return ConnectionSegmentEnd.BRANCH;
+        if (graph.isInstanceOf(connectionPart, br.DIA.Connector))
+            return ConnectionSegmentEnd.CONNECTOR;
+        return null;
+    }
+
+    /**
+     * @param graph
+     * @param diagram
+     * @param segmentEnd
+     * @param endType
+     * @return
+     * @throws DatabaseException
+     */
+    public static DesignatedTerminal findDesignatedTerminal(ReadGraph graph, IDiagram diagram, Resource segmentEnd, ConnectionSegmentEnd endType)
+    throws DatabaseException {
+        if (DebugPolicy.DEBUG_TERMINAL_SEARCH)
+            System.out.println("findDesignatedTerminal: " + NameUtils.getSafeName(graph, segmentEnd) + " : " + endType);
+
+        BasicResources br = BasicResources.getInstance(graph);
+        DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
+
+        switch (endType) {
+            case CONNECTOR: {
+                List<Terminal> ts = new ArrayList<Terminal>();
+                for (Statement stm : graph.getStatements(segmentEnd, br.STR.Connects)) {
+                    // Ignore the Is Connector Of relation that goes to the
+                    // owner :Connection
+                    if (graph.isSubrelationOf(stm.getPredicate(), br.DIA.IsConnectorOf))
+                        continue;
+
+                    Resource connectionRelation = graph.getInverse(stm.getPredicate());
+                    if (DebugPolicy.DEBUG_TERMINAL_SEARCH)
+                        System.out.println("CONNECTION RELATION: " + NameUtils.getSafeName(graph, connectionRelation));
+                    Resource elementResource = stm.getObject();
+                    if (DebugPolicy.DEBUG_TERMINAL_SEARCH)
+                        System.out.println("ELEMENT RESOURCE: " + NameUtils.getSafeName(graph, elementResource));
+                    IElement e = dem.getElement(diagram, elementResource);
+                    if (e == null) {
+                        return null;
+//                        throw new ValidationException("connector "
+//                                + NameUtils.getSafeName(graph, segmentEnd)
+//                                + " is connected to an entity that has not (yet) been loaded as an IElement: "
+//                                + NameUtils.getSafeName(graph, elementResource));
+                    }
+
+                    TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
+                    ts.clear();
+                    tt.getTerminals(e, ts);
+                    for (Terminal t : ts) {
+                        if (t instanceof ResourceTerminal) {
+                            ResourceTerminal rt = (ResourceTerminal) t;
+                            Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, rt.getResource());
+                            if (DebugPolicy.DEBUG_TERMINAL_SEARCH) {
+                                System.out.println("connection relation: "
+                                        + NameUtils.getSafeName(graph, connectionRelation) + " " + connectionRelation.getResourceId());
+                                System.out.println("  terminal: " + NameUtils.getSafeName(graph, rt.getResource()) + " " + rt.getResource().getResourceId());
+                                System.out.println("  binds:    " + NameUtils.getSafeName(graph, binds) + " " + binds.getResourceId());
+                            }
+                            if (graph.isSubrelationOf(connectionRelation, binds)) {
+                                return new DesignatedTerminal(e, t);
+                            }
+                        }
+                    }
+
+                    throw new ValidationException("connector "
+                            + NameUtils.getSafeName(graph, segmentEnd)
+                            + " is connected using a relation that is not its own: "
+                            + NameUtils.getSafeName(graph, connectionRelation));
+                }
+                // throw new
+                // ValidationException("connector " +
+                // NameUtils.getSafeName(g, segmentEnd) +
+                // " is not connected to anything");
+                return null;
+            }
+            case BRANCH: {
+                List<Terminal> ts = new ArrayList<Terminal>();
+                IElement e = dem.getElement(diagram, segmentEnd);
+                if (e == null) {
+//                    throw new ValidationException("branch point "
+//                            + NameUtils.getSafeName(graph, segmentEnd)
+//                            + " has not (yet) been loaded as an IElement");
+                    return null;
+                }
+
+                TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
+                tt.getTerminals(e, ts);
+                if (ts.size() != 1)
+                    throw new IllegalStateException("branch point element has " + ts.size()
+                            + " terminals, expected 1");
+                return new DesignatedTerminal(e, ts.get(0));
+            }
+            default:
+                throw new IllegalArgumentException("unexpected connection segment end: " + endType);
+        }
+    }
+
+    /**
+     * @param graph
+     * @param diagram
+     * @param terminalStm the statement that goes from the connection
+     *        connector to the node with inverse relation of the terminal
+     *        relation.
+     * @return
+     * @throws DatabaseException
+     */
+    public static DesignatedTerminal getDesignatedTerminalForConnector(ReadGraph graph, IDiagram diagram, Resource elementResource, Resource terminalRelation, Resource connector)
+    throws DatabaseException {
+        if (DebugPolicy.DEBUG_TERMINAL_SEARCH)
+            System.out.println("getDesignatedTerminalForConnector: ("
+                    + NameUtils.getSafeName(graph, elementResource) + ", "
+                    + NameUtils.getSafeName(graph, terminalRelation) + ", "
+                    + NameUtils.getSafeName(graph, connector) + ")"
+                    );
+
+        DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
+        IElement e = dem.getElement(diagram, elementResource);
+        if (e == null)
+            return null;
+
+        TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
+        List<Terminal> ts = new ArrayList<Terminal>();
+        tt.getTerminals(e, ts);
+        for (Terminal t : ts) {
+            if (t instanceof ResourceTerminal) {
+                ResourceTerminal rt = (ResourceTerminal) t;
+                Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, rt.getResource());
+                if (DebugPolicy.DEBUG_TERMINAL_SEARCH) {
+                    System.out.println("connection relation: "
+                            + NameUtils.getSafeName(graph, terminalRelation, true));
+                    System.out.println("  terminal: " + NameUtils.getSafeName(graph, rt.getResource(), true));
+                    System.out.println("  binds:    " + NameUtils.getSafeName(graph, binds, true));
+                }
+                if (graph.isSubrelationOf(terminalRelation, binds)) {
+                    return new DesignatedTerminal(e, t);
+                }
+            }
+        }
+
+        throw new ValidationException("terminal connection statement ("
+                + NameUtils.getSafeName(graph, elementResource) + ", "
+                + NameUtils.getSafeName(graph, terminalRelation) + ", "
+                + NameUtils.getSafeName(graph, connector) + ")"
+                + " is using using a terminal relation that is not its own: "
+                + NameUtils.getSafeName(graph, terminalRelation));
+    }
+
+    /**
+     * @param graph
+     * @return
+     * @throws DatabaseException
+     */
+    public static TerminalMap getElementTerminals(ReadGraph graph, Resource element)
+    throws DatabaseException {
+        DiagramResource DIA = DiagramResource.getInstance(graph);
+        Resource elementType = graph.getPossibleType(element, DIA.Element);
+        return elementType != null ? getElementTypeTerminals(graph, elementType) : TerminalMap.EMPTY;
+    }
+
+    private static final boolean DEBUG_GET_ELEMENT_TYPE_TERMINALS = false;
+
+    /**
+     * @param graph
+     * @param elementType
+     * @return
+     * @throws DatabaseException
+     */
+    public static TerminalMap getElementTypeTerminals(ReadGraph graph, Resource elementType) throws DatabaseException {
+        StructuralResource2 STR = StructuralResource2.getInstance(graph);
+        DiagramResource DIA = DiagramResource.getInstance(graph);
+        if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)
+            System.out.println("getElementTypeTerminals: " + NameUtils.getSafeName(graph, elementType));
+        Resource definedBy = graph.getSingleObject(elementType, STR.IsDefinedBy);
+        Collection<Resource> parts = OrderedSetUtils.toList(graph, definedBy);
+        if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)
+            System.out.println("\tdefining part count: " + parts.size());
+        TerminalMap result = null;
+        for (Resource part : parts) {
+            if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)
+                System.out.println("\t\tpart: " + NameUtils.getSafeName(graph, part));
+            if (graph.isInstanceOf(part, DIA.Terminal)) {
+                Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, part);
+                if (result == null)
+                    result = new TerminalMap(parts.size());
+                if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)
+                    System.out.println("\t\t\tFOUND TERMINAL <-> BINDING RELATION: " + NameUtils.getSafeName(graph, part) + " <-> " + NameUtils.getSafeName(graph, binds));
+                result.put(part, binds);
+            }
+        }
+        return result != null ? result : TerminalMap.EMPTY;
+    }
+
+    /**
+     * Get the value of a specified on/off diagram preference setting (=tag)
+     * where the tag may be stored in:
+     * <ol>
+     * <li>The diagram itself</li>
+     * <li>The model</li>
+     * <li>The project</li>
+     * </ol>
+     * 
+     * @param graph database access
+     * @param diagram the diagram to look for the tag in
+     * @param preference the tag relation of the boolean preference to check for
+     * @return value of the preference
+     * @throws DatabaseException
+     */
+    public static boolean getDiagramTagPreference(ReadGraph graph, Resource diagram, Resource preference) throws DatabaseException {
+        boolean result = graph.hasStatement(diagram, preference);
+        if (!result) {
+            Resource model = graph.sync(new PossibleModel(diagram));
+            if (model != null)
+                result = graph.hasStatement(model, preference);
+            if (!result)
+                result = graph.hasStatement(Simantics.getProjectResource(), preference);
+        }
+        return result;
+    }
+
+    public static void rotateConnection(WriteGraph graph, Resource r, 
+            double cx, double cy, boolean clockwise) throws DatabaseException {
+        DiagramResource DIA = DiagramResource.getInstance(graph);
+        for(Resource node : graph.getObjects(r, DIA.HasInteriorRouteNode))
+            if(graph.isInstanceOf(node, DIA.RouteLine)) {
+                boolean isHorizontal = (Boolean)graph.getRelatedValue(node, DIA.IsHorizontal);
+                double position = (Double)graph.getRelatedValue(node, DIA.HasPosition);
+                
+                if(isHorizontal) {
+                    position -= cy;
+                    if(clockwise)
+                        position = -position;
+                    position += cx;
+                }
+                else {
+                    position -= cx;
+                    if(!clockwise)
+                        position = -position;
+                    position += cy;
+                }
+                isHorizontal = !isHorizontal;                
+                
+                graph.claimLiteral(node, DIA.IsHorizontal, isHorizontal);
+                graph.claimLiteral(node, DIA.HasPosition, position);
+            }
+    }
+
+    public static void flipConnection(WriteGraph graph, Resource r,
+            boolean xAxis, double c) throws DatabaseException {
+        DiagramResource DIA = DiagramResource.getInstance(graph);
+        for(Resource node : graph.getObjects(r, DIA.HasInteriorRouteNode))
+            if(graph.isInstanceOf(node, DIA.RouteLine)) {
+                boolean isHorizontal = (Boolean)graph.getRelatedValue(node, DIA.IsHorizontal);
+
+                if(isHorizontal == xAxis) {
+                    double position = (Double)graph.getRelatedValue(node, DIA.HasPosition);
+                    position = 2*c-position;
+                    graph.claimLiteral(node, DIA.HasPosition, position);
+                }
+            }
+    }
+    
+    /*public static void addConnectionPoint(WriteGraph g, Resource symbol, Resource terminal, 
+            Resource diagramConnectionRelation) throws DatabaseException {
+        Layer0 L0 = Layer0.getInstance(g);
+        StructuralResource2 STR = StructuralResource2.getInstance(g);
+        DiagramResource DIA = DiagramResource.getInstance(g);
+        
+        Resource variable = g.newResource();
+        g.claim(variable, L0.InstanceOf, null, STR.ConnectionVariable);
+        g.claim(terminal, DIA.HasConnectionVariable, variable);
+        g.claim(variable, STR.Binds, diagramConnectionRelation);
+        g.claim(variable, STR.IsParameterOf, symbol);
+    }
+    
+
+    public static Resource getConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
+        return g.getSingleObject(
+                g.getSingleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionVariable),
+                StructuralResource2.getInstance(g).Binds);
+    }
+
+    public static Resource getPossibleConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
+        Resource connectionVariable = g.getPossibleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionVariable);
+        return (connectionVariable == null) ? null : g.getPossibleObject(connectionVariable, StructuralResource2.getInstance(g).Binds);
+    }*/
+    
+    public static void addConnectionPoint(WriteGraph g, Resource symbol, Resource terminal, 
+            Resource diagramConnectionRelation) throws DatabaseException {
+        Layer0 L0 = Layer0.getInstance(g);
+        DiagramResource DIA = DiagramResource.getInstance(g);
+        
+        g.claim(terminal, DIA.HasConnectionPoint, diagramConnectionRelation);
+        g.claim(diagramConnectionRelation, L0.HasDomain, symbol);
+    }
+    
+
+    public static Resource getConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
+        return g.getSingleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionPoint);
+    }
+
+    public static Resource getPossibleConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
+        return g.getPossibleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionPoint);
+    }
+
+    public static Collection<Resource> getTerminals(ReadGraph g, Resource symbol) throws DatabaseException {
+//        Layer0 L0 = Layer0.getInstance(g);
+        StructuralResource2 STR = StructuralResource2.getInstance(g);
+        DiagramResource DIA = DiagramResource.getInstance(g);
+        List<Resource> terminals = null;
+        for (Resource definedBy : g.getObjects(symbol, STR.IsDefinedBy)) {
+            Collection<Resource> elements = g.syncRequest( new OrderedSet(definedBy) );
+            if (terminals == null)
+                terminals = new ArrayList<Resource>( elements.size() );
+            for (Resource element : elements)
+                if (g.isInstanceOf(element, DIA.Terminal))
+                    terminals.add(element);
+        }
+//        Collection<Resource> definedBy = g.getObjects(symbol, STR.IsDefinedBy);
+//        if (!definedBy.isEmpty()) {
+//            Collection<Resource> relations = g.getObjects(symbol, L0.DomainOf);
+//            terminals = new ArrayList<Resource>(relations.size());
+//            for(Resource relation : relations) {
+//                for (Resource element : g.getObjects(relation, DIA.HasConnectionPoint_Inverse)) {
+//                    Collection<Resource> owners = OrderedSetUtils.getOwnerLists(g, element, DIA.Diagram);
+//                    if (!Collections.disjoint(definedBy, owners))
+//                        terminals.add(element);
+//                }
+//            }
+//        }
+        return terminals == null ? Collections.<Resource>emptyList() : terminals;
+    }
+       
+    /**
+     * Determines the connection type of the given diagram connection. Uses the modeling rules
+     * specified in the diagram the connection belongs to.
+     */
+       public static Resource determineConnectionType(ReadGraph graph, Resource diagramConnection) throws DatabaseException {
+               Layer0 L0 = Layer0.getInstance(graph);
+               Resource diagram = graph.getPossibleObject(diagramConnection, L0.PartOf);
+               if (diagram == null)
+                       // Invalid diagram connection resource, not a part of any diagram.
+                       return null;
+               IModelingRules modelingRules = graph.syncRequest(DiagramRequests.getModelingRules(diagram, null));
+               if (modelingRules == null)
+                       return null;
+               return determineConnectionType(graph, diagramConnection, modelingRules);
+       }
+
+       /**
+     * Determines the connection type of the given diagram connection assuming the given modeling rules.
+     */
+       public static Resource determineConnectionType(ReadGraph graph, Resource diagramConnection, IModelingRules modelingRules) throws DatabaseException {
+
+               Set<IConnectionPoint> cps = new THashSet<IConnectionPoint>();
+               DiagramRequests.expandConnections(graph, diagramConnection, new THashSet<Resource>(), cps);
+               return modelingRules.computeConnectionType(graph, cps);
+               
+       }
+       
+       public static void defaultSymbolDropHandler(WriteGraph graph, List<WorkbenchSelectionElement> drop) throws DatabaseException {
+               System.err.println("dropped " + drop);
+       }
+
+    public static IModelingRules getModelingRules(ReadGraph graph, Resource diagram, IModelingRules defaultValue) throws DatabaseException {
+        StructuralResource2 sr = StructuralResource2.getInstance(graph);
+        Resource rules = graph.getPossibleObject(diagram, sr.HasModelingRules);
+        if (rules == null)
+            return defaultValue;
+        return graph.adapt(rules, IModelingRules.class);
+    }
+    
+}