1 package org.simantics.plant3d.scenegraph;
3 import java.util.Collections;
6 import javax.vecmath.Quat4d;
7 import javax.vecmath.Tuple3d;
8 import javax.vecmath.Vector3d;
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;
24 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
28 public abstract class PipelineComponent extends GeometryNode {
31 private PipeRun pipeRun;
32 private PipeRun alternativePipeRun;
33 private PipelineComponent next;
34 private PipelineComponent previous;
36 public PipeRun getPipeRun() {
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.
49 public void setPipeRun(PipeRun pipeRun) {
50 if (pipeRun == this.pipeRun)
52 this.pipeRun = pipeRun;
53 if (getControlPoint() != null) {
54 getControlPoint().deattach();
55 if (pipeRun != null) {
56 pipeRun.addChild(getControlPoint());
62 @RelatedGetObj(Plant3D.URIs.HasAlternativePipeRun)
63 public PipeRun getAlternativePipeRun() {
64 return alternativePipeRun;
67 @RelatedSetObj(Plant3D.URIs.HasAlternativePipeRun)
68 public void setAlternativePipeRun(PipeRun pipeRun) {
69 if (this.alternativePipeRun == pipeRun)
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);
77 firePropertyChanged(Plant3D.URIs.HasAlternativePipeRun);
81 public void updateParameters() {
82 setParameterMap(updateParameterMap());
83 super.updateParameters();
86 public abstract void setType(String typeURI) throws Exception;
88 @RelatedGetObj(Plant3D.URIs.HasNext)
89 public PipelineComponent getNext() {
93 @RelatedSetObj(Plant3D.URIs.HasNext)
94 public void setNext(PipelineComponent comp) {
97 if (this.next != null)
98 this.next._removeRef(this);
100 this.syncnext = false;
102 firePropertyChanged(Plant3D.URIs.HasNext);
105 // System.out.println(this + " next " + comp);
109 @RelatedGetObj(Plant3D.URIs.HasPrevious)
110 public PipelineComponent getPrevious() {
114 @RelatedSetObj(Plant3D.URIs.HasPrevious)
115 public void setPrevious(PipelineComponent comp) {
116 if (previous == comp)
118 if (this.previous != null)
119 this.previous._removeRef(this);
120 this.previous = comp;
121 this.syncprev = false;
123 firePropertyChanged(Plant3D.URIs.HasPrevious);
126 // System.out.println(this + " prev " + comp);
128 private PipelineComponent branch0;
130 @RelatedGetObj(Plant3D.URIs.HasBranch0)
131 public PipelineComponent getBranch0() {
135 @RelatedSetObj(Plant3D.URIs.HasBranch0)
136 public void setBranch0(PipelineComponent comp) {
139 if (this.branch0 != null)
140 this.branch0._removeRef(this);
142 this.syncbr0 = false;
144 firePropertyChanged(Plant3D.URIs.HasBranch0);
147 // System.out.println(this + " next " + comp);
150 @GetPropertyValue(name="Previous",tabId="Debug",value=Plant3D.URIs.HasPrevious)
151 public String getPreviousDebug() {
152 if (previous == null)
154 return previous.getName();
157 @GetPropertyValue(name="Next",tabId="Debug",value=Plant3D.URIs.HasNext)
158 public String getNextDebug() {
161 return next.getName();
164 @GetPropertyValue(name="Branch0",tabId="Debug",value=Plant3D.URIs.HasBranch0)
165 public String getBR0Debug() {
168 return branch0.getName();
173 private PipeControlPoint getBranchPoint() {
174 PipeControlPoint branchPoint;
175 if (getControlPoint().getSubPoint().size() > 0) {
176 branchPoint = getControlPoint().getSubPoint().get(0);
178 if (branch0.getPipeRun() == 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());
191 private boolean _connectNext(PipeControlPoint pcp, PipeControlPoint nextPCP) {
194 if (pcp.getNext() != nextPCP) {
195 pcp.setNext(nextPCP);
197 if (pcp.isDualInline()) {
198 PipeControlPoint sub = pcp.getSubPoint().get(0);
199 if (sub.getNext() != nextPCP)
200 sub.setNext(nextPCP);
205 private boolean _connectPrev(PipeControlPoint pcp, PipeControlPoint prevPCP) {
208 if (prevPCP.isDualInline())
209 prevPCP = prevPCP.getSubPoint().get(0);
210 if (pcp.getPrevious() != prevPCP) {
211 pcp.setPrevious(prevPCP);
213 if (pcp.isDualInline()) {
214 PipeControlPoint sub = pcp.getSubPoint().get(0);
215 if (sub.getPrevious() != prevPCP)
216 sub.setPrevious(prevPCP);
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) {
228 } else if (previous == comp) {
232 } else if (branch0 == comp) {
239 boolean syncnext = false;
240 private void syncNext() {
243 syncnext = _syncNext();
247 private boolean _syncNext() {
248 PipeControlPoint pcp = getControlPoint();
252 if (next.getControlPoint() != null) {
254 // TODO, relying that the other direction is connected.
255 boolean nxt = next.getPrevious() == this;
256 boolean br0 = next.getBranch0() == this;
258 return _connectNext(pcp, next.getControlPoint());
260 return _connectNext(pcp, next.getBranchPoint());
268 } else if (pcp.getNext() != null) {
278 boolean syncprev = false;
279 private void syncPrevious() {
282 syncprev = _syncPrevious();
285 private boolean _syncPrevious() {
286 PipeControlPoint pcp = getControlPoint();
288 if (previous != null ) {
289 if (previous.getControlPoint() != null) {
291 // TODO, relying that the other direction is connected.
292 boolean prev = previous.getNext() == this;
293 boolean br0 = previous.getBranch0() == this;
295 return _connectPrev(pcp, previous.getControlPoint());
297 return _connectPrev(pcp, previous.getBranchPoint());
305 } else if (pcp.getPrevious() != null) {
306 pcp.setPrevious(null);
315 boolean syncbr0 = false;
316 private void syncBranch0() {
319 syncbr0 = _syncBranch0();
322 private boolean _syncBranch0() {
323 if (getControlPoint() != null) {
324 if (getControlPoint().isDualInline()) {
328 if (branch0 != null) {
329 if (branch0.getControlPoint() != null) {
330 PipeControlPoint branchPoint = getBranchPoint();
331 if (branchPoint == null)
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;
338 _connectNext(branchPoint, pcp);
340 _connectPrev(branchPoint, pcp);
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();
366 public void sync2() {
367 // if (getControlPoint().isDualInline()) {
368 // PipeControlPoint sub = getControlPoint().getSubPoint().get(0);
369 // next.getControlPoint().getPipeRun().addChild(sub);
371 getControlPoint()._setWorldOrientation(getWorldOrientation());
372 getControlPoint()._setWorldPosition(getWorldPosition());
375 public Map<String,Object> updateParameterMap() {
376 return Collections.EMPTY_MAP;
379 public abstract String getType();
380 public abstract PipeControlPoint getControlPoint();
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) {
393 protected double[] getColor() {
394 if (getControlPoint() == null || !getControlPoint().isFixed())
395 return new double[]{0.7,0.7,0.7};
397 return new double[]{1.0,0.0,0.0};
401 protected double[] getSelectedColor() {
402 return new double[]{0.5,0,0.5};
406 public void setOrientation(Quat4d orientation) {
407 if (MathTools.equals(orientation, getOrientation()))
409 super.setOrientation(orientation);
410 if (getControlPoint() != null) {
411 getControlPoint()._setWorldOrientation(getWorldOrientation());
413 PipingRules.requestUpdate(getControlPoint());
414 } catch (Exception e) {
415 // TODO Auto-generated catch block
422 public void setPosition(Vector3d position) {
423 if (MathTools.equals(position, getPosition()))
425 super.setPosition(position);
426 if (getControlPoint() != null) {
427 getControlPoint()._setWorldPosition(getWorldPosition());
429 PipingRules.requestUpdate(getControlPoint());
430 } catch (Exception e) {
431 // TODO Auto-generated catch block
438 public void _setWorldPosition(Vector3d position) {
439 Vector3d localPos = getLocalPosition(position);
440 super.setPosition(localPos);
443 public void _setWorldOrientation(Quat4d orientation) {
444 Quat4d localOr = getLocalOrientation(orientation);
445 super.setOrientation(localOr);
448 @GetPropertyValue(name="Flow Length", value="flowlength", tabId = "Default")
449 public Double getFlowLength() {
450 PipeControlPoint pcp = getControlPoint();
453 switch (pcp.getType()) {
455 return pcp.getLength();
459 double r = getPipeRun().getTurnRadius();
460 double a = pcp.getTurnAngle();
468 public void getEnds(Tuple3d p1, Tuple3d p2) {
469 getControlPoint().getControlPointEnds(p1, p2);
472 public void getEndDirections(Tuple3d v1, Tuple3d v2) {
473 getControlPoint().getEndDirections(v1, v2);
476 public void getCentroid(Tuple3d p) {
477 PipeControlPoint pcp = getControlPoint();
479 throw new IllegalStateException("No centroid defined");
481 switch (pcp.getType()) {
484 // Just return the world location
485 if (!pcp.isSizeChange()) {
486 p.set(pcp.getWorldPosition());
490 // Calculate center of mass for the frustum
491 double r1 = getPipeRun().getPipeDiameter();
492 double r2 = getAlternativePipeRun().getPipeDiameter();
494 Vector3d p1 = new Vector3d(), p2 = new Vector3d();
495 pcp.getInlineControlPointEnds(p1, p2);
497 // Squared sum of radii
498 double r12 = r1 + r2;
501 // The larger of the radii form the base of a frustum
502 double rmax = Math.max(r1, r2);
504 // Relative distance from the base of the frustum
505 double h = (r12 + 2*rmax*rmax) / (4 * (r12 - r1*r2));
507 // Relative distance from p1 to p2
517 Vector3d loc = pcp.getRealPosition(PositionType.PREVIOUS);
519 double r = getPipeRun().getTurnRadius();
520 double a = pcp.getTurnAngle();
521 double pipeRadius = pcp.getPipeRun().getPipeDiameter() / 2;
523 // Unit vector in inlet flow direction
524 Vector3d inletDir = pcp.getPathLegDirection(Direction.PREVIOUS);
525 inletDir.scale(-1.0);
526 inletDir.normalize();
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);
534 // Location of turn axis
535 Vector3d center = new Vector3d(normal);
536 center.scaleAdd(r, loc);
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;
545 center.add(inletDir);
552 throw new IllegalStateException("No centroid defined");
556 public double getVolume() {
557 PipeControlPoint pcp = getControlPoint();
559 throw new IllegalStateException("No centroid defined");
561 double pipeRadius = getPipeRun().getPipeDiameter() / 2;
563 switch (pcp.getType()) {
566 if (!pcp.isSizeChange()) {
567 // Just return the cylinder volume
568 return pcp.getLength() * Math.PI * pipeRadius * pipeRadius;
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;
576 double r = getPipeRun().getTurnRadius();
577 double a = pcp.getTurnAngle();
578 return r * a * Math.PI * pipeRadius * pipeRadius;
581 throw new IllegalStateException("No centroid defined");