]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/PipelineComponent.java
Remove/Split action removes pipeline components without reconnecting
[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         public void removeAndSplit() {
393             PipeControlPoint pcp = getControlPoint();
394         // Second check is needed, when remove process is initiated from control point.
395         if (pcp != null && pcp.getPipelineComponent() != null) {
396             pcp.removeAndSplit();
397         }
398         super.remove();
399         }
400
401         @Override
402         protected double[] getColor() {
403                 if (getControlPoint() == null || !getControlPoint().isFixed())
404                         return new double[]{0.7,0.7,0.7};
405                 else
406                         return new double[]{1.0,0.0,0.0};
407         }
408         
409         @Override
410         protected double[] getSelectedColor() {
411                 return new double[]{0.5,0,0.5};
412         }
413         
414         @Override
415         public void setOrientation(Quat4d orientation) {
416                 if (MathTools.equals(orientation, getOrientation()))
417                         return;
418                 super.setOrientation(orientation);
419                 if (getControlPoint() != null) {
420                         getControlPoint()._setWorldOrientation(getWorldOrientation());
421                         try {
422                                 PipingRules.requestUpdate(getControlPoint());
423                         } catch (Exception e) {
424                                 // TODO Auto-generated catch block
425                                 e.printStackTrace();
426                         }       
427                 }
428         }
429         
430         @Override
431         public void setPosition(Vector3d position) {
432                 if (MathTools.equals(position, getPosition()))
433                         return;
434                 super.setPosition(position);
435                 if (getControlPoint() != null) {
436                         getControlPoint()._setWorldPosition(getWorldPosition());
437                         try {
438                                 PipingRules.requestUpdate(getControlPoint());
439                         } catch (Exception e) {
440                                 // TODO Auto-generated catch block
441                                 e.printStackTrace();
442                         }
443                 }
444         }
445         
446         
447         public void _setWorldPosition(Vector3d position) {
448                 Vector3d localPos = getLocalPosition(position);
449                 super.setPosition(localPos);
450         }
451         
452         public void _setWorldOrientation(Quat4d orientation) {
453                 Quat4d localOr = getLocalOrientation(orientation);
454                 super.setOrientation(localOr);
455         }
456         
457         @GetPropertyValue(name="Flow Length", value="flowlength", tabId = "Default")
458         public Double getFlowLength() {
459                 PipeControlPoint pcp = getControlPoint(); 
460                 if (pcp == null)
461                         return null;
462                 switch (pcp.getType()) {
463                         case INLINE:
464                                 return pcp.getLength();
465                         case END:
466                                 return null;
467                         case TURN: {
468                                 double r = getPipeRun().getTurnRadius();
469                                 double a = pcp.getTurnAngle();
470                                 return a*r;
471                         }
472                         default:
473                                 return null;
474                 }
475         }
476         
477         public void getEnds(Tuple3d p1, Tuple3d p2) {
478                 getControlPoint().getControlPointEnds(p1, p2);
479         }
480         
481         public void getEndDirections(Tuple3d v1, Tuple3d v2) {
482                 getControlPoint().getEndDirections(v1, v2);
483         }
484         
485         public void getCentroid(Tuple3d p) {
486                 PipeControlPoint pcp = getControlPoint(); 
487                 if (pcp == null)
488                         throw new IllegalStateException("No centroid defined");
489                 
490                 switch (pcp.getType()) {
491                 case INLINE:
492                 case END:
493                         // Just return the world location
494                         if (!pcp.isSizeChange()) {
495                                 p.set(pcp.getWorldPosition());
496                                 return;
497                         }
498                         
499                         // Calculate center of mass for the frustum
500                         double r1 = getPipeRun().getPipeDiameter();
501                         double r2 = getAlternativePipeRun().getPipeDiameter();
502                         
503                         Vector3d p1 = new Vector3d(), p2 = new Vector3d();
504                         pcp.getInlineControlPointEnds(p1, p2);
505                         
506                         // Squared sum of radii
507                         double r12 = r1 + r2;
508                         r12 *= r12;
509                         
510                         // The larger of the radii form the base of a frustum
511                         double rmax = Math.max(r1, r2);
512                         
513                         // Relative distance from the base of the frustum
514                         double h = (r12 + 2*rmax*rmax) / (4 * (r12 - r1*r2));
515                         
516                         // Relative distance from p1 to p2
517                         if (r1 < r2)
518                                 h = 1 - h;
519                         
520                         p2.sub(p1);
521                         p1.scaleAdd(h, p2);
522                         
523                         p.set(p1);
524                         return;
525                 case TURN: {
526                         Vector3d loc = pcp.getRealPosition(PositionType.PREVIOUS);
527                         
528                         double r = getPipeRun().getTurnRadius();
529                         double a = pcp.getTurnAngle();
530                         double pipeRadius = pcp.getPipeRun().getPipeDiameter() / 2;
531                         
532                         // Unit vector in inlet flow direction
533                         Vector3d inletDir = pcp.getPathLegDirection(Direction.PREVIOUS);
534                         inletDir.scale(-1.0);
535                         inletDir.normalize();
536                         
537                         // Normal to both inletDir and turn axis in world coordinates
538                         Vector3d outletDir = pcp.getPathLegDirection(Direction.NEXT);
539                         Vector3d normal = new Vector3d(inletDir);
540                         normal.scaleAdd(-inletDir.dot(outletDir), outletDir);
541                         normal.normalize();
542                         
543                         // Location of turn axis
544                         Vector3d center = new Vector3d(normal);
545                         center.scaleAdd(r, loc);
546                         
547                         // Add vector components from axis to centroid
548                         double c = r + pipeRadius * pipeRadius / (4 * r);
549                         double c1 = c * Math.sin(a) / a;
550                         double c2 = c * (1 - Math.cos(a)) / a;
551                         normal.scale(-c1);
552                         inletDir.scale(c2);
553                         center.add(normal);
554                         center.add(inletDir);
555                 
556                         // Return value
557                         p.set(center);
558                         return;
559                 }
560                 default:
561                         throw new IllegalStateException("No centroid defined");
562                 }
563         }
564         
565         public double getVolume() {
566                 PipeControlPoint pcp = getControlPoint(); 
567                 if (pcp == null)
568                         throw new IllegalStateException("No centroid defined");
569                 
570                 double pipeRadius = getPipeRun().getPipeDiameter() / 2;
571                 
572                 switch (pcp.getType()) {
573                 case INLINE:
574                 case END:
575                         if (!pcp.isSizeChange()) {
576                                 // Just return the cylinder volume
577                                 return pcp.getLength() * Math.PI * pipeRadius * pipeRadius;
578                         }
579                         
580                         // Calculate center of mass for the frustum
581                         double r1 = pipeRadius;
582                         double r2 = getAlternativePipeRun().getPipeDiameter() / 2;
583                         return pcp.getLength() * Math.PI * (r1*r1 + r1*r2 + r2*r2) / 4;
584                 case TURN: {
585                         double r = getPipeRun().getTurnRadius();
586                         double a = pcp.getTurnAngle();
587                         return r * a * Math.PI * pipeRadius * pipeRadius;
588                 }
589                 default:
590                         throw new IllegalStateException("No centroid defined");
591                 }
592         }
593 }