]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java
Adding a component next to a reducer used wrong PipeRun
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / utils / ComponentUtils.java
1 package org.simantics.plant3d.utils;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import javax.vecmath.Point3d;
9 import javax.vecmath.Vector3d;
10
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;
33
34 public class ComponentUtils {
35
36         
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>();
40         
41         public static void preloadCache() {
42                 Simantics.getSession().asyncRequest(new ReadRequest() {
43                         
44                         @Override
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);
52                                 
53                                 for (String typeURI : types) {
54                                         load(graph, typeURI);
55                                 }
56                         }
57                 });
58         }
59         
60         private static GeometryProvider getProvider(ReadGraph graph, Resource type) throws DatabaseException {
61                 
62                 Layer0 l0 = Layer0.getInstance(graph);
63                 Plant3D p3d = Plant3D.getInstance(graph);
64                 Resource geom = graph.getPossibleObject(type,p3d.hasGeometry);
65                 if (geom == null) {
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);
69                                         break;
70                                 }
71                         }
72                 }
73                 if (geom != null) {
74                         GeometryProvider provider = graph.adapt(geom, GeometryProvider.class);
75                         return provider;
76                 }
77                 return null;
78         }
79         
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))
89                         return Nozzle.class;
90                 return null;
91         }
92         
93         private static void load(ReadGraph graph, String typeURI) throws DatabaseException {
94                 Plant3D p3d = Plant3D.getInstance(graph);
95                 Resource type = graph.getResource(typeURI);
96                 
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));
103                         return;
104                 }
105                 throw new DatabaseException("Cannot find component for " + typeURI);
106         }
107         
108         private static void load(final String typeURI) throws DatabaseException {
109                 Simantics.getSession().syncRequest(new ReadRequest() {
110                         
111                         @Override
112                         public void run(ReadGraph graph) throws DatabaseException {
113                                 load(graph,typeURI);    
114                         }
115                 });
116         }
117         
118         /**
119          * Creates a component
120          * 
121          * Does not set the name or add the component to a piperun.
122          * @param root
123          * @param typeURI
124          * @return
125          * @throws Exception
126          */
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) {
131                         load(typeURI);
132                         type = clazzes.get(typeURI);
133                         provider = providers.get(typeURI);
134                 }
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();
145                 }
146                 component.setType(typeURI);
147                 component.setGeometry(provider);
148                 return component;
149         }
150         
151         /**
152          * Creates a equipment
153          * 
154          * Does not set the name
155          * 
156          * @param root
157          * @param typeURI
158          * @return
159          * @throws Exception
160          */
161         
162         public static Equipment createEquipment(P3DRootNode root, String typeURI) throws Exception {
163             GeometryProvider provider = providers.get(typeURI);
164         if (provider == null) {
165             load(typeURI);
166             provider = providers.get(typeURI);
167         }
168         Equipment equipment = root.createEquipment();
169         equipment.setType(typeURI);
170         equipment.setGeometry(provider);
171         root.addChild(equipment);
172         return equipment;
173     }
174         
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));
179                 return component;
180         }
181         
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));
186                 return elbow;
187         }
188         
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));
193                 return component;
194         }
195         
196         public static InlineComponent createBranchSplit(P3DRootNode root) throws Exception {
197                 InlineComponent component = root.createInline();
198                 component.setType(Plant3D.URIs.Builtin_BranchSplitComponent);
199                 return component;
200         }
201         
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);
207         return equipment;
208         }
209         
210         
211         
212         public static Nozzle createDefaultNozzle(P3DRootNode root, Equipment equipment) throws Exception {
213             return createNozzle(root, equipment, new Item(Plant3D.URIs.Builtin_Nozzle, "Nozzle"));
214         }
215         
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());
220         nozzle.setName(n);
221         PipeRun pipeRun = new PipeRun();
222         n = root.getUniqueName("PipeRun");
223         pipeRun.setName(n);
224         nozzle.setPipeRun(pipeRun);
225         
226         equipment.addChild(nozzle);
227         root.addChild(pipeRun);
228         // root.getNodeMap().commit("Add nozzle " + n);
229         return nozzle;
230         }
231         
232         public static class InsertInstruction {
233             public String typeUri;
234             
235             public PositionType position = PositionType.NEXT;
236             public PositionType insertPosition = PositionType.NEXT;
237             
238             // Reducer requires pipe specs
239             public Double diameter;
240             public Double turnRadius;
241             
242             // Variable length 
243             public Double length;
244             
245             // Variable angle
246             public Double angle;
247
248         public String getTypeUri() {
249             return typeUri;
250         }
251
252         public void setTypeUri(String typeUri) {
253             this.typeUri = typeUri;
254         }
255
256         public PositionType getPosition() {
257             return position;
258         }
259
260         public void setPosition(PositionType position) {
261             this.position = position;
262         }
263
264         public PositionType getInsertPosition() {
265             return insertPosition;
266         }
267
268         public void setInsertPosition(PositionType insertPosition) {
269             this.insertPosition = insertPosition;
270         }
271
272         public Double getDiameter() {
273             return diameter;
274         }
275
276         public void setDiameter(Double diameter) {
277             this.diameter = diameter;
278         }
279
280         public Double getTurnRadius() {
281             return turnRadius;
282         }
283
284         public void setTurnRadius(Double turnRadius) {
285             this.turnRadius = turnRadius;
286         }
287
288         public Double getLength() {
289             return length;
290         }
291
292         public void setLength(Double length) {
293             this.length = length;
294         }
295
296         public Double getAngle() {
297             return angle;
298         }
299
300         public void setAngle(Double angle) {
301             this.angle = angle;
302         }
303
304         }
305         
306         public static PipelineComponent addComponent(P3DRootNode root, PipelineComponent component,  InsertInstruction inst) throws Exception {
307            
308         PipelineComponent newComponent = ComponentUtils.createComponent(root, inst.typeUri);
309         PipeControlPoint newPcp = newComponent.getControlPoint();
310         
311         PipeControlPoint toPcp = component.getControlPoint();
312         PipeRun pipeRun = toPcp.getPipeRun();
313         
314         String typeName = names.get(inst.typeUri);
315         if (typeName == null)
316             typeName = "Component";
317         
318         Vector3d dir = null;
319         Vector3d pos = null;
320     
321         PositionType position = inst.position;
322         PositionType insertPosition = inst.insertPosition;
323         boolean lengthAdjustable = false;
324         if (newComponent instanceof InlineComponent) {
325             lengthAdjustable = ((InlineComponent)newComponent).isVariableLength(); 
326         }
327         boolean insertAdjustable = false;
328         if (component instanceof InlineComponent) {
329             insertAdjustable = ((InlineComponent)component).isVariableLength();
330         }
331         boolean sizeChange = false;
332         if (newComponent instanceof InlineComponent) {
333             sizeChange = ((InlineComponent)newComponent).isSizeChange();
334         }
335         
336         if (toPcp.isInline()) {
337             switch (position) {
338             case NEXT: 
339                 if (toPcp.isDualInline()) {
340                     toPcp = toPcp.getSubPoint().get(0);
341                     pipeRun = toPcp.getPipeRun();
342                 }
343                 
344                 break;
345             case PREVIOUS:
346                 if (toPcp.isDualSub()) {
347                     toPcp = toPcp.parent;
348                     pipeRun = toPcp.getPipeRun();
349                 }
350                 break;
351             }
352             Vector3d start = new Vector3d();
353             Vector3d end = new Vector3d();
354             dir = new Vector3d();
355             toPcp.getInlineControlPointEnds(start, end, dir);
356             dir.normalize();
357            switch (position) {
358             case NEXT:
359                 pos = new Vector3d(end);
360                 break;
361             case PREVIOUS:
362                 pos = new Vector3d(start);
363                 break;
364             case SPLIT:
365                 pos = new Vector3d(toPcp.getWorldPosition());
366                 break;
367             }
368            
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());
378                 pos.add(v);
379             } else {
380                 if (insertPosition == PositionType.NEXT) {
381                     Vector3d v = new Vector3d(dir);
382                     v.scale(toPcp.getInlineLength());
383                     pos.add(v);
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);  
388                     pos.add(v);
389                 }
390             }
391         }
392         
393         
394         if (!sizeChange) {
395             String name = component.getPipeRun().getUniqueName(typeName);
396             newComponent.setName(name);
397
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);
404             }
405             
406             newComponent.updateParameters();
407             
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)
413                     v.set(0, 0, 0);
414                 else if (insertPosition == PositionType.PREVIOUS)
415                     v.scale(-newComponent.getControlPoint().getInlineLength());
416             } else {
417                 v.scale(newComponent.getControlPoint().getInlineLength());
418             }
419             switch (position) {
420             case NEXT:
421                 pos.add(v);
422                 break;
423             case PREVIOUS:
424                 pos.sub(v);
425                 break;
426             case SPLIT:
427                 break;
428             }
429             
430             switch (position) {
431             case NEXT: 
432                 if (toPcp.isDualInline())
433                     toPcp = toPcp.getSubPoint().get(0);
434                 newPcp.insert(toPcp, Direction.NEXT);
435                 newPcp.setWorldPosition(pos);
436                 break;
437             case PREVIOUS:
438                 if (toPcp.isDualSub())
439                     toPcp = toPcp.parent;
440                 newPcp.insert(toPcp, Direction.PREVIOUS);
441                 newPcp.setWorldPosition(pos);
442                 break;
443             case SPLIT:
444                 PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
445             }
446         } else {
447             PipeRun other = new PipeRun();
448             String n = root.getUniqueName("PipeRun");
449             other.setName(n);
450             other.setPipeDiameter(inst.diameter);
451             other.setTurnRadius(inst.turnRadius);
452             root.addChild(other);
453             
454             
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);
459             }
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);
465             switch (position) {
466             case NEXT:
467                 pos.add(v);
468                 break;
469             case PREVIOUS:
470                 pos.sub(v);
471                 break;
472             case SPLIT:
473                 break;
474             }
475             newPcp.setWorldPosition(pos);
476             
477         }
478                     
479                
480             return newComponent;
481         }
482         public static boolean connect(PipelineComponent current, PipelineComponent endTo) throws Exception {
483             return connect(current, endTo, null, null);
484         }
485         
486         /**
487          * Connects component to another component
488          * @param current
489          * @param endTo
490          * @param endType
491          * @param position
492          * @return
493          * @throws Exception
494          */
495         public static boolean connect(PipelineComponent current, PipelineComponent endTo, PositionType endType, Vector3d position) throws Exception{
496             PipeControlPoint endCP = endTo.getControlPoint();
497             boolean reversed;
498             if (current.getNext() == null)
499                 reversed = false;
500             else if (current.getPrevious() == null)
501                 reversed = true;
502             else
503                 return false;
504             
505             PipeRun pipeRun = current.getPipeRun();
506             P3DRootNode root = (P3DRootNode)current.getRootNode();
507             PipeControlPoint currentCP = current.getControlPoint();
508             
509         if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
510             
511             
512             
513             boolean requiresReverse = false;
514             if (!reversed && endCP.getPrevious() != null) {
515                 if (endCP.getNext() != null)
516                     return false;
517                 requiresReverse = true;
518             } else if (reversed && endCP.getNext() != null) {
519                 if (endCP.getPrevious() != null)
520                     return false;
521                 requiresReverse = true;
522             }
523             PipeRun other = endCP.getPipeRun();
524             boolean mergeRuns = other == null ? true : pipeRun.equalSpecs(other);
525             
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);
530                 
531             }
532             if (mergeRuns) {
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);
539                     } else {
540                         endTo.setPipeRun(pipeRun);
541                     }
542                 }
543                 if (!reversed) {
544                     currentCP.setNext(endCP);
545                     endCP.setPrevious(currentCP);
546                 } else {
547                     currentCP.setPrevious(endCP);
548                     endCP.setNext(currentCP);
549                 }
550             } else {
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);
555                 
556                 Vector3d endPos = endCP.getWorldPosition();
557                 Vector3d currentPos = currentCP.getWorldPosition();
558                 Vector3d v = new Vector3d(endPos);
559                 v.sub(currentPos);
560                 v.scale(0.5);
561                 v.add(currentPos);
562                 
563                 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
564                 
565                 pcp.setWorldPosition(v);
566                 reducer.updateParameters();
567             }
568             PipingRules.positionUpdate(endCP);
569             return true;
570             
571         } else if (endType == PositionType.SPLIT) {
572             InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, position);
573             if (branchSplit == null)
574                 return false;
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());
581                         
582             
583             if(!reversed) {
584                 pcp.setPrevious(currentCP);
585                 currentCP.setNext(pcp);
586             } else {
587                 pcp.setNext(currentCP);
588                 currentCP.setPrevious(pcp);
589             }
590             PipingRules.positionUpdate(endCP);
591             return true;
592         }
593         return false;
594         }
595         
596         public static InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
597             if (!component.isVariableLength())
598                 return null;
599             PipeRun pipeRun = component.getPipeRun();
600             Vector3d sStart = new Vector3d();
601             Vector3d sEnd = new Vector3d();
602             component.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
603             
604             if (MathTools.distance(sStart, sEnd) < (pipeRun.getPipeDiameter()*0.5))
605                 return null;
606             
607         
608         Vector3d p = MathTools.closestPointOnEdge(new Vector3d(pos), sStart, sEnd);
609         if (p == sStart) {
610             Vector3d v = new Vector3d(sEnd);
611             v.sub(sStart);
612             v.normalize();
613             v.scale(component.getPipeRun().getPipeDiameter()*0.5);
614             p.add(v);
615         } else if (p == sEnd) {
616             Vector3d v = new Vector3d(sStart);
617             v.sub(sEnd);
618             v.normalize();
619             v.scale(component.getPipeRun().getPipeDiameter()*0.5);
620             p.add(v);
621         }
622             
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);
631         return branchSplit;
632     }
633 }