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);
211 public static Nozzle createDefaultNozzle(P3DRootNode root, Equipment equipment) throws Exception {
212 return createNozzle(root, equipment, new Item(Plant3D.URIs.Builtin_Nozzle, "Nozzle"));
215 public static Nozzle createNozzle(P3DRootNode root, Equipment equipment, Item nozzleType) throws Exception {
216 Nozzle nozzle = root.createNozzle();
217 nozzle.setType(nozzleType.getUri());
218 String n = root.getUniqueName(nozzleType.getName());
220 PipeRun pipeRun = new PipeRun();
221 n = root.getUniqueName("PipeRun");
223 nozzle.setPipeRun(pipeRun);
225 equipment.addChild(nozzle);
226 root.addChild(pipeRun);
227 // root.getNodeMap().commit("Add nozzle " + n);
231 public static class InsertInstruction {
232 public String typeUri;
234 public PositionType position = PositionType.NEXT;
235 public PositionType insertPosition = PositionType.NEXT;
237 // Reducer requires pipe specs
238 public Double diameter;
239 public Double turnRadius;
242 public Double length;
247 public String getTypeUri() {
251 public void setTypeUri(String typeUri) {
252 this.typeUri = typeUri;
255 public PositionType getPosition() {
259 public void setPosition(PositionType position) {
260 this.position = position;
263 public PositionType getInsertPosition() {
264 return insertPosition;
267 public void setInsertPosition(PositionType insertPosition) {
268 this.insertPosition = insertPosition;
271 public Double getDiameter() {
275 public void setDiameter(Double diameter) {
276 this.diameter = diameter;
279 public Double getTurnRadius() {
283 public void setTurnRadius(Double turnRadius) {
284 this.turnRadius = turnRadius;
287 public Double getLength() {
291 public void setLength(Double length) {
292 this.length = length;
295 public Double getAngle() {
299 public void setAngle(Double angle) {
305 public static PipelineComponent addComponent(P3DRootNode root, PipelineComponent component, InsertInstruction inst) throws Exception {
307 PipelineComponent newComponent = ComponentUtils.createComponent(root, inst.typeUri);
308 PipeControlPoint newPcp = newComponent.getControlPoint();
310 PipeControlPoint toPcp = component.getControlPoint();
311 PipeRun pipeRun = toPcp.getPipeRun();
313 String typeName = names.get(inst.typeUri);
314 if (typeName == null)
315 typeName = "Component";
320 PositionType position = inst.position;
321 PositionType insertPosition = inst.insertPosition;
322 boolean lengthAdjustable = false;
323 if (newComponent instanceof InlineComponent) {
324 lengthAdjustable = ((InlineComponent)newComponent).isVariableLength();
326 boolean insertAdjustable = false;
327 if (component instanceof InlineComponent) {
328 insertAdjustable = ((InlineComponent)component).isVariableLength();
330 boolean sizeChange = false;
331 if (newComponent instanceof InlineComponent) {
332 sizeChange = ((InlineComponent)newComponent).isSizeChange();
335 if (toPcp.isInline()) {
338 if (toPcp.isDualInline()) {
339 toPcp = toPcp.getSubPoint().get(0);
340 pipeRun = toPcp.getPipeRun();
345 if (toPcp.isDualSub()) {
346 toPcp = toPcp.parent;
347 pipeRun = toPcp.getPipeRun();
351 Vector3d start = new Vector3d();
352 Vector3d end = new Vector3d();
353 dir = new Vector3d();
354 toPcp.getInlineControlPointEnds(start, end, dir);
358 pos = new Vector3d(end);
361 pos = new Vector3d(start);
364 pos = new Vector3d(toPcp.getWorldPosition());
368 } else if (toPcp.isDirected()) {
369 dir = new Vector3d(toPcp.getDirection(Direction.NEXT));
370 pos = new Vector3d(toPcp.getWorldPosition());
371 } else if (toPcp.isTurn() && toPcp.isFixed()) {
372 dir = new Vector3d(toPcp.getDirection(position == PositionType.NEXT ? Direction.NEXT : Direction.PREVIOUS));
373 pos = new Vector3d(toPcp.getWorldPosition());
374 if (!lengthAdjustable) {
375 Vector3d v = new Vector3d(dir);
376 v.scale(toPcp.getInlineLength());
379 if (insertPosition == PositionType.NEXT) {
380 Vector3d v = new Vector3d(dir);
381 v.scale(toPcp.getInlineLength());
383 } else if (insertPosition == PositionType.SPLIT) {
384 // scale 0.5*length so that we don't remove the length twice from the new component
385 Vector3d v = new Vector3d(dir);
386 v.scale(toPcp.getInlineLength()*0.5);
394 String name = component.getPipeRun().getUniqueName(typeName);
395 newComponent.setName(name);
397 pipeRun.addChild(newComponent);
398 // TODO: these options are not stored into DB. Should they?!
399 if (newComponent instanceof InlineComponent && ((InlineComponent)newComponent).isVariableLength()) {
400 newPcp.setLength(inst.length);
401 } else if (newComponent instanceof TurnComponent && ((TurnComponent)newComponent).isVariableAngle()) {
402 newPcp.setTurnAngle(inst.angle);
405 newComponent.updateParameters();
407 Vector3d v = new Vector3d(dir);
408 if (insertAdjustable) {
409 if (insertPosition == PositionType.NEXT)
410 v.scale(newComponent.getControlPoint().getInlineLength());
411 else if (insertPosition == PositionType.SPLIT)
413 else if (insertPosition == PositionType.PREVIOUS)
414 v.scale(-newComponent.getControlPoint().getInlineLength());
416 v.scale(newComponent.getControlPoint().getInlineLength());
431 if (toPcp.isDualInline())
432 toPcp = toPcp.getSubPoint().get(0);
433 newPcp.insert(toPcp, Direction.NEXT);
434 newPcp.setWorldPosition(pos);
437 if (toPcp.isDualSub())
438 toPcp = toPcp.parent;
439 newPcp.insert(toPcp, Direction.PREVIOUS);
440 newPcp.setWorldPosition(pos);
443 PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
446 PipeRun other = new PipeRun();
447 String n = root.getUniqueName("PipeRun");
449 other.setPipeDiameter(inst.diameter);
450 other.setTurnRadius(inst.turnRadius);
451 root.addChild(other);
454 if (position == PositionType.NEXT) {
455 PipingRules.addSizeChange(false, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
456 } else if (position == PositionType.PREVIOUS){
457 PipingRules.addSizeChange(true, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
459 newPcp.setWorldPosition(pos);
460 // TODO : chicken-egg problem
461 newComponent.updateParameters();
462 Vector3d v = new Vector3d(dir);
463 v.scale(newComponent.getControlPoint().getLength()*0.5);
474 newPcp.setWorldPosition(pos);
481 public static boolean connect(PipelineComponent current, PipelineComponent endTo) throws Exception {
482 return connect(current, endTo, null, null);
486 * Connects component to another component
494 public static boolean connect(PipelineComponent current, PipelineComponent endTo, PositionType endType, Vector3d position) throws Exception{
495 PipeControlPoint endCP = endTo.getControlPoint();
497 if (current.getNext() == null)
499 else if (current.getPrevious() == null)
504 PipeRun pipeRun = current.getPipeRun();
505 P3DRootNode root = (P3DRootNode)current.getRootNode();
506 PipeControlPoint currentCP = current.getControlPoint();
508 if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
512 boolean requiresReverse = false;
513 if (!reversed && endCP.getPrevious() != null) {
514 if (endCP.getNext() != null)
516 requiresReverse = true;
517 } else if (reversed && endCP.getNext() != null) {
518 if (endCP.getPrevious() != null)
520 requiresReverse = true;
522 PipeRun other = endCP.getPipeRun();
523 boolean mergeRuns = other == null ? true : pipeRun.equalSpecs(other);
525 if (requiresReverse) {
526 // Pipe line must be traversible with next/previous relations without direction change.
527 // Now the component, where we are connecting the created pipeline is defined in different order.
528 PipingRules.reverse(other);
532 // Runs have compatible specs and must be merged
533 if (other != null && pipeRun != other)
534 PipingRules.merge(pipeRun, other);
535 else if (other == null) {
536 if (!(endTo instanceof Nozzle)) {
537 pipeRun.addChild(endTo);
539 endTo.setPipeRun(pipeRun);
543 currentCP.setNext(endCP);
544 endCP.setPrevious(currentCP);
546 currentCP.setPrevious(endCP);
547 endCP.setNext(currentCP);
550 // Runs do not have compatible specs, and a reducer must be attached in between.
551 InlineComponent reducer = ComponentUtils.createReducer(root);
552 PipeControlPoint pcp = reducer.getControlPoint();
553 PipeControlPoint ocp = pcp.getSubPoint().get(0);
555 Vector3d endPos = endCP.getWorldPosition();
556 Vector3d currentPos = currentCP.getWorldPosition();
557 Vector3d v = new Vector3d(endPos);
562 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
564 pcp.setWorldPosition(v);
565 reducer.updateParameters();
567 PipingRules.positionUpdate(endCP);
570 } else if (endType == PositionType.SPLIT) {
571 InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, position);
572 if (branchSplit == null)
574 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
575 PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
576 branchSplitCP.children.add(pcp);
577 pcp.parent = branchSplitCP;
578 pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
579 pcp.setWorldPosition(branchSplitCP.getWorldPosition());
583 pcp.setPrevious(currentCP);
584 currentCP.setNext(pcp);
586 pcp.setNext(currentCP);
587 currentCP.setPrevious(pcp);
589 PipingRules.positionUpdate(endCP);
595 public static InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
596 if (!component.isVariableLength())
598 PipeRun pipeRun = component.getPipeRun();
599 Vector3d sStart = new Vector3d();
600 Vector3d sEnd = new Vector3d();
601 component.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
603 if (MathTools.distance(sStart, sEnd) < (pipeRun.getPipeDiameter()*0.5))
607 Vector3d p = MathTools.closestPointOnEdge(new Vector3d(pos), sStart, sEnd);
609 Vector3d v = new Vector3d(sEnd);
612 v.scale(component.getPipeRun().getPipeDiameter()*0.5);
614 } else if (p == sEnd) {
615 Vector3d v = new Vector3d(sStart);
618 v.scale(component.getPipeRun().getPipeDiameter()*0.5);
622 P3DRootNode root = (P3DRootNode)component.getRootNode();
623 InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
624 String branchName = component.getPipeRun().getUniqueName("Branch");
625 branchSplit.setName(branchName);
626 component.getPipeRun().addChild(branchSplit);
627 PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
628 branchSplitCP.setWorldPosition(p);
629 PipingRules.splitVariableLengthComponent(branchSplit, component, false);