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