1 package org.simantics.plant3d.scenegraph;
3 import java.util.Collections;
4 import java.util.HashMap;
6 import java.util.Map.Entry;
8 import javax.vecmath.Quat4d;
9 import javax.vecmath.Tuple3d;
10 import javax.vecmath.Vector3d;
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;
30 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
34 public abstract class PipelineComponent extends GeometryNode {
37 private PipeRun pipeRun;
38 private PipeRun alternativePipeRun;
39 private PipelineComponent next;
40 private PipelineComponent previous;
42 public PipeRun getPipeRun() {
49 * With in-line,turn, and end components, the pipe run is the parent object in the scene-graph.
50 * With nozzles, the pipe run setting is explicit (nozzle has to be linked to the piperun, since the parent object is equipment).
51 * With size change components (in-line), there is also alternative pipe run, which must match the next component's pipe run.
55 public void setPipeRun(PipeRun pipeRun) {
56 if (pipeRun == this.pipeRun)
58 this.pipeRun = pipeRun;
59 if (getControlPoint() != null) {
60 getControlPoint().deattach();
61 if (pipeRun != null) {
62 pipeRun.addChild(getControlPoint());
68 @RelatedGetObj(Plant3D.URIs.HasAlternativePipeRun)
69 public PipeRun getAlternativePipeRun() {
70 return alternativePipeRun;
73 @RelatedSetObj(Plant3D.URIs.HasAlternativePipeRun)
74 public void setAlternativePipeRun(PipeRun pipeRun) {
75 if (this.alternativePipeRun == pipeRun)
77 this.alternativePipeRun = pipeRun;
78 if (getControlPoint().isDualInline()) {
79 PipeControlPoint sub = getControlPoint().getSubPoint().get(0);
80 if (sub.getParent() != this.alternativePipeRun)
81 this.alternativePipeRun.addChild(sub);
83 firePropertyChanged(Plant3D.URIs.HasAlternativePipeRun);
87 public void updateParameters() {
88 setParameterMap(updateParameterMap());
89 super.updateParameters();
93 @CompoundRelatedGetValue(objRelation=Plant3D.URIs.hasParameter,objType=Plant3D.URIs.Parameter,valRelation=Plant3D.URIs.hasParameterValue)
94 @CompoundGetPropertyValue(name="Parameters",tabId="Parameters",value="parameters")
95 public Map<String, Object> getParameterMap() {
96 return super.getParameterMap();
100 @CompoundRelatedSetValue(Plant3D.URIs.hasParameter)
101 public void setParameterMap(Map<String, Object> parameters) {
102 super.setParameterMap(parameters);
105 @CompoundGetPropertyValue(name="Parameters",tabId="Parameters",value="parameters")
106 public Map<String,Object> getParameterMapUI() {
107 // TODO : how to filter parameters that are calculated by geometry provider?
108 Map<String,Object> map = new HashMap<String, Object>(getParameterMap());
109 map.remove("radius");
113 @CompoundSetPropertyValue(value="parameters")
114 public void setParameterMapUI(Map<String, Object> parameters) {
115 Map<String, Object> curr = getParameterMap();
116 for (Entry<String, Object> entry : curr.entrySet()) {
117 if (!parameters.containsKey(entry.getKey()))
118 parameters.put(entry.getKey(), entry.getValue());
120 setParameterMap(parameters);
123 public abstract void setType(String typeURI) throws Exception;
125 @RelatedGetObj(Plant3D.URIs.HasNext)
126 public PipelineComponent getNext() {
130 @RelatedSetObj(Plant3D.URIs.HasNext)
131 public void setNext(PipelineComponent comp) {
134 if (this.next != null)
135 this.next._removeRef(this);
137 this.syncnext = false;
139 firePropertyChanged(Plant3D.URIs.HasNext);
142 // System.out.println(this + " next " + comp);
146 @RelatedGetObj(Plant3D.URIs.HasPrevious)
147 public PipelineComponent getPrevious() {
151 @RelatedSetObj(Plant3D.URIs.HasPrevious)
152 public void setPrevious(PipelineComponent comp) {
153 if (previous == comp)
155 if (this.previous != null)
156 this.previous._removeRef(this);
157 this.previous = comp;
158 this.syncprev = false;
160 firePropertyChanged(Plant3D.URIs.HasPrevious);
163 // System.out.println(this + " prev " + comp);
165 private PipelineComponent branch0;
167 @RelatedGetObj(Plant3D.URIs.HasBranch0)
168 public PipelineComponent getBranch0() {
172 @RelatedSetObj(Plant3D.URIs.HasBranch0)
173 public void setBranch0(PipelineComponent comp) {
176 if (this.branch0 != null)
177 this.branch0._removeRef(this);
179 this.syncbr0 = false;
181 firePropertyChanged(Plant3D.URIs.HasBranch0);
184 // System.out.println(this + " next " + comp);
187 @GetPropertyValue(name="Previous",tabId="Debug",value=Plant3D.URIs.HasPrevious)
188 public String getPreviousDebug() {
189 if (previous == null)
191 return previous.getName();
194 @GetPropertyValue(name="Next",tabId="Debug",value=Plant3D.URIs.HasNext)
195 public String getNextDebug() {
198 return next.getName();
201 @GetPropertyValue(name="Branch0",tabId="Debug",value=Plant3D.URIs.HasBranch0)
202 public String getBR0Debug() {
205 return branch0.getName();
210 private PipeControlPoint getBranchPoint() {
211 PipeControlPoint branchPoint;
212 if (getControlPoint().getSubPoint().size() > 0) {
213 branchPoint = getControlPoint().getSubPoint().get(0);
215 if (branch0.getPipeRun() == null)
217 branchPoint = new PipeControlPoint(this,branch0.getPipeRun());
218 branchPoint.setFixed(false);
219 branchPoint.setType(PointType.END);
220 branchPoint.parent = getControlPoint();
221 getControlPoint().children.add(branchPoint);
222 branchPoint.setWorldOrientation(getControlPoint().getWorldOrientation());
223 branchPoint.setWorldPosition(getControlPoint().getWorldPosition());
228 private boolean _connectNext(PipeControlPoint pcp, PipeControlPoint nextPCP) {
231 if (pcp.getNext() != nextPCP) {
232 pcp.setNext(nextPCP);
234 if (pcp.isDualInline()) {
235 PipeControlPoint sub = pcp.getSubPoint().get(0);
236 if (sub.getNext() != nextPCP)
237 sub.setNext(nextPCP);
242 private boolean _connectPrev(PipeControlPoint pcp, PipeControlPoint prevPCP) {
245 if (prevPCP.isDualInline())
246 prevPCP = prevPCP.getSubPoint().get(0);
247 if (pcp.getPrevious() != prevPCP) {
248 pcp.setPrevious(prevPCP);
250 if (pcp.isDualInline()) {
251 PipeControlPoint sub = pcp.getSubPoint().get(0);
252 if (sub.getPrevious() != prevPCP)
253 sub.setPrevious(prevPCP);
258 // When link to a component is removed, also link to the other direction must be removed at the same time, or
259 // Control point structure is left into illegal state.
260 private void _removeRef(PipelineComponent comp) {
265 } else if (previous == comp) {
269 } else if (branch0 == comp) {
276 boolean syncnext = false;
277 private void syncNext() {
280 syncnext = _syncNext();
284 private boolean _syncNext() {
285 PipeControlPoint pcp = getControlPoint();
289 if (next.getControlPoint() != null) {
291 // TODO, relying that the other direction is connected.
292 boolean nxt = next.getPrevious() == this;
293 boolean br0 = next.getBranch0() == this;
295 return _connectNext(pcp, next.getControlPoint());
297 return _connectNext(pcp, next.getBranchPoint());
305 } else if (pcp.getNext() != null) {
315 boolean syncprev = false;
316 private void syncPrevious() {
319 syncprev = _syncPrevious();
322 private boolean _syncPrevious() {
323 PipeControlPoint pcp = getControlPoint();
325 if (previous != null ) {
326 if (previous.getControlPoint() != null) {
328 // TODO, relying that the other direction is connected.
329 boolean prev = previous.getNext() == this;
330 boolean br0 = previous.getBranch0() == this;
332 return _connectPrev(pcp, previous.getControlPoint());
334 return _connectPrev(pcp, previous.getBranchPoint());
342 } else if (pcp.getPrevious() != null) {
343 pcp.setPrevious(null);
352 boolean syncbr0 = false;
353 private void syncBranch0() {
356 syncbr0 = _syncBranch0();
359 private boolean _syncBranch0() {
360 if (getControlPoint() != null) {
361 if (getControlPoint().isDualInline()) {
365 if (branch0 != null) {
366 if (branch0.getControlPoint() != null) {
367 PipeControlPoint branchPoint = getBranchPoint();
368 if (branchPoint == null)
370 PipeControlPoint pcp = branch0.getControlPoint();
371 // TODO, relying that the other direction is connected.
372 boolean next = branch0.getPrevious() == this; // this --> branch0
373 boolean prev = branch0.getNext() == this;
375 _connectNext(branchPoint, pcp);
377 _connectPrev(branchPoint, pcp);
386 } else if (getControlPoint().getSubPoint().size() > 0) { // TODO : this may cause problems? (Removes branch point, before branch has been set?)
387 getControlPoint().getSubPoint().get(0).remove();
388 getControlPoint().children.clear();
403 public void sync2() {
404 // if (getControlPoint().isDualInline()) {
405 // PipeControlPoint sub = getControlPoint().getSubPoint().get(0);
406 // next.getControlPoint().getPipeRun().addChild(sub);
408 getControlPoint()._setWorldOrientation(getWorldOrientation());
409 getControlPoint()._setWorldPosition(getWorldPosition());
412 public Map<String,Object> updateParameterMap() {
413 return Collections.EMPTY_MAP;
416 public abstract String getType();
417 public abstract PipeControlPoint getControlPoint();
420 public void remove() {
421 PipeControlPoint pcp = getControlPoint();
422 // Second check is needed, when remove process is initiated from control point.
423 if (pcp != null && pcp.getPipelineComponent() != null) {
429 public void removeAndSplit() {
430 PipeControlPoint pcp = getControlPoint();
431 // Second check is needed, when remove process is initiated from control point.
432 if (pcp != null && pcp.getPipelineComponent() != null) {
433 pcp.removeAndSplit();
439 protected double[] getColor() {
440 if (getControlPoint() == null || !getControlPoint().isFixed())
441 return new double[]{0.7,0.7,0.7};
443 return new double[]{1.0,0.0,0.0};
447 protected double[] getSelectedColor() {
448 return new double[]{0.5,0,0.5};
452 public void setOrientation(Quat4d orientation) {
453 if (MathTools.equals(orientation, getOrientation()))
455 super.setOrientation(orientation);
456 if (getControlPoint() != null) {
457 getControlPoint()._setWorldOrientation(getWorldOrientation());
459 PipingRules.requestUpdate(getControlPoint());
460 } catch (Exception e) {
461 // TODO Auto-generated catch block
468 public void setPosition(Vector3d position) {
469 if (MathTools.equals(position, getPosition()))
471 super.setPosition(position);
472 if (getControlPoint() != null) {
473 getControlPoint()._setWorldPosition(getWorldPosition());
475 PipingRules.requestUpdate(getControlPoint());
476 } catch (Exception e) {
477 // TODO Auto-generated catch block
484 public void _setWorldPosition(Vector3d position) {
485 Vector3d localPos = getLocalPosition(position);
486 super.setPosition(localPos);
489 public void _setWorldOrientation(Quat4d orientation) {
490 Quat4d localOr = getLocalOrientation(orientation);
491 super.setOrientation(localOr);
494 @GetPropertyValue(name="Flow Length", value="flowlength", tabId = "Default")
495 public Double getFlowLength() {
496 PipeControlPoint pcp = getControlPoint();
499 switch (pcp.getType()) {
501 return pcp.getLength();
505 double r = getPipeRun().getTurnRadius();
506 double a = pcp.getTurnAngle();
514 public void getEnds(Tuple3d p1, Tuple3d p2) {
515 getControlPoint().getControlPointEnds(p1, p2);
518 public void getEndDirections(Tuple3d v1, Tuple3d v2) {
519 getControlPoint().getEndDirections(v1, v2);
522 public void getCentroid(Tuple3d p) {
523 PipeControlPoint pcp = getControlPoint();
525 throw new IllegalStateException("No centroid defined");
527 switch (pcp.getType()) {
530 // Just return the world location
531 if (!pcp.isSizeChange()) {
532 p.set(pcp.getWorldPosition());
536 // Calculate center of mass for the frustum
537 double r1 = getPipeRun().getPipeDiameter();
538 double r2 = getAlternativePipeRun().getPipeDiameter();
540 Vector3d p1 = new Vector3d(), p2 = new Vector3d();
541 pcp.getInlineControlPointEnds(p1, p2);
543 // Squared sum of radii
544 double r12 = r1 + r2;
547 // The larger of the radii form the base of a frustum
548 double rmax = Math.max(r1, r2);
550 // Relative distance from the base of the frustum
551 double h = (r12 + 2*rmax*rmax) / (4 * (r12 - r1*r2));
553 // Relative distance from p1 to p2
563 Vector3d loc = pcp.getRealPosition(PositionType.PREVIOUS);
565 double r = getPipeRun().getTurnRadius();
566 double a = pcp.getTurnAngle();
567 double pipeRadius = pcp.getPipeRun().getPipeDiameter() / 2;
569 // Unit vector in inlet flow direction
570 Vector3d inletDir = pcp.getPathLegDirection(Direction.PREVIOUS);
571 inletDir.scale(-1.0);
572 inletDir.normalize();
574 // Normal to both inletDir and turn axis in world coordinates
575 Vector3d outletDir = pcp.getPathLegDirection(Direction.NEXT);
576 Vector3d normal = new Vector3d(inletDir);
577 normal.scaleAdd(-inletDir.dot(outletDir), outletDir);
580 // Location of turn axis
581 Vector3d center = new Vector3d(normal);
582 center.scaleAdd(r, loc);
584 // Add vector components from axis to centroid
585 double c = r + pipeRadius * pipeRadius / (4 * r);
586 double c1 = c * Math.sin(a) / a;
587 double c2 = c * (1 - Math.cos(a)) / a;
591 center.add(inletDir);
598 throw new IllegalStateException("No centroid defined");
602 public double getVolume() {
603 PipeControlPoint pcp = getControlPoint();
605 throw new IllegalStateException("No centroid defined");
607 double pipeRadius = getPipeRun().getPipeDiameter() / 2;
609 switch (pcp.getType()) {
612 if (!pcp.isSizeChange()) {
613 // Just return the cylinder volume
614 return pcp.getLength() * Math.PI * pipeRadius * pipeRadius;
617 // Calculate center of mass for the frustum
618 double r1 = pipeRadius;
619 double r2 = getAlternativePipeRun().getPipeDiameter() / 2;
620 return pcp.getLength() * Math.PI * (r1*r1 + r1*r2 + r2*r2) / 4;
622 double r = getPipeRun().getTurnRadius();
623 double a = pcp.getTurnAngle();
624 return r * a * Math.PI * pipeRadius * pipeRadius;
627 throw new IllegalStateException("No centroid defined");