Includes also minor code warning/logging cleanup.
refs #7119
Change-Id: I2df8f0f0707e8adf1569679ab41a74f605ae1268
boolean isSimpleConnection;
boolean needsUpdate = false;
+ public void updateTerminals() {
+ boolean changed = false;
+ for(RouteTerminal terminal : terminals)
+ changed |= terminal.updateDynamicPosition();
+ if(changed) update();
+ }
+
/**
* Adds a route line to the graph.
* @param isHorizontal true, if the line is horizontal
* </pre>
* @param style Tells what kind of line end is drawn
* to the connection.
+ * @param position a provider for a dynamic position for the terminal or
+ * <code>null</code> if terminal position is not dynamic
* @return The new terminal.
*/
+ public RouteTerminal addTerminal(double x, double y,
+ double minX, double minY,
+ double maxX, double maxY,
+ int allowedDirections,
+ ILineEndStyle style, RouteTerminalPosition position) {
+ return addTerminal(x, y, minX, minY, maxX, maxY, allowedDirections, style, null, position);
+ }
+
public RouteTerminal addTerminal(double x, double y,
double minX, double minY,
double maxX, double maxY,
int allowedDirections,
ILineEndStyle style) {
- return addTerminal(x, y, minX, minY, maxX, maxY, allowedDirections, style, null);
-
+ return addTerminal(x, y, minX, minY, maxX, maxY, allowedDirections, style, null, null);
}
+
public RouteTerminal addTerminal(double x, double y,
double minX, double minY,
double maxX, double maxY,
int allowedDirections,
- ILineEndStyle style, ILineEndStyle dynamicStyle) {
+ ILineEndStyle style, ILineEndStyle dynamicStyle, RouteTerminalPosition position) {
if(CHECK_PARAMERS) {
if(allowedDirections > 0x1f)
throw new IllegalArgumentException("Illegal allowedDirection flags.");
if(style == null)
style = PlainLineEndStyle.INSTANCE;
RouteTerminal terminal = new RouteTerminal(x, y, minX, minY,
- maxX, maxY, allowedDirections, false, style);
+ maxX, maxY, allowedDirections, false, style, position);
terminal.setDynamicStyle(dynamicStyle);
terminals.add(terminal);
return terminal;
0.5*(minX+maxX), 0.5*(minY+maxY),
minX, minY,
maxX, maxY,
- 0xf, true, style);
+ 0xf, true, style, null);
terminal.setDynamicStyle(dynamicStyle);
terminals.add(terminal);
ILineEndStyle style) {
return addTerminal(x, y,
bounds.getMinX(), bounds.getMinY(), bounds.getMaxX(), bounds.getMaxY(),
- allowedDirections, style);
+ allowedDirections, style, null);
}
/**
RouteTerminal newTerminal = addTerminal(terminal.x, terminal.y,
terminal.getMinX(), terminal.getMinY(),
terminal.getMaxX(), terminal.getMaxY(),
- terminal.getAllowedDirections(), terminal.getStyle(), terminal.getDynamicStyle());
+ terminal.getAllowedDirections(), terminal.getStyle(), terminal.getDynamicStyle(), terminal.getDynamicPosition());
newTerminal.setData(terminal.getData());
return terminal;
}
double maxX, double maxY,
int allowedDirections) {
return addTerminal(x, y, minX, minY, maxX, maxY, allowedDirections,
- PlainLineEndStyle.INSTANCE);
+ PlainLineEndStyle.INSTANCE, null);
}
/**
import gnu.trove.map.hash.THashMap;
+import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.PrintStream;
import java.io.Serializable;
private ILineEndStyle style;
private ILineEndStyle dynamicStyle;
private boolean routeToBounds;
+ private RouteTerminalPosition dynamicPosition;
RouteLine line;
RouteTerminal(double x, double y, double minX, double minY,
double maxX, double maxY, int allowedDirections,
boolean routeToBounds,
- ILineEndStyle style) {
+ ILineEndStyle style, RouteTerminalPosition dynamicPosition) {
super(x, y);
this.minX = minX;
this.minY = minY;
this.allowedDirections = allowedDirections;
this.routeToBounds = routeToBounds;
this.style = style;
+ this.dynamicPosition = dynamicPosition;
}
-
+
@Override
public void setData(Object data) {
this.data = data;
RouteTerminal copy = (RouteTerminal)map.get(this);
if(copy == null) {
copy = new RouteTerminal(x, y, minX, minY, maxX, maxY,
- allowedDirections, routeToBounds, style);
+ allowedDirections, routeToBounds, style, dynamicPosition);
copy.setDynamicStyle(dynamicStyle);
map.put(this, copy);
copy.data = data;
public void setDynamicStyle(ILineEndStyle dynamicStyle) {
this.dynamicStyle = dynamicStyle;
}
+
+ public RouteTerminalPosition getDynamicPosition() {
+ return dynamicPosition;
+ }
+
+ public boolean updateDynamicPosition() {
+ boolean changed = false;
+ if (dynamicPosition != null) {
+ AffineTransform tr = dynamicPosition.getTransform();
+ if (tr != null) {
+ double nx = tr.getTranslateX();
+ changed |= x != nx;
+ x = nx;
+ double ny = tr.getTranslateY();
+ changed |= y != ny;
+ y = ny;
+ }
+ }
+ return changed;
+ }
+
}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.connection;
+
+import java.awt.geom.AffineTransform;
+
+/**
+ * @author Antti Villberg
+ * @since 1.29.0
+ */
+public interface RouteTerminalPosition {
+
+ public AffineTransform getTransform();
+
+}
DIA.Functions.diagramElementIssuePath : L0.Function
DIA.DefinedElement
- >-- DIA.symbolCode ==> "[String]" <R L0.HasProperty : L0.FunctionalRelation
+ // RequiresValueType ]is omitted during transition period.
+ // Used to be ==> "[String]" but DIA.symbolCode now returns either "[String]" or "[G2DNodeModification]" directly
+ >-- DIA.symbolCode <R L0.HasProperty : L0.FunctionalRelation
>-- DIA.symbolDropHandler ==> "[WorkbenchSelectionElement] -> <WriteGraph,Proc> ()" <R L0.HasProperty : L0.FunctionalRelation
DIA.DiagramActivityCondition <T L0.Entity
import org.simantics.g2d.element.handler.TerminalTopology;
import org.simantics.g2d.element.handler.impl.ObjectTerminal;
import org.simantics.g2d.element.handler.impl.Terminals;
-import org.simantics.scenegraph.INode;
import org.simantics.scenegraph.g2d.IG2DNode;
import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
import org.simantics.scenegraph.utils.NodeUtil;
ObjectTerminal ti = terminalMap.get(t);
if (ti == null)
return null;
- return new AffineTransform(ti.getTransform());
+ return ti.getTransform();
}
}
\ No newline at end of file
import java.awt.geom.AffineTransform;
-import org.simantics.databoard.Bindings;
import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
import org.simantics.db.common.procedure.adapter.AsyncProcedureAdapter;
+import org.simantics.db.exception.DatabaseException;
import org.simantics.db.procedure.AsyncProcedure;
-import org.simantics.diagram.stubs.G2DResource;
+import org.simantics.diagram.stubs.DiagramResource;
import org.simantics.diagram.synchronization.ErrorHandler;
import org.simantics.diagram.synchronization.ISynchronizationContext;
import org.simantics.diagram.synchronization.SynchronizationHints;
import org.simantics.g2d.element.IElement;
import org.simantics.g2d.layers.ILayersEditor;
import org.simantics.utils.datastructures.hints.IHintContext.Key;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class ElementFactoryUtil {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ElementFactoryUtil.class);
+
public static void readTransform(AsyncReadGraph graph, final Resource resource, final IElement e) {
readTransform(graph, resource, e, new AsyncProcedureAdapter<IElement>() {
@Override
public void exception(AsyncReadGraph graph, Throwable t) {
- // Nowhere to log properly.
- t.printStackTrace();
+ LOGGER.error("Error reading transform from " + resource + " into element " + e, t);
}
});
}
public static void readTransform(AsyncReadGraph graph, final Resource resource, final IElement e, final AsyncProcedure<IElement> procedure) {
- G2DResource G2D = graph.getService(G2DResource.class);
- graph.forPossibleRelatedValue(resource, G2D.HasTransform, Bindings.DOUBLE_ARRAY, new AsyncProcedure<double[]>() {
- @Override
- public void exception(AsyncReadGraph graph, Throwable throwable) {
- procedure.exception(graph, throwable);
- }
-
- @Override
- public void execute(AsyncReadGraph graph, double[] mat) {
- mat = DiagramGraphUtil.validateAffineTransform(resource, mat);
- AffineTransform tr = mat != null ? new AffineTransform(mat) : new AffineTransform();
- ElementUtils.setTransform(e, tr);
- procedure.execute(graph, e);
- }
- });
+ DiagramResource DIA = graph.getService(DiagramResource.class);
+ try {
+ AffineTransform tr = DiagramGraphUtil.getDynamicAffineTransform((ReadGraph)graph, null, resource, DIA.HasDynamicTransform, true);
+ ElementUtils.setTransform(e, tr);
+ } catch (DatabaseException e1) {
+ ElementUtils.setTransform(e, new AffineTransform());
+ }
+ procedure.execute(graph, e);
}
public static ISynchronizationContext getContext(IDiagram diagram) {
import org.simantics.g2d.diagram.IDiagram;
import org.simantics.g2d.element.ElementClass;
import org.simantics.g2d.element.IElement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* @author Antti Villberg
*/
public class NodeRequest extends BaseRequest2<Resource, IElement> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NodeRequest.class);
+
final IDiagram diagram;
final Listener<IElement> loadListener;
@Override
public void exception(AsyncReadGraph graph, Throwable throwable) {
- throwable.printStackTrace();
+ LOGGER.error("Unexpected error in GetElementClassRequest", throwable);
procedure.execute(graph, null);
}
@Override
public void exception(AsyncReadGraph graph, Throwable throwable) {
- throwable.printStackTrace();
+ LOGGER.error("Unexpected error in SpawnRequest", throwable);
procedure.execute(graph, null);
}
factory.load(graph, canvas, diagram, data, element, new AsyncProcedure<IElement>() {
@Override
public void exception(AsyncReadGraph graph, Throwable throwable) {
- // TODO: proper logging
- throwable.printStackTrace();
+ LOGGER.error("Unexpected error in ElementFactory.load (factory=" + factory + ")", throwable);
}
@Override
public void execute(AsyncReadGraph graph, IElement result) {
Resource diagramRuntime = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);
Set<BackendConnection> backendConnections = new THashSet<>();
- RouteGraph rg = RouteGraphUtils.load(graph, diagramRuntime, connection, canvas, diagram, modelingRules, backendConnections);
+ RouteGraph rg = RouteGraphUtils.load(graph, diagramRuntime, connection, canvas, diagram, element, modelingRules, backendConnections);
// Load connection line style.
ConnectionStyle style = RouteGraphUtils.readConnectionStyle(graph, modelingRules, connection, STR);
import org.simantics.diagram.connection.RouteLine;
import org.simantics.diagram.connection.RouteNode;
import org.simantics.diagram.connection.RouteTerminal;
+import org.simantics.diagram.connection.RouteTerminalPosition;
import org.simantics.diagram.connection.rendering.BasicConnectionStyle;
import org.simantics.diagram.connection.rendering.ConnectionStyle;
import org.simantics.diagram.connection.rendering.StyledRouteGraphRenderer;
import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
import org.simantics.diagram.connection.rendering.arrows.PlainLineEndStyle;
import org.simantics.diagram.content.EdgeResource;
+import org.simantics.diagram.content.ResourceTerminal;
import org.simantics.diagram.content.TerminalMap;
import org.simantics.diagram.query.DiagramRequests;
import org.simantics.diagram.stubs.DiagramResource;
import org.simantics.g2d.canvas.ICanvasContext;
import org.simantics.g2d.canvas.impl.CanvasContext;
import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.DataElementMap;
import org.simantics.g2d.diagram.handler.Topology.Connection;
+import org.simantics.g2d.diagram.handler.Topology.Terminal;
import org.simantics.g2d.diagram.impl.ElementDiagram;
import org.simantics.g2d.element.ElementUtils;
import org.simantics.g2d.element.IElement;
import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
+import org.simantics.g2d.element.handler.TerminalLayout;
import org.simantics.g2d.elementclass.FlagClass.Type;
import org.simantics.layer0.Layer0;
import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphChangeEvent;
Layer0 L0 = Layer0.getInstance(graph);
Resource diagramResource = graph.getPossibleObject(connection, L0.PartOf);
IModelingRules modelingRules = graph.syncRequest(DiagramRequests.getModelingRules(diagramResource, null), TransientCacheListener.<IModelingRules>instance());
- return load(graph, diagramRuntime, connection, canvas, diagram, modelingRules, null);
+ return load(graph, diagramRuntime, connection, canvas, diagram, null, modelingRules, null);
}
- public static RouteGraph load(ReadGraph graph, Resource diagramRuntime, Resource connection, ICanvasContext canvas, IDiagram diagram, IModelingRules modelingRules, Set<BackendConnection> backendConnections) throws DatabaseException {
+ public static RouteGraph load(ReadGraph graph, Resource diagramRuntime, Resource connection, ICanvasContext canvas, IDiagram diagram, IElement element, IModelingRules modelingRules, Set<BackendConnection> backendConnections) throws DatabaseException {
DiagramResource DIA = DiagramResource.getInstance(graph);
StructuralResource2 STR = StructuralResource2.getInstance(graph);
connectorToModeledAttachment = new THashMap<Resource, Resource>(toConnectorStatements.size());
connectorToModeledAttachment.put(connector, attachment);
if (DEBUG)
- System.out.println("modeling rules decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")");
+ LOGGER.debug("modeling rules decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")");
} else if (graph.isInstanceOf(terminalElement, DIA.Flag)) {
// Secondary: believe flag type
attachment = resolveFlagAttachment(graph, connection, terminalElement, modelingRules, DIA);
connectorToModeledAttachment = new THashMap<Resource, Resource>(toConnectorStatements.size());
connectorToModeledAttachment.put(connector, attachment);
if (DEBUG)
- System.out.println("flag type decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")");
+ LOGGER.debug("flag type decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")");
}
}
}
if (terminalCount == 2 && connectorToModeledAttachment.size() == 1) {
forcedAttachmentRelation = getInverseAttachment(graph, connectorToModeledAttachment.values().iterator().next(), DIA);
if (DEBUG)
- System.out.println("set forced attachment: " + NameUtils.getSafeLabel(graph, forcedAttachmentRelation));
+ LOGGER.debug("set forced attachment: " + NameUtils.getSafeLabel(graph, forcedAttachmentRelation));
}
Resource connectionType = graph.getPossibleObject(connection, STR.HasConnectionType);
+ DataElementMap diagramDataElementMap = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
// Load all node terminal connections as RouteTerminals
for (Statement toConnector : toConnectorStatements) {
Resource connector = toConnector.getObject();
Resource attachmentRelation = toConnector.getPredicate();
if (DEBUG)
- System.out.println("original attachment relation: " + NameUtils.getSafeLabel(graph, attachmentRelation));
+ LOGGER.debug("original attachment relation: " + NameUtils.getSafeLabel(graph, attachmentRelation));
Statement terminalStm = findTerminalStatement(graph, connection, connector, STR);
if (terminalStm == null)
if (position.length != 2)
position = new double[] { 0, 0 };
+ AffineTransform terminalTr = DiagramGraphUtil.getDynamicWorldTransform(graph, diagramRuntime, terminalElement);
+ final AffineTransform terminalElementTransform = new AffineTransform(terminalTr);
+
if (DEBUG) {
- System.out.println("terminalStm: " + NameUtils.toString(graph, terminalStm));
- System.out.println("terminal: " + graph.getURI(terminalStm.getPredicate()));
+ LOGGER.debug("terminalStm: " + NameUtils.toString(graph, terminalStm));
+ LOGGER.debug("terminal: " + NameUtils.getURIOrSafeNameInternal(graph, terminalStm.getPredicate()));
+ LOGGER.debug("terminalElement: " + NameUtils.getURIOrSafeNameInternal(graph, terminalElement) + " : " + NameUtils.getURIOrSafeNameInternal(graph, terminalElementType));
+ LOGGER.debug("terminalElementTr: " + terminalTr);
}
- AffineTransform terminalElementTr = diagramRuntime != null ?
- DiagramGraphUtil.getDynamicWorldTransform(graph, diagramRuntime, terminalElement) :
- DiagramGraphUtil.getWorldTransform(graph, terminalElement);
-
- if (DEBUG)
- System.out.println("terminalElementTr: " + terminalElementTr);
- double x = terminalElementTr.getTranslateX();
- double y = terminalElementTr.getTranslateY();
+ double x = terminalTr.getTranslateX();
+ double y = terminalTr.getTranslateY();
double minx = x-1, miny = y-1, maxx = x+1, maxy = y+1;
int direction = 0x0;
if (att != null) {
attachmentRelation = att;
if (DEBUG)
- System.out.println("modeling rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));
+ LOGGER.debug("modeling rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));
} else if (forcedAttachmentRelation != null) {
attachmentRelation = forcedAttachmentRelation;
if (DEBUG)
- System.out.println("forced rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));
+ LOGGER.debug("forced rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));
}
if (DEBUG)
- System.out.println("decided attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));
+ LOGGER.debug("decided attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));
// Get element bounds to decide allowed terminal direction(s)
IElement te = graph.syncRequest(DiagramRequests.getElement(canvas, diagram, terminalElement, null));
ElementUtils.getElementBounds(te, bounds);
{
- Shape shp = org.simantics.g2d.utils.GeometryUtils.transformShape(bounds, terminalElementTr);
+ Shape shp = org.simantics.g2d.utils.GeometryUtils.transformShape(bounds, terminalTr);
bounds.setFrame(shp.getBounds2D());
}
maxx = bounds.getMaxX();
maxy = bounds.getMaxY();
- AffineTransform terminalPos = DiagramGraphUtil.getDynamicAffineTransform(graph, terminalElement, terminal);
- //AffineTransform terminalPos2 = DiagramGraphUtil.getAffineTransform(graph, terminal);
+ final ResourceTerminal rt = new ResourceTerminal(terminal);
+ final TerminalLayout tl = te.getElementClass().getSingleItem(TerminalLayout.class);
+ AffineTransform terminalPos = tl.getTerminalPosition(element, rt);
+
if (terminalPos != null) {
- if (DEBUG) {
- System.out.println("terminalPos: " + terminalPos);
- //System.out.println("terminalPos2: " + terminalPos2);
- }
- terminalElementTr.concatenate(terminalPos);
+ terminalTr.concatenate(terminalPos);
+ x = terminalTr.getTranslateX();
+ y = terminalTr.getTranslateY();
if (DEBUG)
- System.out.println("terminalElementTr: " + terminalElementTr);
- x = terminalElementTr.getTranslateX();
- y = terminalElementTr.getTranslateY();
+ LOGGER.debug("terminalPos/Tr: " + terminalPos + ", " + terminalTr);
}
Integer allowedDirections = graph.getPossibleRelatedValue(terminal, DIA.Terminal_AllowedDirections, Bindings.INTEGER);
if (allowedDirections != null) {
direction |= allowedDirections;
- direction = rotateDirection(direction, terminalElementTr);
+ direction = rotateDirection(direction, terminalTr);
} else {
direction |= RouteGraphConnectionClass.shortestDirectionOutOfBounds(x, y, bounds);
}
- //System.out.println("DIR(" + x + ", " + y + ", " + bounds + "): " + Integer.toHexString(direction));
+ //LOGGER.debug("DIR(" + x + ", " + y + ", " + bounds + "): " + Integer.toHexString(direction));
if (backendConnections != null) {
backendConnections.add(
// FIXME: routegraph crashes if this is done for all terminals regardless of the amount of terminals.
if (DEBUG)
- System.out.println("load line style: " + NameUtils.getSafeLabel(graph, attachmentRelation));
+ LOGGER.debug("load line style: " + NameUtils.getSafeLabel(graph, attachmentRelation));
ILineEndStyle endStyle = loadLineEndStyle(graph, attachmentRelation, connectionType, TAIL);
- RouteTerminal routeTerminal = rg.addTerminal(x, y, minx, miny, maxx, maxy, direction, endStyle);
+ RouteTerminal routeTerminal = rg.addTerminal(x, y, minx, miny, maxx, maxy, direction, endStyle,
+ new RouteTerminalPositionImpl(diagram, diagramDataElementMap, terminalElement, terminalElementTransform, tl, rt));
routeTerminal.setData( RouteGraphConnection.serialize(graph, connector) );
nodeByData.put( connector, routeTerminal );
}
}
+ private static class RouteTerminalPositionImpl implements RouteTerminalPosition {
+
+ private IDiagram diagram;
+ private DataElementMap dataElementMap;
+ private Resource element;
+ private AffineTransform elementTransform;
+ private TerminalLayout terminalLayout;
+ private Terminal elementTerminal;
+
+ private transient AffineTransform lastTerminalTr;
+ private transient AffineTransform transform;
+
+ public RouteTerminalPositionImpl(IDiagram diagram, DataElementMap dem, Resource element, AffineTransform elementTransform, TerminalLayout terminalLayout, Terminal terminal) {
+ this.diagram = diagram;
+ this.dataElementMap = dem;
+ this.element = element;
+ this.elementTransform = elementTransform;
+ this.terminalLayout = terminalLayout;
+ this.elementTerminal = terminal;
+ }
+
+ @Override
+ public AffineTransform getTransform() {
+ IElement actualElement = dataElementMap.getElement(diagram, element);
+ AffineTransform terminalTr = actualElement != null ? terminalLayout.getTerminalPosition(actualElement, elementTerminal) : null;
+ if (terminalTr == null)
+ return elementTransform;
+
+ // Return cached transform if terminal transform has not changed.
+ AffineTransform result = this.transform;
+ AffineTransform lastTerminalTr = this.lastTerminalTr;
+ if (lastTerminalTr != null) {
+ if (terminalTr.equals(lastTerminalTr))
+ return result;
+ lastTerminalTr.setTransform(terminalTr);
+ } else {
+ lastTerminalTr = this.lastTerminalTr = new AffineTransform(terminalTr);
+ result = this.transform = new AffineTransform();
+ }
+
+ result.setTransform(elementTransform);
+ result.concatenate(terminalTr);
+ return result;
+ }
+
+ }
}
import org.simantics.db.Resource;
import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
import org.simantics.db.common.procedure.guarded.GuardedAsyncProcedureWrapper;
-import org.simantics.db.common.request.BinaryAsyncRead;
import org.simantics.db.common.request.ReadRequest;
import org.simantics.db.common.request.UnaryAsyncRead;
import org.simantics.db.common.utils.NameUtils;
import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;
import org.simantics.scenegraph.utils.GeometryUtils;
import org.simantics.structural2.modelingRules.ConnectionJudgement;
-import org.simantics.utils.datastructures.Callback;
import org.simantics.utils.datastructures.Pair;
import org.simantics.utils.datastructures.Triple;
import org.simantics.utils.logging.TimeLogger;
Resource attachToLine = RouteGraphConnection.deserialize(graph, attachedToRouteLine.getData());
builder.attachToRouteGraph(graph, judgment, connection, attachToLine, controlPoints, endTerminal, FlagClass.Type.Out);
}
- }, new Callback<DatabaseException>() {
- @Override
- public void run(DatabaseException parameter) {
- if (parameter != null)
- ExceptionUtils.logAndShowError(parameter);
- }
+ }, e -> {
+ if (e != null)
+ ExceptionUtils.logAndShowError(e);
});
}
private static final ThreadLocal<ArrayList<Terminal>> TERMINALS = new ThreadLocal<ArrayList<Terminal>>() {
@Override
protected ArrayList<Terminal> initialValue() {
- return new ArrayList<Terminal>();
+ return new ArrayList<>();
}
};
private static final ThreadLocal<ArrayList<IElement>> ELEMENTS = new ThreadLocal<ArrayList<IElement>>() {
@Override
protected ArrayList<IElement> initialValue() {
- return new ArrayList<IElement>();
+ return new ArrayList<>();
}
};
pickCenterY = bounds.getCenterY();
}
- List<TerminalInfo> result = new ArrayList<TerminalInfo>();
+ List<TerminalInfo> result = new ArrayList<>();
ArrayList<Terminal> terminals = TERMINALS.get();
for (IElement e : elements)
{
{
Shape terminalShape = getTerminalShape(tls, e, t);
if ( terminalShape==null /* point terminal */ && !pickPointTerminals ) continue;
- if ( terminalShape!=null /* are terminal */ && !pickAreaTerminals ) continue;
- AffineTransform terminalToDiagram = getTerminalPosOnDiagram(e, t);
+ if ( terminalShape!=null /* area terminal */ && !pickAreaTerminals ) continue;
+
+ AffineTransform terminalToElement = getTerminalPosOnElement0(e, t);
+ AffineTransform terminalToDiagram = concatenate(ElementUtils.getTransform(e), terminalToElement);
// Pick distance will is set to 0 if there was no pick shape,
// i.e. everything is picked.
pickDist = Point2D.distance(pickCenterX, pickCenterY, terminalToDiagram.getTranslateX(), terminalToDiagram.getTranslateY());
}
- AffineTransform terminalToElement = getTerminalPosOnElement(e, t);
TerminalInfo ti = new TerminalInfo();
ti.e = e;
ti.posDia = terminalToDiagram;
- ti.posElem = terminalToElement;
+ ti.posElem = terminalToElement != null ? new AffineTransform(terminalToElement) : new AffineTransform();
ti.t = t;
ti.shape = terminalShape;
ti.distance = pickDist;
tt.getTerminals(e, terminals);
for (Terminal t : terminals)
{
+ AffineTransform terminalToElement = getTerminalPosOnElement0(e, t);
+ AffineTransform terminalToDiagram = concatenate(ElementUtils.getTransform(e), terminalToElement);
+
Shape terminalShape = getTerminalShape(e, t);
- AffineTransform terminalToDiagram = getTerminalPosOnDiagram(e, t);
Shape pickTargetShape = terminalShape != null ? terminalShape : POINT_PICK_SHAPE;
pickTargetShape = GeometryUtils.transformShape(pickTargetShape, terminalToDiagram);
if (!GeometryUtils.intersects(pickShape, pickTargetShape)) continue;
result.e = e;
result.posDia = terminalToDiagram;
- result.posElem = getTerminalPosOnElement(e, t);
+ result.posElem = terminalToElement != null ? new AffineTransform(terminalToElement) : new AffineTransform();
result.t = t;
result.shape = terminalShape;
result.distance = Math.sqrt(pickDist);
*/
public static AffineTransform getTerminalPosOnDiagram(IElement e, Terminal t)
{
- AffineTransform pos = getTerminalPosOnElement(e, t);
- AffineTransform at = ElementUtils.getTransform(e);
- AffineTransform result = new AffineTransform(at);
- result.concatenate(pos);
- return result;
+ AffineTransform pos = getTerminalPosOnElement0(e, t);
+ return concatenate(ElementUtils.getTransform(e), pos);
}
/**
* @return Transform of a terminal
*/
public static AffineTransform getTerminalPosOnElement(IElement e, Terminal t)
+ {
+ AffineTransform tr = getTerminalPosOnElement0(e, t);
+ return tr != null ? new AffineTransform(tr) : null;
+ }
+
+ /**
+ * Get position of a terminal in element
+ * @param e element
+ * @param t terminal
+ * @return Transform of a terminal
+ */
+ private static AffineTransform getTerminalPosOnElement0(IElement e, Terminal t)
{
List<TerminalLayout> tls = e.getElementClass().getItemsByClass(TerminalLayout.class);
AffineTransform result = null;
PickRequest req = new PickRequest(pickShape);
DiagramUtils.pick(diagram, req, elements);
- ArrayList<Bend> bends = new ArrayList<Bend>();
+ ArrayList<Bend> bends = new ArrayList<>();
Point2D bendPos = new Point2D.Double();
for (IElement e : diagram.getElements())
{
}
}
- ArrayList<TerminalInfo> result = new ArrayList<TerminalInfo>(len);
+ ArrayList<TerminalInfo> result = new ArrayList<>(len);
for (int i = 0; i < len; ++i) {
TerminalInfo ti = tis.get(i);
if (ti.distance == nearest.distance
return result;
}
+ private static AffineTransform concatenate(AffineTransform a, AffineTransform b) {
+ AffineTransform result = new AffineTransform(a);
+ if (b != null)
+ result.concatenate(b);
+ return result;
+ }
+
}
public interface TerminalLayout extends ElementHandler {
/**
- * Get a copy of terminal transformation (on element)
+ * Get specified terminal transformation on specified element
+ *
* @param node
* @param t
- * @return position of a terminal or null
+ * @return position of a terminal or null if specified terminal does not
+ * belong to the specified element. The returned AffineTransform
+ * must be treated as if it were immutable since the implementation
+ * is allowed to returned singleton/cached values.
*/
AffineTransform getTerminalPosition(IElement node, Terminal t);
ObjectTerminal ti = terminalMap.get(t);
if (ti == null)
return null;
- return new AffineTransform(ti.getTransform());
+ return ti.getTransform();
}
@Override
provider = getICanvasSceneGraphProvider model composite diagramRVI
context = getCanvasContext provider
getCount context
+
+importJava "org.simantics.scenegraph.g2d.G2DNodeModification" where
+ data G2DNodeModification
+ @JavaName "<init>"
+ createG2DNodeModification :: [SVGNodeAssignment] -> [TransformationAssignment] -> G2DNodeModification
+
+importJava "org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment" where
+ data SVGNodeAssignment
+
+importJava "org.simantics.scenegraph.g2d.nodes.TransformationAssignment" where
+ data TransformationAssignment
+ @JavaName "<init>"
+ createTransformationAssignment :: a -> AffineTransform -> TransformationAssignment
+
+importJava "java.awt.geom.AffineTransform" where
+ data AffineTransform
+ @JavaName "<init>"
+ createAffineTransform :: Double -> Double -> Double -> Double -> Double -> Double -> AffineTransform
+
+importJava "org.simantics.scenegraph.g2d.AffineTransformFunctions" where
+ transform :: AffineTransform -> (Double,Double) -> (Double,Double)
+ inverseTransform :: AffineTransform -> (Double,Double) -> (Double,Double)
+
\ No newline at end of file
*******************************************************************************/
package org.simantics.modeling.adapters;
+import java.awt.geom.AffineTransform;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
import org.simantics.diagram.profile.StyleBase;
import org.simantics.diagram.stubs.DiagramResource;
import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.g2d.G2DNodeModification;
+import org.simantics.scenegraph.g2d.IG2DNode;
import org.simantics.scenegraph.g2d.nodes.SVGNode;
-import org.simantics.scenegraph.g2d.nodes.SVGNode.SVGNodeAssignment;
+import org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment;
+import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
+import org.simantics.scenegraph.g2d.nodes.TransformationAssignment;
import org.simantics.scenegraph.profile.EvaluationContext;
import org.simantics.scenegraph.utils.NodeUtil;
import org.simantics.utils.datastructures.Pair;
* @author Antti Villberg
* @since 1.29.0
*/
-public class SymbolCodeStyle extends StyleBase<Pair<List<String>, Object>> {
+public class SymbolCodeStyle extends StyleBase<Pair<G2DNodeModification, Object>> {
@Override
- public Pair<List<String>, Object> calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {
+ public Pair<G2DNodeModification, Object> calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {
DiagramResource DIA = DiagramResource.getInstance(graph);
// Find a component for the element
Variable elementVariable = Variables.getPossibleVariable(graph, element);
if (elementVariable == null)
return null;
- List<String> styles = elementVariable.getPossiblePropertyValue(graph, DIA.symbolCode);
- if (styles == null)
+ Object modi = elementVariable.getPossiblePropertyValue(graph, DIA.symbolCode);
+ if (modi == null)
return null;
// If element is moved, recalculate style
Object transform = graph.getPossibleRelatedValue(element, DIA.HasTransform);
- return Pair.make(styles, transform);
+ if (modi instanceof G2DNodeModification) {
+ return Pair.make((G2DNodeModification)modi, transform);
+ } else if (modi instanceof List) {
+ @SuppressWarnings("unchecked")
+ List<String> styles = (List<String>)modi;
+ List<SVGNodeAssignment> assignments = new ArrayList<>(styles.size()/3);
+ for (int i = 0; i < styles.size()/3; i++)
+ assignments.add(new SVGNodeAssignment(styles.get(3*i), styles.get(3*i+1), styles.get(3*i+2)));
+ return Pair.make(new G2DNodeModification(assignments, Collections.emptyList()), transform);
+ } else {
+ throw new DatabaseException("Invalid symbolCode value: " + modi);
+ }
}
@Override
- public void applyStyleForNode(EvaluationContext evaluationContext, INode node, Pair<List<String>, Object> result) {
- if (result == null || result.first == null || result.first.isEmpty())
+ public void applyStyleForNode(EvaluationContext evaluationContext, INode node, Pair<G2DNodeModification, Object> result) {
+ if (result == null || result.first == null)
return;
- List<String> styles = result.first;
- List<SVGNodeAssignment> assignments = new ArrayList<>(styles.size()/3);
- for (int i = 0; i < styles.size()/3; i++)
- assignments.add(new SVGNodeAssignment(styles.get(3*i), styles.get(3*i+1), styles.get(3*i+2)));
-
- for (SVGNode p : NodeUtil.collectNodes(node, SVGNode.class)) {
- p.setAssignments(assignments);
- p.cleanDiagramCache();
+ G2DNodeModification modification = result.first;
+ if (modification.svgAssignments != null && !modification.svgAssignments.isEmpty()) {
+ for (SVGNode p : NodeUtil.collectNodes(node, SVGNode.class)) {
+ p.setAssignments(modification.svgAssignments);
+ p.cleanDiagramCache();
+ }
+ }
+ if (modification.transformAssignments != null) {
+ Map<Object,AffineTransform> trs = new HashMap<>();
+ for (TransformationAssignment ass : modification.transformAssignments)
+ trs.put(ass.key, ass.transform);
+ NodeUtil.forChildrenDeep(node, SingleElementNode.class, n -> {
+ Object key = n.getKey();
+ AffineTransform tr = trs.get(key);
+ if (tr != null) {
+ IG2DNode[] children = n.getSortedNodes();
+ if (children.length > 0)
+ children[0].setTransform(tr);
+ }
+ return null;
+ });
}
}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.scenegraph.g2d;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Point2D;
+
+import org.simantics.scl.runtime.tuple.Tuple2;
+
+/**
+ * @author Antti Villberg
+ * @since 1.29.0
+ */
+public class AffineTransformFunctions {
+
+ public static Tuple2 transform(AffineTransform transform, Tuple2 point) {
+ Point2D result = new Point2D.Double((Double) point.c0, (Double) point.c1);
+ transform.transform(result, result);
+ return new Tuple2(result.getX(), result.getY());
+ }
+
+ public static Tuple2 inverseTransform(AffineTransform transform, Tuple2 point) throws NoninvertibleTransformException {
+ Point2D result = new Point2D.Double((Double)point.c0, (Double)point.c1);
+ transform.inverseTransform(result, result);
+ return new Tuple2(result.getX(), result.getY());
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.scenegraph.g2d;
+
+import java.util.List;
+
+import org.simantics.scenegraph.g2d.nodes.SVGNodeAssignment;
+import org.simantics.scenegraph.g2d.nodes.TransformationAssignment;
+
+/**
+ * @author Antti Villberg
+ * @since 1.29.0
+ */
+public class G2DNodeModification {
+ public List<SVGNodeAssignment> svgAssignments;
+ public List<TransformationAssignment> transformAssignments;
+ public G2DNodeModification(List<SVGNodeAssignment> svgAssignments, List<TransformationAssignment> transformAssignments) {
+ this.svgAssignments = svgAssignments;
+ this.transformAssignments = transformAssignments;
+ }
+}
@RasterOutputWidget
public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode {
- public static class SVGNodeAssignment {
- public String elementId;
- public String attributeNameOrId;
- public String value;
- public SVGNodeAssignment(String elementId, String attributeNameOrId, String value) {
- this.elementId = elementId;
- this.attributeNameOrId = attributeNameOrId;
- this.value = value;
- }
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((attributeNameOrId == null) ? 0 : attributeNameOrId.hashCode());
- result = prime * result + ((elementId == null) ? 0 : elementId.hashCode());
- result = prime * result + ((value == null) ? 0 : value.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- SVGNodeAssignment other = (SVGNodeAssignment) obj;
- if (attributeNameOrId == null) {
- if (other.attributeNameOrId != null)
- return false;
- } else if (!attributeNameOrId.equals(other.attributeNameOrId))
- return false;
- if (elementId == null) {
- if (other.elementId != null)
- return false;
- } else if (!elementId.equals(other.elementId))
- return false;
- if (value == null) {
- if (other.value != null)
- return false;
- } else if (!value.equals(other.value))
- return false;
- return true;
- }
- }
-
- private static final long serialVersionUID = 8508750881358776559L;
+ private static final long serialVersionUID = 8508750881358776559L;
protected String data = null;
protected String defaultData = null;
--- /dev/null
+package org.simantics.scenegraph.g2d.nodes;
+
+/**
+ * @author Antti Villberg
+ * @since 1.29.0
+ */
+public class SVGNodeAssignment {
+ public String elementId;
+ public String attributeNameOrId;
+ public String value;
+ public SVGNodeAssignment(String elementId, String attributeNameOrId, String value) {
+ this.elementId = elementId;
+ this.attributeNameOrId = attributeNameOrId;
+ this.value = value;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((attributeNameOrId == null) ? 0 : attributeNameOrId.hashCode());
+ result = prime * result + ((elementId == null) ? 0 : elementId.hashCode());
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SVGNodeAssignment other = (SVGNodeAssignment) obj;
+ if (attributeNameOrId == null) {
+ if (other.attributeNameOrId != null)
+ return false;
+ } else if (!attributeNameOrId.equals(other.attributeNameOrId))
+ return false;
+ if (elementId == null) {
+ if (other.elementId != null)
+ return false;
+ } else if (!elementId.equals(other.elementId))
+ return false;
+ if (value == null) {
+ if (other.value != null)
+ return false;
+ } else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.scenegraph.g2d.nodes;
+
+import java.awt.geom.AffineTransform;
+
+/**
+ * @author Antti Villberg
+ * @since 1.29.0
+ */
+public class TransformationAssignment {
+ public Object key;
+ public AffineTransform transform;
+ public TransformationAssignment(Object key, AffineTransform transform) {
+ this.key = key;
+ this.transform = transform;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((key == null) ? 0 : key.hashCode());
+ result = prime * result + ((transform == null) ? 0 : transform.hashCode());
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TransformationAssignment other = (TransformationAssignment) obj;
+ if (key == null) {
+ if (other.key != null)
+ return false;
+ } else if (!key.equals(other.key))
+ return false;
+ if (transform == null) {
+ if (other.transform != null)
+ return false;
+ } else if (!transform.equals(other.transform))
+ return false;
+ return true;
+ }
+}
\ No newline at end of file
boolean selected = NodeUtil.isSelected(this, 1);
+ rg.updateTerminals();
+
if (currentAction != null) {
currentAction.render(g, renderer, mouseX, mouseY);
} else {