1 package org.simantics.plant3d.utils;
3 import java.util.ArrayList;
4 import java.util.HashMap;
8 import javax.vecmath.Point3d;
9 import javax.vecmath.Vector3d;
11 import org.simantics.Simantics;
12 import org.simantics.db.ReadGraph;
13 import org.simantics.db.Resource;
14 import org.simantics.db.common.request.ReadRequest;
15 import org.simantics.db.common.utils.NameUtils;
16 import org.simantics.db.exception.DatabaseException;
17 import org.simantics.g3d.math.MathTools;
18 import org.simantics.g3d.scenegraph.GeometryProvider;
19 import org.simantics.layer0.Layer0;
20 import org.simantics.plant3d.ontology.Plant3D;
21 import org.simantics.plant3d.scenegraph.EndComponent;
22 import org.simantics.plant3d.scenegraph.Equipment;
23 import org.simantics.plant3d.scenegraph.InlineComponent;
24 import org.simantics.plant3d.scenegraph.Nozzle;
25 import org.simantics.plant3d.scenegraph.P3DRootNode;
26 import org.simantics.plant3d.scenegraph.PipeRun;
27 import org.simantics.plant3d.scenegraph.PipelineComponent;
28 import org.simantics.plant3d.scenegraph.TurnComponent;
29 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
30 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
31 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
32 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
34 public class ComponentUtils {
37 private static Map<String,Class<? extends PipelineComponent>> clazzes = new HashMap<String, Class<? extends PipelineComponent>>();
38 private static Map<String,GeometryProvider> providers = new HashMap<String,GeometryProvider>();
39 private static Map<String,String> names = new HashMap<String,String>();
41 public static void preloadCache() {
42 Simantics.getSession().asyncRequest(new ReadRequest() {
45 public void run(ReadGraph graph) throws DatabaseException {
46 List<String> types = new ArrayList<String>();
47 types.add(Plant3D.URIs.Builtin_Straight);
48 types.add(Plant3D.URIs.Builtin_Elbow);
49 types.add(Plant3D.URIs.Builtin_ConcentricReducer);
50 types.add(Plant3D.URIs.Builtin_BranchSplitComponent);
51 types.add(Plant3D.URIs.Builtin_EccentricReducer);
53 for (String typeURI : types) {
60 private static GeometryProvider getProvider(ReadGraph graph, Resource type) throws DatabaseException {
62 Layer0 l0 = Layer0.getInstance(graph);
63 Plant3D p3d = Plant3D.getInstance(graph);
64 Resource geom = graph.getPossibleObject(type,p3d.hasGeometry);
66 for (Resource a : graph.getObjects(type, l0.Asserts)) {
67 if (p3d.hasGeometry.equals(graph.getPossibleObject(a, l0.HasPredicate))) {
68 geom = graph.getPossibleObject(a, l0.HasObject);
74 GeometryProvider provider = graph.adapt(geom, GeometryProvider.class);
80 private static Class<? extends PipelineComponent> getClazz(ReadGraph graph, Resource type) throws DatabaseException {
81 Plant3D p3d = Plant3D.getInstance(graph);
82 if (graph.isInheritedFrom(type, p3d.InlineComponent))
83 return InlineComponent.class;
84 if (graph.isInheritedFrom(type, p3d.TurnComponent))
85 return TurnComponent.class;
86 if (graph.isInheritedFrom(type, p3d.EndComponent))
87 return EndComponent.class;
88 if (graph.isInheritedFrom(type, p3d.Nozzle))
93 private static void load(ReadGraph graph, String typeURI) throws DatabaseException {
94 Plant3D p3d = Plant3D.getInstance(graph);
95 Resource type = graph.getResource(typeURI);
97 GeometryProvider provider = getProvider(graph, type);
98 if (provider != null || graph.hasStatement(type,p3d.NonVisibleComponent)) {
99 providers.put(typeURI, provider);
100 if (graph.isInheritedFrom(type, p3d.PipelineComponent))
101 clazzes.put(typeURI,getClazz(graph, type));
102 names.put(typeURI, NameUtils.getSafeName(graph, type));
105 throw new DatabaseException("Cannot find component for " + typeURI);
108 private static void load(final String typeURI) throws DatabaseException {
109 Simantics.getSession().syncRequest(new ReadRequest() {
112 public void run(ReadGraph graph) throws DatabaseException {
119 * Creates a component
121 * Does not set the name or add the component to a piperun.
127 public static PipelineComponent createComponent(P3DRootNode root, String typeURI) throws Exception {
128 Class<? extends PipelineComponent> type = clazzes.get(typeURI);
129 GeometryProvider provider = providers.get(typeURI);
130 if (type == null || provider == null) {
132 type = clazzes.get(typeURI);
133 provider = providers.get(typeURI);
135 //PipelineComponent component = type.newInstance();
136 PipelineComponent component = null;
137 if (type == InlineComponent.class) {
138 component = root.createInline();
139 } else if (type == TurnComponent.class) {
140 component = root.createTurn();
141 } else if (type == EndComponent.class) {
142 component = root.createTurn();
143 } else if (type == Nozzle.class) {
144 component = root.createNozzle();
146 component.setType(typeURI);
147 component.setGeometry(provider);
152 * Creates a equipment
154 * Does not set the name
162 public static Equipment createEquipment(P3DRootNode root, String typeURI) throws Exception {
163 GeometryProvider provider = providers.get(typeURI);
164 if (provider == null) {
166 provider = providers.get(typeURI);
168 Equipment equipment = root.createEquipment();
169 equipment.setType(typeURI);
170 equipment.setGeometry(provider);
171 root.addChild(equipment);
175 public static InlineComponent createStraight(P3DRootNode root) throws Exception{
176 InlineComponent component = root.createInline();
177 component.setType(Plant3D.URIs.Builtin_Straight);
178 component.setGeometry(providers.get(Plant3D.URIs.Builtin_Straight));
182 public static TurnComponent createTurn(P3DRootNode root) throws Exception {
183 TurnComponent elbow = root.createTurn();
184 elbow.setType(Plant3D.URIs.Builtin_Elbow);
185 elbow.setGeometry(providers.get(Plant3D.URIs.Builtin_Elbow));
189 public static InlineComponent createReducer(P3DRootNode root) throws Exception {
190 InlineComponent component = root.createInline();
191 component.setType(Plant3D.URIs.Builtin_ConcentricReducer);
192 component.setGeometry(providers.get(Plant3D.URIs.Builtin_ConcentricReducer));
196 public static InlineComponent createBranchSplit(P3DRootNode root) throws Exception {
197 InlineComponent component = root.createInline();
198 component.setType(Plant3D.URIs.Builtin_BranchSplitComponent);
202 public static Equipment createEquipment(P3DRootNode root, Item equipmentType) throws Exception {
203 Equipment equipment = createEquipment(root, equipmentType.getUri());
204 String n = root.getUniqueName(equipmentType.getName());
205 equipment.setName(n);
206 root.addChild(equipment);
212 public static Nozzle createDefaultNozzle(P3DRootNode root, Equipment equipment) throws Exception {
213 return createNozzle(root, equipment, new Item(Plant3D.URIs.Builtin_Nozzle, "Nozzle"));
216 public static Nozzle createNozzle(P3DRootNode root, Equipment equipment, Item nozzleType) throws Exception {
217 Nozzle nozzle = root.createNozzle();
218 nozzle.setType(nozzleType.getUri());
219 String n = root.getUniqueName(nozzleType.getName());
221 PipeRun pipeRun = new PipeRun();
222 n = root.getUniqueName("PipeRun");
224 nozzle.setPipeRun(pipeRun);
226 equipment.addChild(nozzle);
227 root.addChild(pipeRun);
228 // root.getNodeMap().commit("Add nozzle " + n);
232 public static class InsertInstruction {
233 public String typeUri;
235 public PositionType position = PositionType.NEXT;
236 public PositionType insertPosition = PositionType.NEXT;
238 // Reducer requires pipe specs
239 public Double diameter;
240 public Double turnRadius;
243 public Double length;
248 public String getTypeUri() {
252 public void setTypeUri(String typeUri) {
253 this.typeUri = typeUri;
256 public PositionType getPosition() {
260 public void setPosition(PositionType position) {
261 this.position = position;
264 public PositionType getInsertPosition() {
265 return insertPosition;
268 public void setInsertPosition(PositionType insertPosition) {
269 this.insertPosition = insertPosition;
272 public Double getDiameter() {
276 public void setDiameter(Double diameter) {
277 this.diameter = diameter;
280 public Double getTurnRadius() {
284 public void setTurnRadius(Double turnRadius) {
285 this.turnRadius = turnRadius;
288 public Double getLength() {
292 public void setLength(Double length) {
293 this.length = length;
296 public Double getAngle() {
300 public void setAngle(Double angle) {
306 public static PipelineComponent addComponent(P3DRootNode root, PipelineComponent component, InsertInstruction inst) throws Exception {
308 PipelineComponent newComponent = ComponentUtils.createComponent(root, inst.typeUri);
309 PipeControlPoint newPcp = newComponent.getControlPoint();
311 PipeControlPoint toPcp = component.getControlPoint();
312 PipeRun pipeRun = toPcp.getPipeRun();
314 String typeName = names.get(inst.typeUri);
315 if (typeName == null)
316 typeName = "Component";
321 PositionType position = inst.position;
322 PositionType insertPosition = inst.insertPosition;
323 boolean lengthAdjustable = false;
324 if (newComponent instanceof InlineComponent) {
325 lengthAdjustable = ((InlineComponent)newComponent).isVariableLength();
327 boolean insertAdjustable = false;
328 if (component instanceof InlineComponent) {
329 insertAdjustable = ((InlineComponent)component).isVariableLength();
331 boolean sizeChange = false;
332 if (newComponent instanceof InlineComponent) {
333 sizeChange = ((InlineComponent)newComponent).isSizeChange();
336 if (toPcp.isInline()) {
339 if (toPcp.isDualInline()) {
340 toPcp = toPcp.getSubPoint().get(0);
341 pipeRun = toPcp.getPipeRun();
346 if (toPcp.isDualSub()) {
347 toPcp = toPcp.parent;
348 pipeRun = toPcp.getPipeRun();
352 Vector3d start = new Vector3d();
353 Vector3d end = new Vector3d();
354 dir = new Vector3d();
355 toPcp.getInlineControlPointEnds(start, end, dir);
359 pos = new Vector3d(end);
362 pos = new Vector3d(start);
365 pos = new Vector3d(toPcp.getWorldPosition());
369 } else if (toPcp.isDirected()) {
370 dir = new Vector3d(toPcp.getDirection(Direction.NEXT));
371 pos = new Vector3d(toPcp.getWorldPosition());
372 } else if (toPcp.isTurn() && toPcp.isFixed()) {
373 dir = new Vector3d(toPcp.getDirection(position == PositionType.NEXT ? Direction.NEXT : Direction.PREVIOUS));
374 pos = new Vector3d(toPcp.getWorldPosition());
375 if (!lengthAdjustable) {
376 Vector3d v = new Vector3d(dir);
377 v.scale(toPcp.getInlineLength());
380 if (insertPosition == PositionType.NEXT) {
381 Vector3d v = new Vector3d(dir);
382 v.scale(toPcp.getInlineLength());
384 } else if (insertPosition == PositionType.SPLIT) {
385 // scale 0.5*length so that we don't remove the length twice from the new component
386 Vector3d v = new Vector3d(dir);
387 v.scale(toPcp.getInlineLength()*0.5);
395 String name = component.getPipeRun().getUniqueName(typeName);
396 newComponent.setName(name);
398 pipeRun.addChild(newComponent);
399 // TODO: these options are not stored into DB. Should they?!
400 if (newComponent instanceof InlineComponent && ((InlineComponent)newComponent).isVariableLength()) {
401 newPcp.setLength(inst.length);
402 } else if (newComponent instanceof TurnComponent && ((TurnComponent)newComponent).isVariableAngle()) {
403 newPcp.setTurnAngle(inst.angle);
406 newComponent.updateParameters();
408 Vector3d v = new Vector3d(dir);
409 if (insertAdjustable) {
410 if (insertPosition == PositionType.NEXT)
411 v.scale(newComponent.getControlPoint().getInlineLength());
412 else if (insertPosition == PositionType.SPLIT)
414 else if (insertPosition == PositionType.PREVIOUS)
415 v.scale(-newComponent.getControlPoint().getInlineLength());
417 v.scale(newComponent.getControlPoint().getInlineLength());
432 if (toPcp.isDualInline())
433 toPcp = toPcp.getSubPoint().get(0);
434 newPcp.insert(toPcp, Direction.NEXT);
435 newPcp.setWorldPosition(pos);
438 if (toPcp.isDualSub())
439 toPcp = toPcp.parent;
440 newPcp.insert(toPcp, Direction.PREVIOUS);
441 newPcp.setWorldPosition(pos);
444 PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
447 PipeRun other = new PipeRun();
448 String n = root.getUniqueName("PipeRun");
450 other.setPipeDiameter(inst.diameter);
451 other.setTurnRadius(inst.turnRadius);
452 root.addChild(other);
455 if (position == PositionType.NEXT) {
456 PipingRules.addSizeChange(false, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
457 } else if (position == PositionType.PREVIOUS){
458 PipingRules.addSizeChange(true, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
460 newPcp.setWorldPosition(pos);
461 // TODO : chicken-egg problem
462 newComponent.updateParameters();
463 Vector3d v = new Vector3d(dir);
464 v.scale(newComponent.getControlPoint().getLength()*0.5);
475 newPcp.setWorldPosition(pos);
482 public static boolean connect(PipelineComponent current, PipelineComponent endTo) throws Exception {
483 return connect(current, endTo, null, null);
487 * Connects component to another component
495 public static boolean connect(PipelineComponent current, PipelineComponent endTo, PositionType endType, Vector3d position) throws Exception{
496 PipeControlPoint endCP = endTo.getControlPoint();
498 if (current.getNext() == null)
500 else if (current.getPrevious() == null)
505 PipeRun pipeRun = current.getPipeRun();
506 P3DRootNode root = (P3DRootNode)current.getRootNode();
507 PipeControlPoint currentCP = current.getControlPoint();
509 if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
513 boolean requiresReverse = false;
514 if (!reversed && endCP.getPrevious() != null) {
515 if (endCP.getNext() != null)
517 requiresReverse = true;
518 } else if (reversed && endCP.getNext() != null) {
519 if (endCP.getPrevious() != null)
521 requiresReverse = true;
523 PipeRun other = endCP.getPipeRun();
524 boolean mergeRuns = other == null ? true : pipeRun.equalSpecs(other);
526 if (requiresReverse) {
527 // Pipe line must be traversible with next/previous relations without direction change.
528 // Now the component, where we are connecting the created pipeline is defined in different order.
529 PipingRules.reverse(other);
533 // Runs have compatible specs and must be merged
534 if (other != null && pipeRun != other)
535 PipingRules.merge(pipeRun, other);
536 else if (other == null) {
537 if (!(endTo instanceof Nozzle)) {
538 pipeRun.addChild(endTo);
540 endTo.setPipeRun(pipeRun);
544 currentCP.setNext(endCP);
545 endCP.setPrevious(currentCP);
547 currentCP.setPrevious(endCP);
548 endCP.setNext(currentCP);
551 // Runs do not have compatible specs, and a reducer must be attached in between.
552 InlineComponent reducer = ComponentUtils.createReducer(root);
553 PipeControlPoint pcp = reducer.getControlPoint();
554 PipeControlPoint ocp = pcp.getSubPoint().get(0);
556 Vector3d endPos = endCP.getWorldPosition();
557 Vector3d currentPos = currentCP.getWorldPosition();
558 Vector3d v = new Vector3d(endPos);
563 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
565 pcp.setWorldPosition(v);
566 reducer.updateParameters();
568 PipingRules.positionUpdate(endCP);
571 } else if (endType == PositionType.SPLIT) {
572 InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, position);
573 if (branchSplit == null)
575 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
576 PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
577 branchSplitCP.children.add(pcp);
578 pcp.parent = branchSplitCP;
579 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
580 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
584 pcp.setPrevious(currentCP);
585 currentCP.setNext(pcp);
587 pcp.setNext(currentCP);
588 currentCP.setPrevious(pcp);
590 PipingRules.positionUpdate(endCP);
596 public static InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
597 if (!component.isVariableLength())
599 PipeRun pipeRun = component.getPipeRun();
600 Vector3d sStart = new Vector3d();
601 Vector3d sEnd = new Vector3d();
602 component.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
604 if (MathTools.distance(sStart, sEnd) < (pipeRun.getPipeDiameter()*0.5))
608 Vector3d p = MathTools.closestPointOnEdge(new Vector3d(pos), sStart, sEnd);
610 Vector3d v = new Vector3d(sEnd);
613 v.scale(component.getPipeRun().getPipeDiameter()*0.5);
615 } else if (p == sEnd) {
616 Vector3d v = new Vector3d(sStart);
619 v.scale(component.getPipeRun().getPipeDiameter()*0.5);
623 P3DRootNode root = (P3DRootNode)component.getRootNode();
624 InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
625 String branchName = component.getPipeRun().getUniqueName("Branch");
626 branchSplit.setName(branchName);
627 component.getPipeRun().addChild(branchSplit);
628 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
629 branchSplitCP.setWorldPosition(p);
630 PipingRules.splitVariableLengthComponent(branchSplit, component, false);