]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java
Preliminary example of creating pipes with elbow coordinates
[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                 
342                 break;
343             case PREVIOUS:
344                 if (toPcp.isDualSub())
345                     toPcp = toPcp.parent;
346             }
347             Vector3d start = new Vector3d();
348             Vector3d end = new Vector3d();
349             dir = new Vector3d();
350             toPcp.getInlineControlPointEnds(start, end, dir);
351             dir.normalize();
352            switch (position) {
353             case NEXT:
354                 pos = new Vector3d(end);
355                 break;
356             case PREVIOUS:
357                 pos = new Vector3d(start);
358                 break;
359             case SPLIT:
360                 pos = new Vector3d(toPcp.getWorldPosition());
361                 break;
362             }
363            
364         } else if (toPcp.isDirected()) {
365             dir = new Vector3d(toPcp.getDirection(Direction.NEXT));
366             pos = new Vector3d(toPcp.getWorldPosition());
367         } else if (toPcp.isTurn() && toPcp.isFixed()) {
368             dir = new Vector3d(toPcp.getDirection(position == PositionType.NEXT ? Direction.NEXT : Direction.PREVIOUS));
369             pos = new Vector3d(toPcp.getWorldPosition());
370             if (!lengthAdjustable) {
371                 Vector3d v = new Vector3d(dir);
372                 v.scale(toPcp.getInlineLength());
373                 pos.add(v);
374             } else {
375                 if (insertPosition == PositionType.NEXT) {
376                     Vector3d v = new Vector3d(dir);
377                     v.scale(toPcp.getInlineLength());
378                     pos.add(v);
379                 } else if (insertPosition == PositionType.SPLIT) {
380                     // scale 0.5*length so that we don't remove the length twice from the new component
381                     Vector3d v = new Vector3d(dir);
382                     v.scale(toPcp.getInlineLength()*0.5);  
383                     pos.add(v);
384                 }
385             }
386         }
387         
388         
389         if (!sizeChange) {
390             String name = component.getPipeRun().getUniqueName(typeName);
391             newComponent.setName(name);
392
393             pipeRun.addChild(newComponent);
394             // TODO: these options are not stored into DB. Should they?!
395             if (newComponent instanceof InlineComponent && ((InlineComponent)newComponent).isVariableLength()) {
396                 newPcp.setLength(inst.length);
397             } else if (newComponent instanceof TurnComponent && ((TurnComponent)newComponent).isVariableAngle()) {
398                 newPcp.setTurnAngle(inst.angle);
399             }
400             
401             newComponent.updateParameters();
402             
403             Vector3d v = new Vector3d(dir);
404             if (insertAdjustable) {
405                 if (insertPosition == PositionType.NEXT)
406                     v.scale(newComponent.getControlPoint().getInlineLength());
407                 else if (insertPosition == PositionType.SPLIT)
408                     v.set(0, 0, 0);
409                 else if (insertPosition == PositionType.PREVIOUS)
410                     v.scale(-newComponent.getControlPoint().getInlineLength());
411             } else {
412                 v.scale(newComponent.getControlPoint().getInlineLength());
413             }
414             switch (position) {
415             case NEXT:
416                 pos.add(v);
417                 break;
418             case PREVIOUS:
419                 pos.sub(v);
420                 break;
421             case SPLIT:
422                 break;
423             }
424             
425             switch (position) {
426             case NEXT: 
427                 if (toPcp.isDualInline())
428                     toPcp = toPcp.getSubPoint().get(0);
429                 newPcp.insert(toPcp, Direction.NEXT);
430                 newPcp.setWorldPosition(pos);
431                 break;
432             case PREVIOUS:
433                 if (toPcp.isDualSub())
434                     toPcp = toPcp.parent;
435                 newPcp.insert(toPcp, Direction.PREVIOUS);
436                 newPcp.setWorldPosition(pos);
437                 break;
438             case SPLIT:
439                 PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
440             }
441         } else {
442             PipeRun other = new PipeRun();
443             String n = root.getUniqueName("PipeRun");
444             other.setName(n);
445             other.setPipeDiameter(inst.diameter);
446             other.setTurnRadius(inst.turnRadius);
447             root.addChild(other);
448             
449             
450             if (position == PositionType.NEXT) {
451                 PipingRules.addSizeChange(false, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
452             } else if (position == PositionType.PREVIOUS){
453                 PipingRules.addSizeChange(true, pipeRun, other, (InlineComponent)newComponent, toPcp, null);
454             }
455             newPcp.setWorldPosition(pos);
456             // TODO : chicken-egg problem
457             newComponent.updateParameters();
458             Vector3d v = new Vector3d(dir);
459             v.scale(newComponent.getControlPoint().getLength()*0.5);
460             switch (position) {
461             case NEXT:
462                 pos.add(v);
463                 break;
464             case PREVIOUS:
465                 pos.sub(v);
466                 break;
467             case SPLIT:
468                 break;
469             }
470             newPcp.setWorldPosition(pos);
471             
472         }
473                     
474                
475             return newComponent;
476         }
477         public static boolean connect(PipelineComponent current, PipelineComponent endTo) throws Exception {
478             return connect(current, endTo, null, null);
479         }
480         
481         /**
482          * Connects component to another component
483          * @param current
484          * @param endTo
485          * @param endType
486          * @param position
487          * @return
488          * @throws Exception
489          */
490         public static boolean connect(PipelineComponent current, PipelineComponent endTo, PositionType endType, Vector3d position) throws Exception{
491             PipeControlPoint endCP = endTo.getControlPoint();
492             boolean reversed;
493             if (current.getNext() == null)
494                 reversed = false;
495             else if (current.getPrevious() == null)
496                 reversed = true;
497             else
498                 return false;
499             
500             PipeRun pipeRun = current.getPipeRun();
501             P3DRootNode root = (P3DRootNode)current.getRootNode();
502             PipeControlPoint currentCP = current.getControlPoint();
503             
504         if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
505             
506             
507             
508             boolean requiresReverse = false;
509             if (!reversed && endCP.getPrevious() != null) {
510                 if (endCP.getNext() != null)
511                     return false;
512                 requiresReverse = true;
513             } else if (reversed && endCP.getNext() != null) {
514                 if (endCP.getPrevious() != null)
515                     return false;
516                 requiresReverse = true;
517             }
518             PipeRun other = endCP.getPipeRun();
519             boolean mergeRuns = other == null ? true : pipeRun.equalSpecs(other);
520             
521             if (requiresReverse) {
522                 // Pipe line must be traversible with next/previous relations without direction change.
523                 // Now the component, where we are connecting the created pipeline is defined in different order.
524                 PipingRules.reverse(other);
525                 
526             }
527             if (mergeRuns) {
528                 // Runs have compatible specs and must be merged
529                 if (other != null && pipeRun != other)
530                     PipingRules.merge(pipeRun, other);
531                 else if (other == null) {
532                     if (!(endTo instanceof Nozzle)) {
533                         pipeRun.addChild(endTo);
534                     } else {
535                         endTo.setPipeRun(pipeRun);
536                     }
537                 }
538                 if (!reversed) {
539                     currentCP.setNext(endCP);
540                     endCP.setPrevious(currentCP);
541                 } else {
542                     currentCP.setPrevious(endCP);
543                     endCP.setNext(currentCP);
544                 }
545             } else {
546                 // Runs do not have compatible specs, and a reducer must be attached in between.
547                 InlineComponent reducer = ComponentUtils.createReducer(root);
548                 PipeControlPoint pcp = reducer.getControlPoint();
549                 PipeControlPoint ocp = pcp.getSubPoint().get(0);
550                 
551                 Vector3d endPos = endCP.getWorldPosition();
552                 Vector3d currentPos = currentCP.getWorldPosition();
553                 Vector3d v = new Vector3d(endPos);
554                 v.sub(currentPos);
555                 v.scale(0.5);
556                 v.add(currentPos);
557                 
558                 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
559                 
560                 pcp.setWorldPosition(v);
561                 reducer.updateParameters();
562             }
563             PipingRules.positionUpdate(endCP);
564             return true;
565             
566         } else if (endType == PositionType.SPLIT) {
567             InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, position);
568             if (branchSplit == null)
569                 return false;
570             PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
571             PipeControlPoint pcp = new PipeControlPoint(branchSplit,pipeRun);
572             branchSplitCP.children.add(pcp);
573             pcp.parent = branchSplitCP;
574             pcp.setWorldOrientation(branchSplitCP.getWorldOrientation());
575             pcp.setWorldPosition(branchSplitCP.getWorldPosition());
576                         
577             
578             if(!reversed) {
579                 pcp.setPrevious(currentCP);
580                 currentCP.setNext(pcp);
581             } else {
582                 pcp.setNext(currentCP);
583                 currentCP.setPrevious(pcp);
584             }
585             PipingRules.positionUpdate(endCP);
586             return true;
587         }
588         return false;
589         }
590         
591         public static InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
592             if (!component.isVariableLength())
593                 return null;
594             PipeRun pipeRun = component.getPipeRun();
595             Vector3d sStart = new Vector3d();
596             Vector3d sEnd = new Vector3d();
597             component.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
598             
599             if (MathTools.distance(sStart, sEnd) < (pipeRun.getPipeDiameter()*0.5))
600                 return null;
601             
602         
603         Vector3d p = MathTools.closestPointOnEdge(new Vector3d(pos), sStart, sEnd);
604         if (p == sStart) {
605             Vector3d v = new Vector3d(sEnd);
606             v.sub(sStart);
607             v.normalize();
608             v.scale(component.getPipeRun().getPipeDiameter()*0.5);
609             p.add(v);
610         } else if (p == sEnd) {
611             Vector3d v = new Vector3d(sStart);
612             v.sub(sEnd);
613             v.normalize();
614             v.scale(component.getPipeRun().getPipeDiameter()*0.5);
615             p.add(v);
616         }
617             
618             P3DRootNode root = (P3DRootNode)component.getRootNode();
619         InlineComponent branchSplit = ComponentUtils.createBranchSplit(root);
620         String branchName = component.getPipeRun().getUniqueName("Branch");
621         branchSplit.setName(branchName);
622         component.getPipeRun().addChild(branchSplit);
623         PipeControlPoint branchSplitCP = branchSplit.getControlPoint();
624         branchSplitCP.setWorldPosition(p);
625         PipingRules.splitVariableLengthComponent(branchSplit, component, false);
626         return branchSplit;
627     }
628 }