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