package org.simantics.diagram.synchronization.graph; import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.THashSet; import gnu.trove.set.hash.TIntHashSet; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.util.RelativeReference; import org.simantics.db.service.SerialisationSupport; import org.simantics.diagram.connection.RouteGraph; import org.simantics.diagram.connection.RouteLine; import org.simantics.diagram.connection.RouteLink; import org.simantics.diagram.connection.RouteNode; import org.simantics.diagram.connection.RoutePoint; import org.simantics.diagram.connection.RouteTerminal; import org.simantics.diagram.flag.RouteGraphConnectionSplitter; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.layer0.Layer0; import org.simantics.structural.stubs.StructuralResource2; /** * Encodes modifications to a route graph. * @author Hannu Niemistö */ public class RouteGraphModification { // Identification information int lineCount; int terminalCount; int[] links; // Modification information ArrayList modis = new ArrayList(); // Two different ways to identify Resource[] resources; String[] terminalIdentifiers; // Auxiliary TObjectIntHashMap idMap; Resource connection; public interface Modi { } public static class UpdateLine implements Modi { int id; double position; boolean isHorizontal; public UpdateLine(int id, double position, boolean isHorizontal) { this.id = id; this.position = position; this.isHorizontal = isHorizontal; } public UpdateLine(String text) { String[] parts = text.split("\\$"); this.id = Integer.parseInt(parts[0]); this.position = Double.parseDouble(parts[1]); this.isHorizontal = Boolean.parseBoolean(parts[2]); } @Override public String toString() { return "M" + id + "$" + position + "$" + isHorizontal; } } public static class RemoveLink implements Modi { int a; int b; public RemoveLink(int a, int b) { this.a = a; this.b = b; } public RemoveLink(String text) { String[] parts = text.split("\\$"); this.a = Integer.parseInt(parts[0]); this.b = Integer.parseInt(parts[1]); } @Override public String toString() { return "r" + a + "$" + b; } } public static class RemoveLine implements Modi { int a; public RemoveLine(int a) { this.a = a; } public RemoveLine(String text) { this.a = Integer.parseInt(text); } @Override public String toString() { return "R" + a; } } public static class CreateLink implements Modi { int a; int b; public CreateLink(int a, int b) { this.a = a; this.b = b; } public CreateLink(String text) { String[] parts = text.split("\\$"); this.a = Integer.parseInt(parts[0]); this.b = Integer.parseInt(parts[1]); } @Override public String toString() { return "c" + a + "$" + b; } } public static class CreateLine implements Modi { double position; boolean isHorizontal; public CreateLine(double position, boolean isHorizontal) { this.position = position; this.isHorizontal = isHorizontal; } public CreateLine(String text) { String[] parts = text.split("\\$"); this.position = Double.parseDouble(parts[0]); this.isHorizontal = Boolean.parseBoolean(parts[1]); } @Override public String toString() { return "C" + position + "$" + isHorizontal; } } public static class Split implements Modi { int[] interface1; int[] interface2; int[] lines2; int[] terminals1; int[] terminals2; boolean isHorizontal; double isectX; double isectY; public Split(int[] interface1, int[] interface2, int[] lines2, int[] terminals1, int[] terminals2, boolean isHorizontal, double isectX, double isectY) { this.interface1 = interface1; this.interface2 = interface2; this.lines2 = lines2; this.terminals1 = terminals1; this.terminals2 = terminals2; this.isHorizontal = isHorizontal; this.isectX = isectX; this.isectY = isectY; } public Split(String text) { List parts = Arrays.asList(text.split("\\$")); Iterator it = parts.iterator(); this.interface1 = readInts(it); this.interface2 = readInts(it); this.lines2 = readInts(it); this.terminals1 = readInts(it); this.terminals2 = readInts(it); this.isHorizontal = Boolean.parseBoolean(it.next()); this.isectX = Double.parseDouble(it.next()); this.isectY = Double.parseDouble(it.next()); } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("S"); write(b, interface1); b.append("$"); write(b, interface2); b.append("$"); write(b, lines2); b.append("$"); write(b, terminals1); b.append("$"); write(b, terminals2); b.append("$"); b.append(isHorizontal); b.append("$"); b.append(isectX); b.append("$"); b.append(isectY); return b.toString(); } } private static void write(StringBuilder b, int[] ids) { b.append(ids.length); for(int e : ids) { b.append('$'); b.append(e); } } private static int[] readInts(Iterator it) { int length = Integer.parseInt(it.next()); int[] result = new int[length]; for(int i=0;i lines = rg.getLines(); lineCount = lines.size(); Collection terminals = rg.getTerminals(); terminalCount = terminals.size(); resources = new Resource[lineCount + terminalCount]; THashSet linkSet = new THashSet(); idMap = new TObjectIntHashMap(); int i=0; for(RouteLine line : lines) { idMap.put(line, i); resources[i] = ser.getResource((Long)line.getData()); for(RoutePoint rp : line.getPoints()) { if(rp instanceof RouteLink) { RouteLink link = (RouteLink)rp; if(!link.getA().isTransient() && !link.getA().isTransient()) linkSet.add(link); } } ++i; } for(RouteTerminal terminal : terminals) { idMap.put(terminal, i); resources[i] = ser.getResource((Long)terminal.getData()); ++i; } if(rg.isSimpleConnection()) { links = new int[] {0, 1}; } else { links = new int[2*(terminalCount + linkSet.size())]; i = 0; for(RouteLink link : linkSet) { links[i++] = idMap.get(link.getA()); links[i++] = idMap.get(link.getB()); } for(RouteTerminal terminal : terminals) { links[i++] = idMap.get(terminal); links[i++] = idMap.get(terminal.getLine()); } } } public Resource findTerminalIdentifiers(ReadGraph g) throws DatabaseException { Resource base = null; terminalIdentifiers = new String[terminalCount]; for(int i=0;i> connectorCandidates = new ArrayList>(terminalCount); for(int i=0;i connectors : connectorCandidates) { if(connectors.isEmpty()) return false; if(connection == null && connectors.size() == 1) { for(Resource temp : g.getObjects(connectors.get(0), STR.Connects)) if(g.isInstanceOf(temp, DIA.Connection)) { connection = temp; break; } } } if(connection == null) return false; loop: for(int i=0;i invResources = new TObjectIntHashMap(); for(int i=0;i 0) { connection = g.getSingleObject(resources[0], DIA.HasInteriorRouteNode_Inverse); } else { StructuralResource2 STR = StructuralResource2.getInstance(g); for(Resource temp : g.getObjects(resources[0], STR.Connects)) if(g.isInstanceOf(temp, DIA.Connection)) { connection = temp; break; } } } return connection; } public void runUpdates(WriteGraph g) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(g); Layer0 L0 = Layer0.getInstance(g); for(Modi modi_ : modis) { if(modi_ instanceof UpdateLine) { UpdateLine modi = (UpdateLine)modi_; Resource routeLine = resources[modi.id]; g.claimLiteral(routeLine, DIA.HasPosition, modi.position); g.claimLiteral(routeLine, DIA.IsHorizontal, modi.isHorizontal); } else if(modi_ instanceof RemoveLink) { RemoveLink modi = (RemoveLink)modi_; g.denyStatement(resources[modi.a], DIA.AreConnected, resources[modi.b]); } else if(modi_ instanceof RemoveLine) { RemoveLine modi = (RemoveLine)modi_; g.deny(resources[modi.a]); } else if(modi_ instanceof CreateLink) { CreateLink modi = (CreateLink)modi_; g.claim(resources[modi.a], DIA.AreConnected, resources[modi.b]); } else if(modi_ instanceof CreateLine) { CreateLine modi = (CreateLine)modi_; Resource routeLine = g.newResource(); g.claim(routeLine, L0.InstanceOf, DIA.RouteLine); g.claimLiteral(routeLine, DIA.HasPosition, modi.position); g.claimLiteral(routeLine, DIA.IsHorizontal, modi.isHorizontal); g.claim(getConnection(g), DIA.HasInteriorRouteNode, routeLine); int id = resources.length; resources = Arrays.copyOf(resources, id+1); resources[id] = routeLine; } else if(modi_ instanceof Split) { Split modi = (Split)modi_; RouteGraphConnectionSplitter splitter = new RouteGraphConnectionSplitter(g); splitter.doSplit(g, connection, toResources(modi.interface1), toResources(modi.interface2), toResources(modi.lines2), toResources(modi.terminals1), toResources(modi.terminals2), modi.isHorizontal, modi.isectX, modi.isectY ); } } } public TObjectIntHashMap getIdMap() { return idMap; } public int[] toIds(ArrayList rs) { TObjectIntHashMap rmap = new TObjectIntHashMap(); for(int i=0;i toResources(int[] ids) { ArrayList result = new ArrayList(ids.length); for(int id : ids) result.add(resources[id]); return result; } }