package org.simantics.plant3d.scenegraph; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.vecmath.Vector3d; import org.simantics.g3d.math.MathTools; import org.simantics.g3d.property.annotations.GetComboProperty; import org.simantics.g3d.property.annotations.GetComboPropertyValue; import org.simantics.g3d.property.annotations.GetPropertyValue; import org.simantics.g3d.property.annotations.SetComboPropertyValue; import org.simantics.g3d.property.annotations.SetPropertyValue; import org.simantics.g3d.scenegraph.base.ParentNode; import org.simantics.g3d.tools.NodeTools; import org.simantics.objmap.graph.annotations.DynamicGraphType; import org.simantics.objmap.graph.annotations.GetType; import org.simantics.objmap.graph.annotations.RelatedGetValue; import org.simantics.objmap.graph.annotations.RelatedSetValue; import org.simantics.objmap.graph.annotations.SetType; import org.simantics.plant3d.ontology.Plant3D; import org.simantics.plant3d.scenegraph.controlpoint.ControlPointFactory; import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint; import org.simantics.plant3d.scenegraph.controlpoint.PipingRules; @DynamicGraphType(Plant3D.URIs.TurnComponent) public class TurnComponent extends PipelineComponent { private String type; private PipeControlPoint controlPoint; private Integer turnRadiusIndex; @GetType(Plant3D.URIs.TurnComponent) public String getType() { return type; } @SetType(Plant3D.URIs.TurnComponent) public void setType(String type) throws Exception{ this.type = type; controlPoint = ControlPointFactory.create(this); syncNext(); syncPrevious(); syncBranch0(); } @Override public PipeControlPoint getControlPoint() { return controlPoint; } @Override public void setParent(ParentNode parent, String name) { super.setParent(parent, name); setPipeRun((PipeRun)parent); } @Override public Map updateParameterMap() { Map map = new HashMap(); if (getPipeRun() != null) { map.put("turnRadius", getTurnRadius()); map.put("radius", getDiameter() * 0.5); } if (controlPoint != null && controlPoint.getTurnAngle() != null && !Double.isNaN(controlPoint.getTurnAngle())) { map.put("turnAngle", controlPoint.getTurnAngle()); } return map; } public boolean isVariableAngle() { return !controlPoint.isFixed(); } @Override public void updateParameters() { super.updateParameters(); if (controlPoint.asFixedAngle()) { Map calculated = getCalculatedParameters(); if (calculated.containsKey("length")) { controlPoint.setLength((Double)calculated.get("length")); } PipingRules.requestUpdate(getControlPoint()); } } public Double getTurnAngle() { return getControlPoint().getTurnAngle(); } @RelatedGetValue(Plant3D.URIs.HasTurnAngle) public Double _getTurnAngle() { if (!getControlPoint().asFixedAngle()) return null; return getControlPoint().getTurnAngle(); } @RelatedSetValue(Plant3D.URIs.HasTurnAngle) public void setTurnAngle(Double a) { if (!getControlPoint().asFixedAngle()) return; getControlPoint().setTurnAngle(a); } @GetPropertyValue(name="Turn Angle", value="turn angle", tabId = "Default") public Double getTurnAngleDeg() { Double d = getControlPoint().getTurnAngle(); if (d == null) return null; return MathTools.radToDeg(d); } public Vector3d getTurnAxis() { return getControlPoint().getTurnAxis(); } public Double getTurnRadius() { if (turnRadiusIndex != null) return getPipeRun().getTurnRadiusArray()[turnRadiusIndex]; return getPipeRun().getTurnRadiusArray()[0]; } @RelatedGetValue(Plant3D.URIs.HasTurnRadiusIndex) @GetComboPropertyValue(name="Turn Radius", value=Plant3D.URIs.HasTurnRadiusIndex, tabId = "Default") public Integer getTurnRadiusIndex() { // TODO: For backwards compatibility, we do not accept null values. // One development path would allow null index, and setting custom turn radius for the component. if (turnRadiusIndex == null) return 0; return turnRadiusIndex; } @RelatedSetValue(Plant3D.URIs.HasTurnRadiusIndex) @SetComboPropertyValue(value=Plant3D.URIs.HasTurnRadiusIndex) public void setTurnRadiusIndex(Integer turnRadiusIndex) { if (this.turnRadiusIndex == turnRadiusIndex) return; if (turnRadiusIndex == null || turnRadiusIndex < 0) return; if (turnRadiusIndex != null && getPipeRun() != null) { if (getPipeRun().getTurnRadiusArray().length <= turnRadiusIndex) return; } this.turnRadiusIndex = turnRadiusIndex; firePropertyChanged(Plant3D.URIs.HasTurnRadiusIndex); PipingRules.requestUpdate(getControlPoint()); } @GetComboProperty(value=Plant3D.URIs.HasTurnRadiusIndex) public List _getTurnRadii() { List values = new ArrayList(); for (double d : getPipeRun().getTurnRadiusArray()) values.add(d); return values; } @RelatedGetValue(Plant3D.URIs.HasRotationAngle) @GetPropertyValue(name="Rotation Angle", value=Plant3D.URIs.HasRotationAngle, tabId = "Default") public Double getRotationAngle() { if (!controlPoint.asFixedAngle()) return null; Double d = controlPoint.getRotationAngle(); if (d == null) return 0.0; return MathTools.radToDeg(d); } @RelatedSetValue(Plant3D.URIs.HasRotationAngle) @SetPropertyValue(value=Plant3D.URIs.HasRotationAngle) public void setRotationAngle(Double angle) { if (!controlPoint.asFixedAngle()) return; if (angle == null || Double.isInfinite(angle) || Double.isNaN(angle)) { return; } angle = MathTools.degToRad(angle); if (controlPoint.getRotationAngle() != null && Math.abs(controlPoint.getRotationAngle()-angle) < MathTools.NEAR_ZERO) return; controlPoint.setRotationAngle(angle); PipingRules.requestUpdate(getControlPoint()); } @RelatedGetValue(Plant3D.URIs.IsReversed) @GetPropertyValue(name="Reverse", value=Plant3D.URIs.IsReversed, tabId = "Default") public Boolean isReversed() { if (!controlPoint.asFixedAngle()) return null; Boolean d = controlPoint._getReversed(); return d; } @RelatedSetValue(Plant3D.URIs.IsReversed) public void setReversed(Boolean reverse) { if (!controlPoint.asFixedAngle()) return; if (reverse == null) { return; } controlPoint.setReversed(reverse); PipingRules.requestUpdate(getControlPoint()); } @Override protected double[] getColor() { if (getControlPoint() == null || !getControlPoint().isFixed()) return new double[]{0.6,0.6,0.6}; else return new double[]{1.0,0.0,0.0}; } /** * Turn is a section of a circle; this method returns center of that circle. * @return */ public Vector3d getCenterPosition() { // getPosition() is control point position, located outside of turn // we need to calculate position in the middle of the turn double t = Math.tan((Math.PI - getControlPoint().getTurnAngle()) * 0.5); double tr = getTurnRadius(); double R = 0.0; if (t > MathTools.NEAR_ZERO) R = tr / t; Vector3d localC = new Vector3d(-R, 0.0, -tr); // worldC is center of a circle Vector3d worldC = NodeTools.getWorldPosition(this,localC); return worldC; } /** * Returns position in the middle of turn component * @return */ public Vector3d getMiddlePosition() { Vector3d pos = getWorldPosition(); Vector3d worldC = getCenterPosition(); // calculate vector from center to edge, which is middle of the turn pos.sub(worldC); pos.normalize(); pos.scale(getTurnRadius()); pos.add(worldC); return pos; } }