]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java
28e4ad71f12951eb9237ef2b2514ae3c12047413
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / scenegraph / PipelineComponent.java
1 package org.simantics.plant3d.scenegraph;
2
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.Map;
6 import java.util.Map.Entry;
7
8 import javax.vecmath.Quat4d;
9 import javax.vecmath.Tuple3d;
10 import javax.vecmath.Vector3d;
11
12 import org.simantics.g3d.math.MathTools;
13 import org.simantics.g3d.property.annotations.CompoundGetPropertyValue;
14 import org.simantics.g3d.property.annotations.CompoundSetPropertyValue;
15 import org.simantics.g3d.property.annotations.GetPropertyValue;
16 import org.simantics.g3d.property.annotations.PropertyContributor;
17 import org.simantics.objmap.graph.annotations.CompoundRelatedGetValue;
18 import org.simantics.objmap.graph.annotations.CompoundRelatedSetValue;
19 import org.simantics.objmap.graph.annotations.RelatedGetObj;
20 import org.simantics.objmap.graph.annotations.RelatedSetObj;
21 import org.simantics.plant3d.ontology.Plant3D;
22 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint;
23 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction;
24 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PointType;
25 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
26 import org.simantics.plant3d.scenegraph.controlpoint.PipingRules;
27
28 /**
29  * 
30  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
31  *
32  */
33 @PropertyContributor
34 public abstract class PipelineComponent extends GeometryNode {
35     
36     private static boolean DEBUG = false;
37
38         
39         private PipeRun pipeRun;
40         private PipeRun alternativePipeRun;
41         private PipelineComponent next;
42         private PipelineComponent previous;
43         
44         public PipeRun getPipeRun() {
45                 return pipeRun;
46         }
47         
48         /**
49          * Sets the pipe run.
50          * 
51          * With in-line,turn, and end components, the pipe run is the parent object in the scene-graph.
52          * With nozzles, the pipe run setting is explicit (nozzle has to be linked to the piperun, since the parent object is equipment).
53          * With size change components (in-line), there is also alternative pipe run, which must match the next component's pipe run.
54          * 
55          * @param pipeRun
56          */
57         public void setPipeRun(PipeRun pipeRun) {
58                 if (pipeRun == this.pipeRun)
59                         return;
60                 this.pipeRun = pipeRun;
61                 if (getControlPoint() != null) {
62                         getControlPoint().deattach();
63                         if (pipeRun != null) {
64                                 pipeRun.addChild(getControlPoint());
65                         }
66                 }
67                 updateParameters();
68         }
69         
70         @RelatedGetObj(Plant3D.URIs.HasAlternativePipeRun)
71         public PipeRun getAlternativePipeRun() {
72                 return alternativePipeRun;
73         }
74         
75         @RelatedSetObj(Plant3D.URIs.HasAlternativePipeRun)
76         public void setAlternativePipeRun(PipeRun pipeRun) {
77                 if (this.alternativePipeRun == pipeRun)
78                         return;
79                 this.alternativePipeRun = pipeRun;
80                 if (getControlPoint().isDualInline()) {
81                         PipeControlPoint sub = getControlPoint().getSubPoint().get(0);
82                         if (sub.getParent() != this.alternativePipeRun)
83                                 this.alternativePipeRun.addChild(sub);
84                 }
85                 firePropertyChanged(Plant3D.URIs.HasAlternativePipeRun);
86         }
87         
88         @Override
89         public void updateParameters() {
90                 setParameterMap(updateParameterMap());
91                 super.updateParameters();
92         }
93         
94         @Override
95     @CompoundRelatedGetValue(objRelation=Plant3D.URIs.hasParameter,objType=Plant3D.URIs.Parameter,valRelation=Plant3D.URIs.hasParameterValue)
96     @CompoundGetPropertyValue(name="Parameters",tabId="Parameters",value="parameters")
97     public Map<String, Object> getParameterMap() {
98         return super.getParameterMap();
99     }
100         
101     @Override
102     @CompoundRelatedSetValue(Plant3D.URIs.hasParameter)
103     public void setParameterMap(Map<String, Object> parameters) {
104         super.setParameterMap(parameters);
105     }
106     
107     @CompoundGetPropertyValue(name="Parameters",tabId="Parameters",value="parameters")
108     public Map<String,Object> getParameterMapUI() {
109         // TODO : how to filter parameters that are calculated by geometry provider?
110         Map<String,Object> map = new HashMap<String, Object>(getParameterMap());
111         map.remove("radius");
112         return map;
113     }
114     
115     @CompoundSetPropertyValue(value="parameters")
116     public void setParameterMapUI(Map<String, Object> parameters) { 
117         Map<String, Object> curr = getParameterMap();
118         for (Entry<String, Object> entry : curr.entrySet()) {
119             if (!parameters.containsKey(entry.getKey()))
120                 parameters.put(entry.getKey(), entry.getValue());
121         }
122         setParameterMap(parameters);
123     }
124         
125         public abstract void setType(String typeURI) throws Exception;
126         
127         @RelatedGetObj(Plant3D.URIs.HasNext)
128         public PipelineComponent getNext() {
129                 return next;
130         }
131         
132         @RelatedSetObj(Plant3D.URIs.HasNext)
133         public void setNext(PipelineComponent comp) {
134                 if (next == comp)
135                         return;
136                 if (this.next != null)
137                         this.next._removeRef(this);
138                 this.next = comp;
139                 this.syncnext = false;
140                 if (DEBUG) System.out.println(this + " next " + comp);
141                 syncNext();
142                 firePropertyChanged(Plant3D.URIs.HasNext);
143                 if (comp != null)
144                         comp.sync();
145                 
146         }
147         
148         
149         @RelatedGetObj(Plant3D.URIs.HasPrevious)
150         public PipelineComponent getPrevious() {
151                 return previous;
152         }
153         
154         @RelatedSetObj(Plant3D.URIs.HasPrevious)
155         public void setPrevious(PipelineComponent comp) {
156                 if (previous == comp)
157                         return;
158                 if (this.previous != null)
159                         this.previous._removeRef(this);
160                 this.previous = comp;
161                 this.syncprev = false;
162                 if (DEBUG) System.out.println(this + " prev " + comp);
163                 syncPrevious();
164                 firePropertyChanged(Plant3D.URIs.HasPrevious);
165                 if (comp != null)
166                         comp.sync();
167                 
168         }
169         private PipelineComponent branch0;
170         
171         @RelatedGetObj(Plant3D.URIs.HasBranch0)
172         public PipelineComponent getBranch0() {
173                 return branch0;
174         }
175         
176         @RelatedSetObj(Plant3D.URIs.HasBranch0)
177         public void setBranch0(PipelineComponent comp) {
178                 if (branch0 == comp)
179                         return;
180                 if (this.branch0 != null)
181                         this.branch0._removeRef(this);
182                 this.branch0 = comp;
183                 this.syncbr0 = false;
184                 if (DEBUG) System.out.println(this + " br0 " + comp);
185                 syncBranch0();
186                 firePropertyChanged(Plant3D.URIs.HasBranch0);
187                 if (comp != null)
188                         comp.sync();
189         }
190
191         @GetPropertyValue(name="Previous",tabId="Debug",value=Plant3D.URIs.HasPrevious)
192         public String getPreviousDebug() {
193                 if (previous == null)
194                         return null;
195                 return previous.getName();
196         }
197         
198         @GetPropertyValue(name="Next",tabId="Debug",value=Plant3D.URIs.HasNext)
199         public String getNextDebug() {
200                 if (next == null)
201                         return null;
202                 return next.getName();
203         }
204         
205         @GetPropertyValue(name="Branch0",tabId="Debug",value=Plant3D.URIs.HasBranch0)
206         public String getBR0Debug() {
207                 if (branch0 == null)
208                         return null;
209                 return branch0.getName();
210         }
211
212         
213         
214         private PipeControlPoint getBranchPoint() {
215                 PipeControlPoint branchPoint;
216                 if (getControlPoint().getSubPoint().size() > 0) {
217                         branchPoint = getControlPoint().getSubPoint().get(0);
218                 } else {
219                         if (branch0.getPipeRun() == null)
220                                 return null;
221                         branchPoint = new PipeControlPoint(this,branch0.getPipeRun());
222                         branchPoint.setFixed(false);
223                         branchPoint.setType(PointType.END);
224                         branchPoint.parent = getControlPoint();
225                         getControlPoint().children.add(branchPoint);
226                         branchPoint.setWorldOrientation(getControlPoint().getWorldOrientation());
227                         branchPoint.setWorldPosition(getControlPoint().getWorldPosition());
228                 }
229                 return branchPoint;
230         }
231         
232         private boolean _connectNext(PipeControlPoint pcp, PipeControlPoint nextPCP) {
233                 if (nextPCP == null)
234                         return false;
235                 if (pcp.getNext() != nextPCP) {
236                         pcp.setNext(nextPCP);
237                 }
238                 if (pcp.isDualInline()) {
239                         PipeControlPoint sub = pcp.getSubPoint().get(0);
240                         if (sub.getNext() != nextPCP)
241                                 sub.setNext(nextPCP);
242                 }
243                 return true;
244         }
245         
246         private boolean  _connectPrev(PipeControlPoint pcp, PipeControlPoint prevPCP) {
247                 if (prevPCP == null)
248                         return false;
249                 if (prevPCP.isDualInline())
250                         prevPCP = prevPCP.getSubPoint().get(0);
251                 if (pcp.getPrevious() != prevPCP) {
252                         pcp.setPrevious(prevPCP);
253                 }
254                 if (pcp.isDualInline()) {
255                         PipeControlPoint sub = pcp.getSubPoint().get(0);
256                         if (sub.getPrevious() != prevPCP)
257                                 sub.setPrevious(prevPCP);
258                 }
259                 return true;
260         }
261         
262         // When link to a component is removed, also link to the other direction must be removed at the same time, or
263         // Control point structure is left into illegal state.
264         private void _removeRef(PipelineComponent comp) {
265                 if (next == comp) {
266                         next = null;
267                         syncnext = false;
268                         syncNext();
269                 } else if (previous == comp) {
270                         previous = null;
271                         syncprev = false;
272                         syncPrevious();
273                 } else if (branch0 == comp) {
274                         branch0 = null;
275                         syncbr0 = false;
276                         syncBranch0();
277                 }
278         }
279         
280         boolean syncnext = false;
281         private void syncNext() {
282                 if (syncnext)
283                         return;
284                 syncnext = _syncNext();
285         }
286         
287         
288         private boolean _syncNext() {
289                 PipeControlPoint pcp = getControlPoint();
290                 if (pcp != null) {
291                         
292                         if (next != null ) {
293                                 if (next.getControlPoint() != null) {
294                                         
295                                         // TODO, relying that the other direction is connected.
296                                         boolean nxt = next.getPrevious() == this;
297                                         boolean br0 = next.getBranch0() == this;
298                                         if (nxt){
299                                                 return _connectNext(pcp, next.getControlPoint());       
300                                         } else if (br0) {
301                                                 return _connectNext(pcp, next.getBranchPoint());
302                                         } else {
303                                                 return false;
304                                         }
305                                 } else {
306                                         return false;
307                                 }
308                                 
309                         } else if (pcp.getNext() != null) {
310                                 pcp.setNext(null);
311                                 return true;
312                         }
313                 } else {
314                         return false;
315                 }
316                 return true;
317         }
318         
319         boolean syncprev = false;
320         private void syncPrevious() {
321                 if (syncprev)
322                         return;
323                 syncprev = _syncPrevious();
324         }
325         
326         private boolean _syncPrevious() {
327                 PipeControlPoint pcp = getControlPoint();
328                 if (pcp != null) {
329                         if (previous != null ) {
330                                 if (previous.getControlPoint() != null) {
331                                         
332                                         // TODO, relying that the other direction is connected.
333                                         boolean prev = previous.getNext() == this;
334                                         boolean br0 = previous.getBranch0() == this;
335                                         if (prev){
336                                                 return _connectPrev(pcp, previous.getControlPoint());   
337                                         } else if (br0) {
338                                                 return _connectPrev(pcp, previous.getBranchPoint());
339                                         } else {
340                                                 return false;
341                                         }
342                                 } else {
343                                         return false;
344                                 }
345                                 
346                         } else if (pcp.getPrevious() != null) {
347                                 pcp.setPrevious(null);
348                                 return true;
349                         }
350                 } else {
351                         return false;
352                 }
353                 return true;
354         }
355         
356         boolean syncbr0 = false;
357         private void syncBranch0() {
358                 if (syncbr0)
359                         return;
360                 syncbr0 = _syncBranch0();
361         }
362         
363         private boolean _syncBranch0() {
364                 if (getControlPoint() != null) {
365                         if (getControlPoint().isDualInline()) {
366                                 branch0 = null;
367                                 return false;
368                         }
369                         if (branch0 != null) {
370                                 if (branch0.getControlPoint() != null) {
371                                         PipeControlPoint branchPoint = getBranchPoint();
372                                         if (branchPoint == null)
373                                                 return false;
374                                         PipeControlPoint pcp = branch0.getControlPoint();
375                                         // TODO, relying that the other direction is connected.
376                                         boolean next = branch0.getPrevious() == this; // this --> branch0
377                                         boolean prev = branch0.getNext() == this;
378                                         if (next) {
379                                                 _connectNext(branchPoint, pcp);
380                                         } else if (prev){
381                                                 _connectPrev(branchPoint, pcp); 
382                                         } else {
383                                                 return false;
384                                         }
385                                         
386                                 } else {
387                                         return false;
388                                 }
389                                 
390                         } else if (getControlPoint().getSubPoint().size() > 0) { // TODO : this may cause problems? (Removes branch point, before branch has been set?)
391                                 //getControlPoint().getSubPoint().get(0).remove();
392                                 //getControlPoint().children.clear();
393                                 return true;
394                         }
395                 } else {
396                         return false;
397                 }
398                 return true;
399         }
400         
401         public void sync() {
402                 syncPrevious();
403                 syncNext();
404                 syncBranch0();
405         }
406         
407         public void sync2() {
408 //              if (getControlPoint().isDualInline()) {
409 //                      PipeControlPoint sub = getControlPoint().getSubPoint().get(0);
410 //                      next.getControlPoint().getPipeRun().addChild(sub);
411 //              }
412                 getControlPoint()._setWorldOrientation(getWorldOrientation());
413                 getControlPoint()._setWorldPosition(getWorldPosition());
414         }
415         
416         public Map<String,Object> updateParameterMap() {
417                 return Collections.EMPTY_MAP;
418         }
419         
420         public abstract String getType();
421         public abstract PipeControlPoint getControlPoint();
422         
423         @Override
424         public void remove() {
425             if (DEBUG) System.out.println(this + " remove");
426                 PipeControlPoint pcp = getControlPoint();
427                 // Second check is needed, when remove process is initiated from control point.
428                 if (pcp != null && pcp.getPipelineComponent() != null) {
429                         pcp.remove();
430                 }
431                 super.remove();
432         }
433         
434         public void removeAndSplit() {
435             PipeControlPoint pcp = getControlPoint();
436         // Second check is needed, when remove process is initiated from control point.
437         if (pcp != null && pcp.getPipelineComponent() != null) {
438             pcp.removeAndSplit();
439         }
440         super.remove();
441         }
442
443         @Override
444         protected double[] getColor() {
445                 if (getControlPoint() == null || !getControlPoint().isFixed())
446                         return new double[]{0.7,0.7,0.7};
447                 else
448                         return new double[]{1.0,0.0,0.0};
449         }
450         
451         @Override
452         protected double[] getSelectedColor() {
453                 return new double[]{0.5,0,0.5};
454         }
455         
456         @Override
457         public void setOrientation(Quat4d orientation) {
458                 if (MathTools.equals(orientation, getOrientation()))
459                         return;
460                 super.setOrientation(orientation);
461                 if (getControlPoint() != null) {
462                         getControlPoint()._setWorldOrientation(getWorldOrientation());
463                         try {
464                                 PipingRules.requestUpdate(getControlPoint());
465                         } catch (Exception e) {
466                                 // TODO Auto-generated catch block
467                                 e.printStackTrace();
468                         }       
469                 }
470         }
471         
472         @Override
473         public void setPosition(Vector3d position) {
474                 if (MathTools.equals(position, getPosition()))
475                         return;
476                 super.setPosition(position);
477                 if (getControlPoint() != null) {
478                         getControlPoint()._setWorldPosition(getWorldPosition());
479                         try {
480                                 PipingRules.requestUpdate(getControlPoint());
481                         } catch (Exception e) {
482                                 // TODO Auto-generated catch block
483                                 e.printStackTrace();
484                         }
485                 }
486         }
487         
488         
489         public void _setWorldPosition(Vector3d position) {
490                 Vector3d localPos = getLocalPosition(position);
491                 super.setPosition(localPos);
492         }
493         
494         public void _setWorldOrientation(Quat4d orientation) {
495                 Quat4d localOr = getLocalOrientation(orientation);
496                 super.setOrientation(localOr);
497         }
498         
499         @GetPropertyValue(name="Flow Length", value="flowlength", tabId = "Default")
500         public Double getFlowLength() {
501                 PipeControlPoint pcp = getControlPoint(); 
502                 if (pcp == null)
503                         return null;
504                 switch (pcp.getType()) {
505                         case INLINE:
506                                 return pcp.getLength();
507                         case END:
508                                 return null;
509                         case TURN: {
510                                 double r = getPipeRun().getTurnRadius();
511                                 double a = pcp.getTurnAngle();
512                                 return a*r;
513                         }
514                         default:
515                                 return null;
516                 }
517         }
518         
519         public void getEnds(Tuple3d p1, Tuple3d p2) {
520                 getControlPoint().getControlPointEnds(p1, p2);
521         }
522         
523         public void getEndDirections(Tuple3d v1, Tuple3d v2) {
524                 getControlPoint().getEndDirections(v1, v2);
525         }
526         
527         public void getCentroid(Tuple3d p) {
528                 PipeControlPoint pcp = getControlPoint(); 
529                 if (pcp == null)
530                         throw new IllegalStateException("No centroid defined");
531                 
532                 switch (pcp.getType()) {
533                 case INLINE:
534                 case END:
535                         // Just return the world location
536                         if (!pcp.isSizeChange()) {
537                                 p.set(pcp.getWorldPosition());
538                                 return;
539                         }
540                         
541                         // Calculate center of mass for the frustum
542                         double r1 = getPipeRun().getPipeDiameter();
543                         double r2 = getAlternativePipeRun().getPipeDiameter();
544                         
545                         Vector3d p1 = new Vector3d(), p2 = new Vector3d();
546                         pcp.getInlineControlPointEnds(p1, p2);
547                         
548                         // Squared sum of radii
549                         double r12 = r1 + r2;
550                         r12 *= r12;
551                         
552                         // The larger of the radii form the base of a frustum
553                         double rmax = Math.max(r1, r2);
554                         
555                         // Relative distance from the base of the frustum
556                         double h = (r12 + 2*rmax*rmax) / (4 * (r12 - r1*r2));
557                         
558                         // Relative distance from p1 to p2
559                         if (r1 < r2)
560                                 h = 1 - h;
561                         
562                         p2.sub(p1);
563                         p1.scaleAdd(h, p2);
564                         
565                         p.set(p1);
566                         return;
567                 case TURN: {
568                         Vector3d loc = pcp.getRealPosition(PositionType.PREVIOUS);
569                         
570                         double r = getPipeRun().getTurnRadius();
571                         double a = pcp.getTurnAngle();
572                         double pipeRadius = pcp.getPipeRun().getPipeDiameter() / 2;
573                         
574                         // Unit vector in inlet flow direction
575                         Vector3d inletDir = pcp.getPathLegDirection(Direction.PREVIOUS);
576                         inletDir.scale(-1.0);
577                         inletDir.normalize();
578                         
579                         // Normal to both inletDir and turn axis in world coordinates
580                         Vector3d outletDir = pcp.getPathLegDirection(Direction.NEXT);
581                         Vector3d normal = new Vector3d(inletDir);
582                         normal.scaleAdd(-inletDir.dot(outletDir), outletDir);
583                         normal.normalize();
584                         
585                         // Location of turn axis
586                         Vector3d center = new Vector3d(normal);
587                         center.scaleAdd(r, loc);
588                         
589                         // Add vector components from axis to centroid
590                         double c = r + pipeRadius * pipeRadius / (4 * r);
591                         double c1 = c * Math.sin(a) / a;
592                         double c2 = c * (1 - Math.cos(a)) / a;
593                         normal.scale(-c1);
594                         inletDir.scale(c2);
595                         center.add(normal);
596                         center.add(inletDir);
597                 
598                         // Return value
599                         p.set(center);
600                         return;
601                 }
602                 default:
603                         throw new IllegalStateException("No centroid defined");
604                 }
605         }
606         
607         public double getVolume() {
608                 PipeControlPoint pcp = getControlPoint(); 
609                 if (pcp == null)
610                         throw new IllegalStateException("No centroid defined");
611                 
612                 double pipeRadius = getPipeRun().getPipeDiameter() / 2;
613                 
614                 switch (pcp.getType()) {
615                 case INLINE:
616                 case END:
617                         if (!pcp.isSizeChange()) {
618                                 // Just return the cylinder volume
619                                 return pcp.getLength() * Math.PI * pipeRadius * pipeRadius;
620                         }
621                         
622                         // Calculate center of mass for the frustum
623                         double r1 = pipeRadius;
624                         double r2 = getAlternativePipeRun().getPipeDiameter() / 2;
625                         return pcp.getLength() * Math.PI * (r1*r1 + r1*r2 + r2*r2) / 4;
626                 case TURN: {
627                         double r = getPipeRun().getTurnRadius();
628                         double a = pcp.getTurnAngle();
629                         return r * a * Math.PI * pipeRadius * pipeRadius;
630                 }
631                 default:
632                         throw new IllegalStateException("No centroid defined");
633                 }
634         }
635 }