1 package org.simantics.plant3d.utils;
3 import java.util.ArrayList;
4 import java.util.HashMap;
8 import javax.vecmath.Vector3d;
10 import org.simantics.Simantics;
11 import org.simantics.db.ReadGraph;
12 import org.simantics.db.Resource;
13 import org.simantics.db.common.request.ReadRequest;
14 import org.simantics.db.common.utils.NameUtils;
15 import org.simantics.db.exception.DatabaseException;
16 import org.simantics.g3d.math.MathTools;
17 import org.simantics.g3d.scenegraph.GeometryProvider;
18 import org.simantics.g3d.scenegraph.ParametricGeometryProvider;
19 import org.simantics.layer0.Layer0;
20 import org.simantics.plant3d.geometry.ParameterRead;
21 import org.simantics.plant3d.ontology.Plant3D;
22 import org.simantics.plant3d.scenegraph.EndComponent;
23 import org.simantics.plant3d.scenegraph.Equipment;
24 import org.simantics.plant3d.scenegraph.InlineComponent;
25 import org.simantics.plant3d.scenegraph.Nozzle;
26 import org.simantics.plant3d.scenegraph.P3DRootNode;
27 import org.simantics.plant3d.scenegraph.PipeRun;
28 import org.simantics.plant3d.scenegraph.PipelineComponent;
29 import org.simantics.plant3d.scenegraph.TurnComponent;
30 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
31 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
32 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
33 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
35 public class ComponentUtils {
38 private static Map<String,Class<? extends PipelineComponent>> clazzes = new HashMap<String, Class<? extends PipelineComponent>>();
39 private static Map<String,GeometryProvider> providers = new HashMap<String,GeometryProvider>();
40 private static Map<String,String> names = new HashMap<String,String>();
42 public static void preloadCache() {
43 Simantics.getSession().asyncRequest(new ReadRequest() {
46 public void run(ReadGraph graph) throws DatabaseException {
47 List<String> types = new ArrayList<String>();
48 types.add(Plant3D.URIs.Builtin_Straight);
49 types.add(Plant3D.URIs.Builtin_Elbow);
50 types.add(Plant3D.URIs.Builtin_ConcentricReducer);
51 types.add(Plant3D.URIs.Builtin_BranchSplitComponent);
52 types.add(Plant3D.URIs.Builtin_EccentricReducer);
53 types.add(Plant3D.URIs.Builtin_Elbow45);
54 types.add(Plant3D.URIs.Builtin_Elbow90);
56 for (String typeURI : types) {
63 private static GeometryProvider getProvider(ReadGraph graph, Resource type) throws DatabaseException {
65 Layer0 l0 = Layer0.getInstance(graph);
66 Plant3D p3d = Plant3D.getInstance(graph);
67 Resource geom = graph.getPossibleObject(type,p3d.hasGeometry);
69 for (Resource a : graph.getObjects(type, l0.Asserts)) {
70 if (p3d.hasGeometry.equals(graph.getPossibleObject(a, l0.HasPredicate))) {
71 geom = graph.getPossibleObject(a, l0.HasObject);
77 GeometryProvider provider = graph.adapt(geom, GeometryProvider.class);
78 if (provider instanceof ParametricGeometryProvider) {
79 Map<String,Object> params = graph.syncRequest(new ParameterRead(type));
80 if (params.size() > 0)
81 ((ParametricGeometryProvider)provider).setProperties(params);
88 private static Class<? extends PipelineComponent> getClazz(ReadGraph graph, Resource type) throws DatabaseException {
89 Plant3D p3d = Plant3D.getInstance(graph);
90 if (graph.isInheritedFrom(type, p3d.InlineComponent))
91 return InlineComponent.class;
92 if (graph.isInheritedFrom(type, p3d.TurnComponent))
93 return TurnComponent.class;
94 if (graph.isInheritedFrom(type, p3d.EndComponent))
95 return EndComponent.class;
96 if (graph.isInheritedFrom(type, p3d.Nozzle))
101 private static void load(ReadGraph graph, String typeURI) throws DatabaseException {
102 Plant3D p3d = Plant3D.getInstance(graph);
103 Resource type = graph.getResource(typeURI);
105 GeometryProvider provider = getProvider(graph, type);
106 if (provider != null || graph.hasStatement(type,p3d.NonVisibleComponent)) {
107 providers.put(typeURI, provider);
108 if (graph.isInheritedFrom(type, p3d.PipelineComponent))
109 clazzes.put(typeURI,getClazz(graph, type));
110 names.put(typeURI, NameUtils.getSafeName(graph, type));
113 throw new DatabaseException("Cannot find component for " + typeURI);
116 private static void load(final String typeURI) throws DatabaseException {
117 Simantics.getSession().syncRequest(new ReadRequest() {
120 public void run(ReadGraph graph) throws DatabaseException {
127 * Creates a component
129 * Does not set the name or add the component to a piperun.
135 public static PipelineComponent createComponent(P3DRootNode root, String typeURI) throws Exception {
136 Class<? extends PipelineComponent> type = clazzes.get(typeURI);
137 GeometryProvider provider = providers.get(typeURI);
138 if (type == null || provider == null) {
140 type = clazzes.get(typeURI);
141 provider = providers.get(typeURI);
143 //PipelineComponent component = type.newInstance();
144 PipelineComponent component = null;
145 if (type == InlineComponent.class) {
146 component = root.createInline();
147 } else if (type == TurnComponent.class) {
148 component = root.createTurn();
149 } else if (type == EndComponent.class) {
150 component = root.createTurn();
151 } else if (type == Nozzle.class) {
152 component = root.createNozzle();
154 component.setType(typeURI);
155 component.setGeometry(provider);
160 * Creates a equipment
162 * Does not set the name
170 public static Equipment createEquipment(P3DRootNode root, String typeURI) throws Exception {
171 GeometryProvider provider = providers.get(typeURI);
172 if (provider == null) {
174 provider = providers.get(typeURI);
176 Equipment equipment = root.createEquipment();
177 equipment.setType(typeURI);
178 equipment.setGeometry(provider);
179 root.addChild(equipment);
183 public static Equipment createEquipmentWithNozzles(P3DRootNode root, String typeURI, String nozzleTypeUri) throws Exception {
184 GeometryProvider provider = providers.get(typeURI);
185 if (provider == null) {
187 provider = providers.get(typeURI);
189 Equipment equipment = root.createEquipment();
190 equipment.setType(typeURI);
191 equipment.setGeometry(provider);
192 root.addChild(equipment);
194 for (int i = 0; i < equipment.numberOfFixedNozzles(); i++) {
195 createNozzle(root, equipment, new Item(nozzleTypeUri, "Nozzle"));
202 public static InlineComponent createStraight(P3DRootNode root) throws Exception{
203 InlineComponent component = root.createInline();
204 component.setType(Plant3D.URIs.Builtin_Straight);
205 component.setGeometry(providers.get(Plant3D.URIs.Builtin_Straight));
209 public static TurnComponent createTurn(P3DRootNode root) throws Exception {
210 TurnComponent elbow = root.createTurn();
211 elbow.setType(Plant3D.URIs.Builtin_Elbow);
212 elbow.setGeometry(providers.get(Plant3D.URIs.Builtin_Elbow));
216 public static InlineComponent createReducer(P3DRootNode root) throws Exception {
217 InlineComponent component = root.createInline();
218 component.setType(Plant3D.URIs.Builtin_ConcentricReducer);
219 component.setGeometry(providers.get(Plant3D.URIs.Builtin_ConcentricReducer));
223 public static InlineComponent createBranchSplit(P3DRootNode root) throws Exception {
224 InlineComponent component = root.createInline();
225 component.setType(Plant3D.URIs.Builtin_BranchSplitComponent);
229 public static Equipment createEquipment(P3DRootNode root, Item equipmentType) throws Exception {
230 Equipment equipment = createEquipment(root, equipmentType.getUri());
231 String n = root.getUniqueName(equipmentType.getName());
232 equipment.setName(n);
236 public static Equipment createEquipmentWithNozzles(P3DRootNode root, Item equipmentType, Item nozzleType) throws Exception {
237 Equipment equipment = createEquipmentWithNozzles(root, equipmentType.getUri(), nozzleType.getUri());
238 String n = root.getUniqueName(equipmentType.getName());
239 equipment.setName(n);
243 public static Nozzle createDefaultNozzle(P3DRootNode root, Equipment equipment) throws Exception {
244 return createNozzle(root, equipment, new Item(Plant3D.URIs.Builtin_Nozzle, "Nozzle"));
247 public static Nozzle createNozzle(P3DRootNode root, Equipment equipment, Item nozzleType) throws Exception {
248 Nozzle nozzle = root.createNozzle();
249 nozzle.setType(nozzleType.getUri());
250 String n = root.getUniqueName(nozzleType.getName());
252 PipeRun pipeRun = new PipeRun();
253 n = root.getUniqueName("PipeRun");
255 nozzle.setPipeRun(pipeRun);
257 equipment.addChild(nozzle);
258 root.addChild(pipeRun);
259 // root.getNodeMap().commit("Add nozzle " + n);
263 public static class InsertInstruction {
264 public String typeUri;
266 public PositionType position = PositionType.NEXT;
267 public PositionType insertPosition = PositionType.NEXT;
269 // Reducer requires pipe specs
270 public Double diameter;
271 public Double turnRadius;
274 public Double length;
279 // Rotation angle used with turns and rotated inline.
280 public Double rotationAngle;
282 public String getTypeUri() {
286 public void setTypeUri(String typeUri) {
287 this.typeUri = typeUri;
290 public PositionType getPosition() {
294 public void setPosition(PositionType position) {
295 this.position = position;
298 public PositionType getInsertPosition() {
299 return insertPosition;
302 public void setInsertPosition(PositionType insertPosition) {
303 this.insertPosition = insertPosition;
306 public Double getDiameter() {
310 public void setDiameter(Double diameter) {
311 this.diameter = diameter;
314 public Double getTurnRadius() {
318 public void setTurnRadius(Double turnRadius) {
319 this.turnRadius = turnRadius;
322 public Double getLength() {
326 public void setLength(Double length) {
327 this.length = length;
330 public Double getAngle() {
334 public void setAngle(Double angle) {
338 public Double getRotationAngle() {
339 return rotationAngle;
342 public void setRotationAngle(Double rotationAngle) {
343 this.rotationAngle = rotationAngle;
348 public static PipelineComponent addComponent(P3DRootNode root, PipelineComponent component, InsertInstruction inst) throws Exception {
350 PipelineComponent newComponent = ComponentUtils.createComponent(root, inst.typeUri);
351 PipeControlPoint newPcp = newComponent.getControlPoint();
353 PipeControlPoint toPcp = component.getControlPoint();
354 PipeRun pipeRun = toPcp.getPipeRun();
356 String typeName = names.get(inst.typeUri);
357 if (typeName == null)
358 typeName = "Component";
363 PositionType position = inst.position;
364 PositionType insertPosition = inst.insertPosition;
365 boolean lengthAdjustable = false;
366 if (newComponent instanceof InlineComponent) {
367 lengthAdjustable = ((InlineComponent)newComponent).isVariableLength() || ((InlineComponent)newComponent).isModifialble();
369 boolean insertAdjustable = false;
370 if (component instanceof InlineComponent) {
371 insertAdjustable = ((InlineComponent)component).isVariableLength();
373 boolean sizeChange = false;
374 if (newComponent instanceof InlineComponent) {
375 sizeChange = ((InlineComponent)newComponent).isSizeChange();
378 if (toPcp.isInline()) {
381 if (toPcp.isDualInline()) {
382 toPcp = toPcp.getDualSub();
383 pipeRun = toPcp.getPipeRun();
388 if (toPcp.isDualSub()) {
389 toPcp = toPcp.parent;
390 pipeRun = toPcp.getPipeRun();
396 Vector3d start = new Vector3d();
397 Vector3d end = new Vector3d();
398 dir = new Vector3d();
399 toPcp.getInlineControlPointEnds(start, end, dir);
403 pos = new Vector3d(end);
406 pos = new Vector3d(start);
409 pos = new Vector3d(toPcp.getWorldPosition());
415 } else if (toPcp.isDirected()) {
416 dir = new Vector3d(toPcp.getDirection(Direction.NEXT));
417 pos = new Vector3d(toPcp.getWorldPosition());
418 } else if (toPcp.isTurn() && toPcp.asFixedAngle()) {
419 dir = new Vector3d(toPcp.getDirection(position == PositionType.NEXT ? Direction.NEXT : Direction.PREVIOUS));
420 pos = new Vector3d(toPcp.getWorldPosition());
421 if (!lengthAdjustable) {
422 Vector3d v = new Vector3d(dir);
423 v.scale(toPcp.getInlineLength());
426 if (insertPosition == PositionType.NEXT) {
427 Vector3d v = new Vector3d(dir);
428 v.scale(toPcp.getInlineLength());
430 } else if (insertPosition == PositionType.SPLIT) {
431 // scale 0.5*length so that we don't remove the length twice from the new component
432 Vector3d v = new Vector3d(dir);
433 v.scale(toPcp.getInlineLength()*0.5);
441 String name = component.getPipeRun().getUniqueName(typeName);
442 newComponent.setName(name);
444 pipeRun.addChild(newComponent);
446 if (newComponent instanceof InlineComponent) {
447 InlineComponent inlineComponent = (InlineComponent)newComponent;
448 if (inlineComponent.isVariableLength()|| inlineComponent.isModifialble()) {
449 newPcp.setLength(inst.length);
450 newComponent.setParameter("length", inst.length);
452 if (inst.rotationAngle != null)
453 ((InlineComponent) newComponent).setRotationAngle(inst.rotationAngle);
454 } else if (newComponent instanceof TurnComponent) {
455 TurnComponent turnComponent = (TurnComponent)newComponent;
456 if (turnComponent.isVariableAngle()) {
457 newPcp.setTurnAngle(inst.angle);
458 newComponent.setParameter("turnAngle", inst.angle);
460 if (inst.rotationAngle != null)
461 ((TurnComponent) newComponent).setRotationAngle(inst.rotationAngle);
465 newComponent.updateParameters();
467 Vector3d v = new Vector3d(dir);
468 if (insertAdjustable) {
469 if (insertPosition == PositionType.NEXT)
470 v.scale(newComponent.getControlPoint().getInlineLength());
471 else if (insertPosition == PositionType.SPLIT)
473 else if (insertPosition == PositionType.PREVIOUS)
474 v.scale(-newComponent.getControlPoint().getInlineLength());
476 v.scale(newComponent.getControlPoint().getInlineLength());
493 if (toPcp.isDualInline())
494 toPcp = toPcp.getDualSub();
495 newPcp.insert(toPcp, Direction.NEXT);
496 newPcp.setWorldPosition(pos);
499 if (toPcp.isDualSub())
500 toPcp = toPcp.parent;
501 newPcp.insert(toPcp, Direction.PREVIOUS);
502 newPcp.setWorldPosition(pos);
505 PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
510 PipeRun other = new PipeRun();
511 String n = root.getUniqueName("PipeRun");
513 other.setPipeDiameter(inst.diameter);
514 other.setTurnRadius(inst.turnRadius);
515 root.addChild(other);
518 if (position == PositionType.NEXT) {
519 PipingRules.addSizeChange(false, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
520 } else if (position == PositionType.PREVIOUS){
521 PipingRules.addSizeChange(true, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
523 newPcp.setWorldPosition(pos);
525 // TODO : chicken-egg problem
526 newComponent.updateParameters();
527 Vector3d v = new Vector3d(dir);
528 v.scale(newComponent.getControlPoint().getLength()*0.5);
541 newPcp.setWorldPosition(pos);
542 if (inst.rotationAngle != null)
543 ((InlineComponent) newComponent).setRotationAngle(inst.rotationAngle);
550 public static boolean connect(PipelineComponent current, PipelineComponent endTo) throws Exception {
551 return connect(current, endTo, null, null);
555 * Connects component to another component
563 public static boolean connect(PipelineComponent current, PipelineComponent endTo, PositionType endType, Vector3d position) throws Exception{
564 PipeControlPoint endCP = endTo.getControlPoint();
566 if (current.getNext() == null)
568 else if (current.getPrevious() == null)
573 PipeRun pipeRun = current.getPipeRun();
574 P3DRootNode root = (P3DRootNode)current.getRootNode();
575 PipeControlPoint currentCP = current.getControlPoint();
577 if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
581 boolean requiresReverse = false;
582 if (!reversed && endCP.getPrevious() != null) {
583 if (endCP.getNext() != null)
585 requiresReverse = true;
586 } else if (reversed && endCP.getNext() != null) {
587 if (endCP.getPrevious() != null)
589 requiresReverse = true;
591 PipeRun other = endCP.getPipeRun();
592 boolean mergeRuns = other == null ? true : pipeRun.canMerge(other);
594 if (requiresReverse) {
595 // Pipe line must be traversible with next/previous relations without direction change.
596 // Now the component, where we are connecting the created pipeline is defined in different order.
597 PipingRules.reverse(other);
602 // Runs have compatible specs and must be merged
603 if (other != null && pipeRun != other)
604 pipeRun.merge(other);
605 else if (other == null) {
606 if (!(endTo instanceof Nozzle)) {
607 pipeRun.addChild(endTo);
609 endTo.setPipeRun(pipeRun);
613 currentCP.setNext(endCP);
614 endCP.setPrevious(currentCP);
616 currentCP.setPrevious(endCP);
617 endCP.setNext(currentCP);
620 // Runs do not have compatible specs, and a reducer must be attached in between.
621 InlineComponent reducer = ComponentUtils.createReducer(root);
622 PipeControlPoint pcp = reducer.getControlPoint();
624 Vector3d endPos = endCP.getWorldPosition();
625 Vector3d currentPos = currentCP.getWorldPosition();
626 Vector3d v = new Vector3d(endPos);
631 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
633 pcp.setWorldPosition(v);
634 reducer.updateParameters();
636 PipingRules.positionUpdate(endCP);
639 } else if (endType == PositionType.SPLIT) {
640 InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, position);
641 if (branchSplit == null)
643 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
644 PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
645 branchSplitCP.children.add(pcp);
646 pcp.parent = branchSplitCP;
647 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
648 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
652 pcp.setPrevious(currentCP);
653 currentCP.setNext(pcp);
655 pcp.setNext(currentCP);
656 currentCP.setPrevious(pcp);
658 PipingRules.positionUpdate(endCP);
664 public static InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
665 if (!component.isVariableLength())
667 PipeRun pipeRun = component.getPipeRun();
668 Vector3d sStart = new Vector3d();
669 Vector3d sEnd = new Vector3d();
670 component.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
672 if (MathTools.distance(sStart, sEnd) < (pipeRun.getPipeDiameter()*0.5))
676 Vector3d p = MathTools.closestPointOnEdge(new Vector3d(pos), sStart, sEnd);
678 Vector3d v = new Vector3d(sEnd);
681 v.scale(component.getPipeRun().getPipeDiameter()*0.5);
683 } else if (p == sEnd) {
684 Vector3d v = new Vector3d(sStart);
687 v.scale(component.getPipeRun().getPipeDiameter()*0.5);
691 P3DRootNode root = (P3DRootNode)component.getRootNode();
692 InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
693 String branchName = component.getPipeRun().getUniqueName("Branch");
694 branchSplit.setName(branchName);
695 component.getPipeRun().addChild(branchSplit);
696 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
697 branchSplitCP.setWorldPosition(p);
698 PipingRules.splitVariableLengthComponent(branchSplit, component, false);