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