]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java
Merge "Up-to-date resource classes"
[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                 return equipment;
207         }
208         
209         
210         
211         public static Nozzle createDefaultNozzle(P3DRootNode root, Equipment equipment) throws Exception {
212                 return createNozzle(root, equipment, new Item(Plant3D.URIs.Builtin_Nozzle, "Nozzle"));
213         }
214         
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());
219                 nozzle.setName(n);
220                 PipeRun pipeRun = new PipeRun();
221                 n = root.getUniqueName("PipeRun");
222                 pipeRun.setName(n);
223                 nozzle.setPipeRun(pipeRun);
224                 
225                 equipment.addChild(nozzle);
226                 root.addChild(pipeRun);
227                 // root.getNodeMap().commit("Add nozzle " + n);
228                 return nozzle;
229         }
230         
231         public static class InsertInstruction {
232                 public String typeUri;
233                 
234                 public PositionType position = PositionType.NEXT;
235                 public PositionType insertPosition = PositionType.NEXT;
236                 
237                 // Reducer requires pipe specs
238                 public Double diameter;
239                 public Double turnRadius;
240                 
241                 // Variable length 
242                 public Double length;
243                 
244                 // Variable angle
245                 public Double angle;
246
247                 public String getTypeUri() {
248                         return typeUri;
249                 }
250
251                 public void setTypeUri(String typeUri) {
252                         this.typeUri = typeUri;
253                 }
254
255                 public PositionType getPosition() {
256                         return position;
257                 }
258
259                 public void setPosition(PositionType position) {
260                         this.position = position;
261                 }
262
263                 public PositionType getInsertPosition() {
264                         return insertPosition;
265                 }
266
267                 public void setInsertPosition(PositionType insertPosition) {
268                         this.insertPosition = insertPosition;
269                 }
270
271                 public Double getDiameter() {
272                         return diameter;
273                 }
274
275                 public void setDiameter(Double diameter) {
276                         this.diameter = diameter;
277                 }
278
279                 public Double getTurnRadius() {
280                         return turnRadius;
281                 }
282
283                 public void setTurnRadius(Double turnRadius) {
284                         this.turnRadius = turnRadius;
285                 }
286
287                 public Double getLength() {
288                         return length;
289                 }
290
291                 public void setLength(Double length) {
292                         this.length = length;
293                 }
294
295                 public Double getAngle() {
296                         return angle;
297                 }
298
299                 public void setAngle(Double angle) {
300                         this.angle = angle;
301                 }
302
303         }
304         
305         public static PipelineComponent addComponent(P3DRootNode root, PipelineComponent component,  InsertInstruction inst) throws Exception {
306                 
307                 PipelineComponent newComponent = ComponentUtils.createComponent(root, inst.typeUri);
308                 PipeControlPoint newPcp = newComponent.getControlPoint();
309                 
310                 PipeControlPoint toPcp = component.getControlPoint();
311                 PipeRun pipeRun = toPcp.getPipeRun();
312                 
313                 String typeName = names.get(inst.typeUri);
314                 if (typeName == null)
315                         typeName = "Component";
316                 
317                 Vector3d dir = null;
318                 Vector3d pos = null;
319         
320                 PositionType position = inst.position;
321                 PositionType insertPosition = inst.insertPosition;
322                 boolean lengthAdjustable = false;
323                 if (newComponent instanceof InlineComponent) {
324                         lengthAdjustable = ((InlineComponent)newComponent).isVariableLength(); 
325                 }
326                 boolean insertAdjustable = false;
327                 if (component instanceof InlineComponent) {
328                         insertAdjustable = ((InlineComponent)component).isVariableLength();
329                 }
330                 boolean sizeChange = false;
331                 if (newComponent instanceof InlineComponent) {
332                         sizeChange = ((InlineComponent)newComponent).isSizeChange();
333                 }
334                 
335                 if (toPcp.isInline()) {
336                         switch (position) {
337                         case NEXT: 
338                                 if (toPcp.isDualInline()) {
339                                         toPcp = toPcp.getSubPoint().get(0);
340                                         pipeRun = toPcp.getPipeRun();
341                                 }
342                                 
343                                 break;
344                         case PREVIOUS:
345                                 if (toPcp.isDualSub()) {
346                                         toPcp = toPcp.parent;
347                                         pipeRun = toPcp.getPipeRun();
348                                 }
349                                 break;
350                         }
351                         Vector3d start = new Vector3d();
352                         Vector3d end = new Vector3d();
353                         dir = new Vector3d();
354                         toPcp.getInlineControlPointEnds(start, end, dir);
355                         dir.normalize();
356                         switch (position) {
357                         case NEXT:
358                                 pos = new Vector3d(end);
359                                 break;
360                         case PREVIOUS:
361                                 pos = new Vector3d(start);
362                                 break;
363                         case SPLIT:
364                                 pos = new Vector3d(toPcp.getWorldPosition());
365                                 break;
366                         }
367
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());
377                                 pos.add(v);
378                         } else {
379                                 if (insertPosition == PositionType.NEXT) {
380                                         Vector3d v = new Vector3d(dir);
381                                         v.scale(toPcp.getInlineLength());
382                                         pos.add(v);
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);  
387                                         pos.add(v);
388                                 }
389                         }
390                 }
391                 
392                 
393                 if (!sizeChange) {
394                         String name = component.getPipeRun().getUniqueName(typeName);
395                         newComponent.setName(name);
396
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);
403                         }
404                         
405                         newComponent.updateParameters();
406                         
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)
412                                         v.set(0, 0, 0);
413                                 else if (insertPosition == PositionType.PREVIOUS)
414                                         v.scale(-newComponent.getControlPoint().getInlineLength());
415                         } else {
416                                 v.scale(newComponent.getControlPoint().getInlineLength());
417                         }
418                         switch (position) {
419                         case NEXT:
420                                 pos.add(v);
421                                 break;
422                         case PREVIOUS:
423                                 pos.sub(v);
424                                 break;
425                         case SPLIT:
426                                 break;
427                         }
428                         
429                         switch (position) {
430                         case NEXT: 
431                                 if (toPcp.isDualInline())
432                                         toPcp = toPcp.getSubPoint().get(0);
433                                 newPcp.insert(toPcp, Direction.NEXT);
434                                 newPcp.setWorldPosition(pos);
435                                 break;
436                         case PREVIOUS:
437                                 if (toPcp.isDualSub())
438                                         toPcp = toPcp.parent;
439                                 newPcp.insert(toPcp, Direction.PREVIOUS);
440                                 newPcp.setWorldPosition(pos);
441                                 break;
442                         case SPLIT:
443                                 PipingRules.splitVariableLengthComponent(newComponent, (InlineComponent)component, true);
444                         }
445                 } else {
446                         PipeRun other = new PipeRun();
447                         String n = root.getUniqueName("PipeRun");
448                         other.setName(n);
449                         other.setPipeDiameter(inst.diameter);
450                         other.setTurnRadius(inst.turnRadius);
451                         root.addChild(other);
452                         
453                         
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);
458                         }
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);
464                         switch (position) {
465                         case NEXT:
466                                 pos.add(v);
467                                 break;
468                         case PREVIOUS:
469                                 pos.sub(v);
470                                 break;
471                         case SPLIT:
472                                 break;
473                         }
474                         newPcp.setWorldPosition(pos);
475                         
476                 }
477                                 
478                 
479                 return newComponent;
480         }
481         public static boolean connect(PipelineComponent current, PipelineComponent endTo) throws Exception {
482                 return connect(current, endTo, null, null);
483         }
484         
485         /**
486          * Connects component to another component
487          * @param current
488          * @param endTo
489          * @param endType
490          * @param position
491          * @return
492          * @throws Exception
493          */
494         public static boolean connect(PipelineComponent current, PipelineComponent endTo, PositionType endType, Vector3d position) throws Exception{
495                 PipeControlPoint endCP = endTo.getControlPoint();
496                 boolean reversed;
497                 if (current.getNext() == null)
498                         reversed = false;
499                 else if (current.getPrevious() == null)
500                         reversed = true;
501                 else
502                         return false;
503                 
504                 PipeRun pipeRun = current.getPipeRun();
505                 P3DRootNode root = (P3DRootNode)current.getRootNode();
506                 PipeControlPoint currentCP = current.getControlPoint();
507                 
508                 if (endType == null || endType == PositionType.NEXT || endType == PositionType.PREVIOUS) {
509                         
510                         
511                         
512                         boolean requiresReverse = false;
513                         if (!reversed && endCP.getPrevious() != null) {
514                                 if (endCP.getNext() != null)
515                                         return false;
516                                 requiresReverse = true;
517                         } else if (reversed && endCP.getNext() != null) {
518                                 if (endCP.getPrevious() != null)
519                                         return false;
520                                 requiresReverse = true;
521                         }
522                         PipeRun other = endCP.getPipeRun();
523                         boolean mergeRuns = other == null ? true : pipeRun.equalSpecs(other);
524                         
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);
529                                 
530                         }
531                         if (mergeRuns) {
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);
538                                         } else {
539                                                 endTo.setPipeRun(pipeRun);
540                                         }
541                                 }
542                                 if (!reversed) {
543                                         currentCP.setNext(endCP);
544                                         endCP.setPrevious(currentCP);
545                                 } else {
546                                         currentCP.setPrevious(endCP);
547                                         endCP.setNext(currentCP);
548                                 }
549                         } else {
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);
554                                 
555                                 Vector3d endPos = endCP.getWorldPosition();
556                                 Vector3d currentPos = currentCP.getWorldPosition();
557                                 Vector3d v = new Vector3d(endPos);
558                                 v.sub(currentPos);
559                                 v.scale(0.5);
560                                 v.add(currentPos);
561                                 
562                                 PipingRules.addSizeChange(reversed, pipeRun, other, reducer, currentCP, endCP);
563                                 
564                                 pcp.setWorldPosition(v);
565                                 reducer.updateParameters();
566                         }
567                         PipingRules.positionUpdate(endCP);
568                         return true;
569                         
570                 } else if (endType == PositionType.SPLIT) {
571                         InlineComponent branchSplit = createBranchSplit((InlineComponent)endTo, position);
572                         if (branchSplit == null)
573                                 return false;
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());
580                                                 
581                         
582                         if(!reversed) {
583                                 pcp.setPrevious(currentCP);
584                                 currentCP.setNext(pcp);
585                         } else {
586                                 pcp.setNext(currentCP);
587                                 currentCP.setPrevious(pcp);
588                         }
589                         PipingRules.positionUpdate(endCP);
590                         return true;
591                 }
592                 return false;
593         }
594         
595         public static InlineComponent createBranchSplit(InlineComponent component, Vector3d pos) throws Exception{
596                 if (!component.isVariableLength())
597                         return null;
598                 PipeRun pipeRun = component.getPipeRun();
599                 Vector3d sStart = new Vector3d();
600                 Vector3d sEnd = new Vector3d();
601                 component.getControlPoint().getInlineControlPointEnds(sStart, sEnd);
602                 
603                 if (MathTools.distance(sStart, sEnd) < (pipeRun.getPipeDiameter()*0.5))
604                         return null;
605                 
606                 
607                 Vector3d p = MathTools.closestPointOnEdge(new Vector3d(pos), sStart, sEnd);
608                 if (p == sStart) {
609                         Vector3d v = new Vector3d(sEnd);
610                         v.sub(sStart);
611                         v.normalize();
612                         v.scale(component.getPipeRun().getPipeDiameter()*0.5);
613                         p.add(v);
614                 } else if (p == sEnd) {
615                         Vector3d v = new Vector3d(sStart);
616                         v.sub(sEnd);
617                         v.normalize();
618                         v.scale(component.getPipeRun().getPipeDiameter()*0.5);
619                         p.add(v);
620                 }
621                 
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);
630                 return branchSplit;
631         }
632 }