]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java
White space clean-up
[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 }