]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java
90dba91d0282b748ec0c0c8be196a6651af102ea
[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                         firePropertyChanged(Plant3D.URIs.HasNext);
269                         syncNext();
270                 } else if (previous == comp) {
271                         previous = null;
272                         syncprev = false;
273                         firePropertyChanged(Plant3D.URIs.HasPrevious);
274                         syncPrevious();
275                 } else if (branch0 == comp) {
276                         branch0 = null;
277                         syncbr0 = false;
278                         firePropertyChanged(Plant3D.URIs.HasBranch0);
279                         syncBranch0();
280                 }
281         }
282         
283         boolean syncnext = false;
284         private void syncNext() {
285                 if (syncnext)
286                         return;
287                 syncnext = _syncNext();
288         }
289         
290         
291         private boolean _syncNext() {
292                 PipeControlPoint pcp = getControlPoint();
293                 if (pcp != null) {
294                         
295                         if (next != null ) {
296                                 if (next.getControlPoint() != null) {
297                                         
298                                         // TODO, relying that the other direction is connected.
299                                         boolean nxt = next.getPrevious() == this;
300                                         boolean br0 = next.getBranch0() == this;
301                                         if (nxt){
302                                                 return _connectNext(pcp, next.getControlPoint());       
303                                         } else if (br0) {
304                                                 return _connectNext(pcp, next.getBranchPoint());
305                                         } else {
306                                                 return false;
307                                         }
308                                 } else {
309                                         return false;
310                                 }
311                                 
312                         } else if (pcp.getNext() != null) {
313                                 pcp.setNext(null);
314                                 return true;
315                         }
316                 } else {
317                         return false;
318                 }
319                 return true;
320         }
321         
322         boolean syncprev = false;
323         private void syncPrevious() {
324                 if (syncprev)
325                         return;
326                 syncprev = _syncPrevious();
327         }
328         
329         private boolean _syncPrevious() {
330                 PipeControlPoint pcp = getControlPoint();
331                 if (pcp != null) {
332                         if (previous != null ) {
333                                 if (previous.getControlPoint() != null) {
334                                         
335                                         // TODO, relying that the other direction is connected.
336                                         boolean prev = previous.getNext() == this;
337                                         boolean br0 = previous.getBranch0() == this;
338                                         if (prev){
339                                                 return _connectPrev(pcp, previous.getControlPoint());   
340                                         } else if (br0) {
341                                                 return _connectPrev(pcp, previous.getBranchPoint());
342                                         } else {
343                                                 return false;
344                                         }
345                                 } else {
346                                         return false;
347                                 }
348                                 
349                         } else if (pcp.getPrevious() != null) {
350                                 pcp.setPrevious(null);
351                                 return true;
352                         }
353                 } else {
354                         return false;
355                 }
356                 return true;
357         }
358         
359         boolean syncbr0 = false;
360         private void syncBranch0() {
361                 if (syncbr0)
362                         return;
363                 syncbr0 = _syncBranch0();
364         }
365         
366         private boolean _syncBranch0() {
367                 if (getControlPoint() != null) {
368                         if (getControlPoint().isDualInline()) {
369                                 branch0 = null;
370                                 return false;
371                         }
372                         if (branch0 != null) {
373                                 if (branch0.getControlPoint() != null) {
374                                         PipeControlPoint branchPoint = getBranchPoint();
375                                         if (branchPoint == null)
376                                                 return false;
377                                         PipeControlPoint pcp = branch0.getControlPoint();
378                                         // TODO, relying that the other direction is connected.
379                                         boolean next = branch0.getPrevious() == this; // this --> branch0
380                                         boolean prev = branch0.getNext() == this;
381                                         if (next) {
382                                                 _connectNext(branchPoint, pcp);
383                                         } else if (prev){
384                                                 _connectPrev(branchPoint, pcp); 
385                                         } else {
386                                                 return false;
387                                         }
388                                         
389                                 } else {
390                                         return false;
391                                 }
392                                 
393                         } else if (getControlPoint().getSubPoint().size() > 0) { // TODO : this may cause problems? (Removes branch point, before branch has been set?)
394                                 //getControlPoint().getSubPoint().get(0).remove();
395                                 //getControlPoint().children.clear();
396                                 return true;
397                         }
398                 } else {
399                         return false;
400                 }
401                 return true;
402         }
403         
404         public void sync() {
405                 syncPrevious();
406                 syncNext();
407                 syncBranch0();
408         }
409         
410         public void sync2() {
411 //              if (getControlPoint().isDualInline()) {
412 //                      PipeControlPoint sub = getControlPoint().getSubPoint().get(0);
413 //                      next.getControlPoint().getPipeRun().addChild(sub);
414 //              }
415                 getControlPoint()._setWorldOrientation(getWorldOrientation());
416                 getControlPoint()._setWorldPosition(getWorldPosition());
417         }
418         
419         public Map<String,Object> updateParameterMap() {
420                 return Collections.EMPTY_MAP;
421         }
422         
423         public abstract String getType();
424         public abstract PipeControlPoint getControlPoint();
425         
426         @Override
427         public void remove() {
428             if (DEBUG) System.out.println(this + " remove");
429                 PipeControlPoint pcp = getControlPoint();
430                 // Second check is needed, when remove process is initiated from control point.
431                 if (pcp != null && pcp.getPipelineComponent() != null) {
432                         pcp.remove();
433                 }
434                 super.remove();
435         }
436         
437         public void removeAndSplit() {
438             PipeControlPoint pcp = getControlPoint();
439         // Second check is needed, when remove process is initiated from control point.
440         if (pcp != null && pcp.getPipelineComponent() != null) {
441             pcp.removeAndSplit();
442         }
443         super.remove();
444         }
445
446         @Override
447         protected double[] getColor() {
448                 if (getControlPoint() == null || !getControlPoint().isFixed())
449                         return new double[]{0.7,0.7,0.7};
450                 else
451                         return new double[]{1.0,0.0,0.0};
452         }
453         
454         @Override
455         protected double[] getSelectedColor() {
456                 return new double[]{0.5,0,0.5};
457         }
458         
459         @Override
460         public void setOrientation(Quat4d orientation) {
461                 if (MathTools.equals(orientation, getOrientation()))
462                         return;
463                 super.setOrientation(orientation);
464                 if (getControlPoint() != null) {
465                         getControlPoint()._setWorldOrientation(getWorldOrientation());
466                         try {
467                                 PipingRules.requestUpdate(getControlPoint());
468                         } catch (Exception e) {
469                                 // TODO Auto-generated catch block
470                                 e.printStackTrace();
471                         }       
472                 }
473         }
474         
475         @Override
476         public void setPosition(Vector3d position) {
477                 if (MathTools.equals(position, getPosition()))
478                         return;
479                 super.setPosition(position);
480                 if (getControlPoint() != null) {
481                         getControlPoint()._setWorldPosition(getWorldPosition());
482                         try {
483                                 PipingRules.requestUpdate(getControlPoint());
484                         } catch (Exception e) {
485                                 // TODO Auto-generated catch block
486                                 e.printStackTrace();
487                         }
488                 }
489         }
490         
491         
492         public void _setWorldPosition(Vector3d position) {
493                 Vector3d localPos = getLocalPosition(position);
494                 super.setPosition(localPos);
495         }
496         
497         public void _setWorldOrientation(Quat4d orientation) {
498                 Quat4d localOr = getLocalOrientation(orientation);
499                 super.setOrientation(localOr);
500         }
501         
502         @GetPropertyValue(name="Flow Length", value="flowlength", tabId = "Default")
503         public Double getFlowLength() {
504                 PipeControlPoint pcp = getControlPoint(); 
505                 if (pcp == null)
506                         return null;
507                 switch (pcp.getType()) {
508                         case INLINE:
509                                 return pcp.getLength();
510                         case END:
511                                 return null;
512                         case TURN: {
513                                 double r = getPipeRun().getTurnRadius();
514                                 double a = pcp.getTurnAngle();
515                                 return a*r;
516                         }
517                         default:
518                                 return null;
519                 }
520         }
521         
522         public void getEnds(Tuple3d p1, Tuple3d p2) {
523                 getControlPoint().getControlPointEnds(p1, p2);
524         }
525         
526         public void getEndDirections(Tuple3d v1, Tuple3d v2) {
527                 getControlPoint().getEndDirections(v1, v2);
528         }
529         
530         public void getCentroid(Tuple3d p) {
531                 PipeControlPoint pcp = getControlPoint(); 
532                 if (pcp == null)
533                         throw new IllegalStateException("No centroid defined");
534                 
535                 switch (pcp.getType()) {
536                 case INLINE:
537                 case END:
538                         // Just return the world location
539                         if (!pcp.isSizeChange()) {
540                                 p.set(pcp.getWorldPosition());
541                                 return;
542                         }
543                         
544                         // Calculate center of mass for the frustum
545                         double r1 = getPipeRun().getPipeDiameter();
546                         double r2 = getAlternativePipeRun().getPipeDiameter();
547                         
548                         Vector3d p1 = new Vector3d(), p2 = new Vector3d();
549                         pcp.getInlineControlPointEnds(p1, p2);
550                         
551                         // Squared sum of radii
552                         double r12 = r1 + r2;
553                         r12 *= r12;
554                         
555                         // The larger of the radii form the base of a frustum
556                         double rmax = Math.max(r1, r2);
557                         
558                         // Relative distance from the base of the frustum
559                         double h = (r12 + 2*rmax*rmax) / (4 * (r12 - r1*r2));
560                         
561                         // Relative distance from p1 to p2
562                         if (r1 < r2)
563                                 h = 1 - h;
564                         
565                         p2.sub(p1);
566                         p1.scaleAdd(h, p2);
567                         
568                         p.set(p1);
569                         return;
570                 case TURN: {
571                         Vector3d loc = pcp.getRealPosition(PositionType.PREVIOUS);
572                         
573                         double r = getPipeRun().getTurnRadius();
574                         double a = pcp.getTurnAngle();
575                         double pipeRadius = pcp.getPipeRun().getPipeDiameter() / 2;
576                         
577                         // Unit vector in inlet flow direction
578                         Vector3d inletDir = pcp.getPathLegDirection(Direction.PREVIOUS);
579                         inletDir.scale(-1.0);
580                         inletDir.normalize();
581                         
582                         // Normal to both inletDir and turn axis in world coordinates
583                         Vector3d outletDir = pcp.getPathLegDirection(Direction.NEXT);
584                         Vector3d normal = new Vector3d(inletDir);
585                         normal.scaleAdd(-inletDir.dot(outletDir), outletDir);
586                         normal.normalize();
587                         
588                         // Location of turn axis
589                         Vector3d center = new Vector3d(normal);
590                         center.scaleAdd(r, loc);
591                         
592                         // Add vector components from axis to centroid
593                         double c = r + pipeRadius * pipeRadius / (4 * r);
594                         double c1 = c * Math.sin(a) / a;
595                         double c2 = c * (1 - Math.cos(a)) / a;
596                         normal.scale(-c1);
597                         inletDir.scale(c2);
598                         center.add(normal);
599                         center.add(inletDir);
600                 
601                         // Return value
602                         p.set(center);
603                         return;
604                 }
605                 default:
606                         throw new IllegalStateException("No centroid defined");
607                 }
608         }
609         
610         public double getVolume() {
611                 PipeControlPoint pcp = getControlPoint(); 
612                 if (pcp == null)
613                         throw new IllegalStateException("No centroid defined");
614                 
615                 double pipeRadius = getPipeRun().getPipeDiameter() / 2;
616                 
617                 switch (pcp.getType()) {
618                 case INLINE:
619                 case END:
620                         if (!pcp.isSizeChange()) {
621                                 // Just return the cylinder volume
622                                 return pcp.getLength() * Math.PI * pipeRadius * pipeRadius;
623                         }
624                         
625                         // Calculate center of mass for the frustum
626                         double r1 = pipeRadius;
627                         double r2 = getAlternativePipeRun().getPipeDiameter() / 2;
628                         return pcp.getLength() * Math.PI * (r1*r1 + r1*r2 + r2*r2) / 4;
629                 case TURN: {
630                         double r = getPipeRun().getTurnRadius();
631                         double a = pcp.getTurnAngle();
632                         return r * a * Math.PI * pipeRadius * pipeRadius;
633                 }
634                 default:
635                         throw new IllegalStateException("No centroid defined");
636                 }
637         }
638 }