X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.plant3d%2Fsrc%2Forg%2Fsimantics%2Fplant3d%2Fscenegraph%2Fcontrolpoint%2FPipeControlPoint.java;h=cd4f407b22b6f65e3e80a91c2bc4cc5fae2df9a6;hb=d005c67f1706391f2eb9dfd6cfd9489a4a7ec60d;hp=53a612e201179eca765af679c424c04a4c8ef601;hpb=b63b50f907c318cd999ff8cdc0ca3f1bf93dc6fe;p=simantics%2F3d.git diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java index 53a612e2..cd4f407b 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Objects; import javax.vecmath.AxisAngle4d; import javax.vecmath.Matrix3d; @@ -15,7 +16,10 @@ import javax.vecmath.Vector3d; import org.simantics.g3d.math.MathTools; import org.simantics.g3d.property.annotations.GetPropertyValue; import org.simantics.g3d.scenegraph.G3DNode; +import org.simantics.g3d.scenegraph.base.INode; import org.simantics.plant3d.scenegraph.IP3DNode; +import org.simantics.plant3d.scenegraph.Nozzle; +import org.simantics.plant3d.scenegraph.P3DRootNode; import org.simantics.plant3d.scenegraph.PipeRun; import org.simantics.plant3d.scenegraph.PipelineComponent; @@ -23,34 +27,38 @@ import vtk.vtkRenderer; public class PipeControlPoint extends G3DNode implements IP3DNode { - - private static boolean DEBUG = false; - + + private static boolean DEBUG = false; + public enum PointType{INLINE,TURN,END}; public enum Direction{NEXT,PREVIOUS}; public enum PositionType {SPLIT,NEXT,PREVIOUS,PORT} - + private PipelineComponent component; - + private PointType type; - private boolean fixed = true; - private boolean rotate = false; - private boolean reverse = false; - private boolean deletable = true; - private boolean sub = false; + private boolean isFixed = true; // In-line: fixed-length Turn: fixed-angle + private boolean isMod = false; // Can user modify fixed value manually + private boolean isRotate = false; // rotates around path leg axis. + private boolean isReverse = false; // definition direction can be swapped + private boolean isDeletable = true; // can be removed by rules + private boolean isSizeChange = false; // changes size of the pipe. The next control point / component is on different PipeRun + private boolean isSub = false; // child point for offset / size change + + private boolean disposed = false; public PipeControlPoint(PipelineComponent component) { this.component = component; if (component.getPipeRun() != null) component.getPipeRun().addChild(this); - + } - + public PipeControlPoint(PipelineComponent component, PipeRun piperun) { this.component = component; piperun.addChild(this); } - + @Override public void update(vtkRenderer ren) { try { @@ -58,180 +66,306 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } catch (Exception e) { e.printStackTrace(); } - + } - + public PipeRun getPipeRun() { return (PipeRun)getParent(); } - + public PipelineComponent getPipelineComponent() { return component; } - + public PointType getType() { return type; } - + public void setType(PointType type) { this.type = type; } - + @GetPropertyValue(name="Fixed",tabId="Debug",value="fixed") public boolean isFixed() { - return fixed; + return isFixed; } - - + public void setFixed(boolean fixed) { - this.fixed = fixed; + this.isFixed = fixed; } + @GetPropertyValue(name="Mod",tabId="Debug",value="mod") + public boolean isMod() { + return isMod; + } + + public void setMod(boolean isMod) { + this.isMod = isMod; + } + @GetPropertyValue(name="Rotate",tabId="Debug",value="rotate") public boolean isRotate() { - return rotate; + return isRotate; } - + public void setRotate(boolean rotate) { - this.rotate = rotate; + this.isRotate = rotate; } - + @GetPropertyValue(name="Reverse",tabId="Debug",value="reverse") public boolean isReverse() { - return reverse; + return isReverse; } - + public void setReverse(boolean reverse) { - this.reverse = reverse; + this.isReverse = reverse; } - + public void setSub(boolean sub) { - this.sub = sub; + this.isSub = sub; } - + @GetPropertyValue(name="Deletable",tabId="Debug",value="deletable") public boolean isDeletable() { - return deletable; + return isDeletable; } - + public void setDeletable(boolean deletable) { - this.deletable = deletable; + this.isDeletable = deletable; } - + public boolean isPathLegEnd() { return type != PointType.INLINE; } - + public boolean isEnd() { return type == PointType.END; } - + public boolean isTurn() { return type == PointType.TURN; } - + public boolean isInline() { return type == PointType.INLINE; } + public boolean asPathLegEnd() { + // Ends and Turns are path leg ends by default, but also unconnected inline are path leg ends. + return isPathLegEnd() || getNext() == null || getPrevious() == null; + } + + /** + * True for end components, if control point defines absolute position direction, which rules cannot modify. + * This is typical for nozzles. + * @return + */ public boolean isDirected() { - return fixed && isEnd(); + return isFixed && isEnd(); } - + + /** + * True for end components, if control is opposite to directed, and rules can modify position and orientation. + * This is typical for caps, and other end components. + * @return + */ public boolean isNonDirected() { - return !fixed && isEnd(); + return !isFixed && isEnd(); } - + public boolean isVariableLength() { - return !fixed && isInline(); + return !isFixed && isInline(); } + /** + * Fixed length in-line component is such that piping rules cannot modify the length. + * @return + */ + public boolean isFixedLength() { + return isFixed && isInline(); + } + public boolean isVariableAngle() { - return !fixed && isTurn(); + return !isFixed && isTurn(); } + /** + * Fixed angle turn component is such that piping rules cannot modify the angle. + * @return + */ + public boolean isFixedAngle() { + return isFixed && isTurn(); + } + + /** + * Does the turn behave like fixed angle? + * For variable angle turns, the turn angle is defined by connected components, and without them, we must handle the component as fixed angle. + * @return + */ + public boolean asFixedAngle() { + return isTurn() && (isFixed || next == null || previous == null); + } + public boolean isBranchEnd() { - return deletable && isEnd(); + return isDeletable && isEnd(); } - + public boolean isOffset() { return offset != null; } - + public boolean isDualSub() { - return parent != null && sub; + return parent != null && isSub; } - + public boolean isDualInline() { return children.size() == 1 && children.get(0).isDualSub(); } - + + public boolean isAxial() { + return isInline() && !isDualInline(); + } + public boolean isSizeChange() { - if (children.size() == 0) - return false; - if (!isDualInline()) - return false; - return getPipeRun() != children.get(0).getPipeRun(); + return isSizeChange; + // if (children.size() == 0) + // return false; + // if (!isDualInline()) + // return false; + // return getPipeRun() != children.get(0).getPipeRun(); } - + public void setSizeChange(boolean isSizeChange) { + this.isSizeChange = isSizeChange; + } + + private PipeControlPoint next; private PipeControlPoint previous; - + public PipeControlPoint getNext() { return next; } - + public PipeControlPoint getPrevious() { return previous; } - + public void setNext(PipeControlPoint next) { + if (isSub) { + getParentPoint().setNext(next); + return; + } + if (next != null && next.isDualSub()) + next = next.parent; + if (_setNext(next)) { + for (PipeControlPoint pcp : children) { + if (pcp.isSub) + pcp._setNext(next); + } + updateSubPoint(); + } + } + + public void setPrevious(PipeControlPoint prev) { + if (isSub) { + getParentPoint().setPrevious(prev); + return; + } + if (prev != null && prev.isDualInline()) + prev = prev.children.get(0); + if (_setPrevious(prev)) { + for (PipeControlPoint pcp : children) { + if (pcp.isSub) + pcp._setPrevious(prev); + } + updateSubPoint(); + } + } + + protected boolean _setNext(PipeControlPoint next) { if (isEnd() && previous != null && next != null) throw new RuntimeException("End control points are allowed to have only one connection"); + if (next == this) + throw new RuntimeException("Cannot connect to self"); if (this.next == next) - return; + return false; if (DEBUG) System.out.println(this + " next " + next); + if (next == null && isVariableAngle() && previous != null && !isRemoved()) { + convertVariableAngleToFixed(Direction.NEXT); + } this.next = next; if (component != null) { - if (parent == null || sub) + if (parent == null || isSub) component.setNext(next != null ? next.component : null); else component.setBranch0(next != null ? next.component : null); - updateSubPoint(); + } - + return true; } - - public void setPrevious(PipeControlPoint previous) { + + protected boolean _setPrevious(PipeControlPoint previous) { if (isEnd() && next != null && previous != null) throw new RuntimeException("End control points are allowed to have only one connection"); + if (previous == this) + throw new RuntimeException("Cannot connect to self"); if (this.previous == previous) - return; + return false; if (DEBUG) System.out.println(this + " previous " + previous); + if (previous == null && isVariableAngle() && next != null && !isRemoved()) { + convertVariableAngleToFixed(Direction.PREVIOUS); + } this.previous = previous; if (component != null) { - if (parent == null || sub) + if (parent == null || isSub) component.setPrevious(previous != null ? previous.component : null); else component.setBranch0(previous != null ? previous.component : null); updateSubPoint(); } - + return true; } + private void convertVariableAngleToFixed(Direction direction) { + // We are removing reference, which transforms variable angle to fixed angle. + // Since fixed angle is defined differently, we need to calculate fixed angle parameters based on current data + // We need to calculate turnAngle and rotationAngle + Vector3d dirOut = getPathLegDirection(direction == Direction.NEXT ? Direction.NEXT : Direction.PREVIOUS); + Vector3d dir = getPathLegDirection(direction == Direction.NEXT ? Direction.PREVIOUS : Direction.NEXT); + if (dir == null || dirOut == null) + return; + dir.negate(); + double angle = dir.angle(dirOut); + //super._setNext(null); + if (direction == Direction.NEXT) + next = null; + else + previous = null; + setRotationAngle(0.0); + setReversed(direction == Direction.NEXT ? false : true); + Vector3d dirOutN = getPathLegDirection(direction == Direction.NEXT ? Direction.NEXT : Direction.PREVIOUS); + dirOutN.normalize(); + AxisAngle4d aa = new AxisAngle4d(); + if (MathTools.createRotation(dirOutN, dirOut, dir, aa)) { + setRotationAngle(aa.angle); + setTurnAngle(angle); + if (DEBUG) System.out.println("convertToFixed " + dir + " " + dirOut + " " +dirOutN + " " +angle + " "+ aa.angle); + } + } + public PipeControlPoint parent; public List children = new ArrayList(); - - public List getSubPoint() { + + public List getChildPoints() { return children; } - + public PipeControlPoint getParentPoint() { return parent; } - + private double length; private Double turnAngle; private Vector3d turnAxis; @@ -239,97 +373,108 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { private Double offset; private Double rotationAngle; private Boolean reversed; - + @GetPropertyValue(name="Length",tabId="Debug",value="length") public double getLength() { return length; } - + public void setLength(double l) { - if (Double.isInfinite(l) || Double.isNaN(l)) { + if (this.length == l) + return; + if (Double.isInfinite(l) || Double.isNaN(l)) return; - } if (Math.abs(this.length-l) < MathTools.NEAR_ZERO) return; this.length = l; firePropertyChanged("length"); if (isDualInline()) - getSubPoint().get(0).setLength(l); + getDualSub().setLength(l); } - + @GetPropertyValue(name="Turn Angle",tabId="Debug",value="turnAngle") public Double getTurnAngle() { return turnAngle; } - + @GetPropertyValue(name="Turn Axis",tabId="Debug",value="turnAxis") public Vector3d getTurnAxis() { return turnAxis; } - + @GetPropertyValue(name="Offset",tabId="Debug",value="offset") public Double getOffset() { return offset; } - + @GetPropertyValue(name="Rotation Angle",tabId="Debug",value="rotationAngle") public Double getRotationAngle() { - return rotationAngle; + if (isRotate || asFixedAngle()) + return rotationAngle; + return null; } - + @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed") public Boolean getReversed() { return reversed; } - + public boolean _getReversed() { - if (reversed == null) - return false; - return reversed; - } - + if (reversed == null) + return false; + return reversed; + } + public void setTurnAngle(Double turnAngle) { if (turnAngle == null || Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) { return; } if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO) return; + if (Objects.equals(this.turnAngle, turnAngle)) + return; this.turnAngle = turnAngle; firePropertyChanged("turnAngle"); } - + public void setTurnAxis(Vector3d turnAxis) { - if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis)) - return; - this.turnAxis = turnAxis; + if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis)) + return; + this.turnAxis = turnAxis; firePropertyChanged("turnAxis"); } - + public void setOffset(Double offset) { if (Double.isInfinite(offset) || Double.isNaN(offset)) { return; } if (this.offset != null && Math.abs(this.offset-offset) < MathTools.NEAR_ZERO) return; + if (Objects.equals(this.offset, offset)) + return; this.offset = offset; firePropertyChanged("offset"); } - + public void setRotationAngle(Double rotationAngle) { if (Double.isInfinite(rotationAngle) || Double.isNaN(rotationAngle)) { return; } if (this.rotationAngle != null && Math.abs(this.rotationAngle-rotationAngle) < MathTools.NEAR_ZERO) return; + if (Objects.equals(this.rotationAngle, rotationAngle)) + return; this.rotationAngle = rotationAngle; firePropertyChanged("rotationAngle"); } - + public void setReversed(Boolean reversed) { + if (this.reversed == reversed) + return; this.reversed = reversed; firePropertyChanged("reversed"); } - + public Vector3d getSizeChangeOffsetVector(Vector3d dir) { Quat4d q; if (rotationAngle == null) @@ -337,11 +482,11 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { else q = getControlPointOrientationQuat(dir, rotationAngle); Vector3d v = new Vector3d(0.0,offset,0.0); - Vector3d offset = new Vector3d(); - MathTools.rotate(q, v, offset); - return offset; + Vector3d offset = new Vector3d(); + MathTools.rotate(q, v, offset); + return offset; } - + public Vector3d getSizeChangeOffsetVector() { Quat4d q; if (rotationAngle == null) @@ -349,182 +494,173 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { else q = getControlPointOrientationQuat(rotationAngle); Vector3d v = new Vector3d(0.0,offset,0.0); - Vector3d offset = new Vector3d(); - MathTools.rotate(q, v, offset); - return offset; + Vector3d offset = new Vector3d(); + MathTools.rotate(q, v, offset); + return offset; } - + @GetPropertyValue(name="Next",tabId="Debug",value="next") private String getNextString() { if (next == null) return null; return next.toString(); } - + @GetPropertyValue(name="Previous",tabId="Debug",value="previous") private String getPrevString() { if (previous == null) return null; return previous.toString(); } - + @GetPropertyValue(name="Sub",tabId="Debug",value="sub") private String getSubString() { if (children.size() == 0) return ""; return Arrays.toString(children.toArray()); } - + @GetPropertyValue(name="Type",tabId="Debug",value="type") public String getTypeString() { return type.name(); } + + public Vector3d getPathLegEndpointVector() { + PipeControlPoint a = findPreviousEnd(); + PipeControlPoint b = findNextEnd(); + + if (a == null || b == null) { + return getPathLegDirection(); + } + + Vector3d p1 = a.getWorldPosition(); + Vector3d p2 = b.getWorldPosition(); + p2.sub(p1); + double l = p2.length(); + if (l != 0.0) { + p2.scale(1.0 / l); + return p2; + } + else { + return getPathLegDirection(); + } + } + + public Vector3d getPathLegDirection() { + if (turnAxis == null) { + return getPathLegDirection(Direction.NEXT); + } else { + Vector3d dir = getPathLegDirection(Direction.PREVIOUS); + if (dir != null) dir.negate(); + return dir; + } + } public Quat4d getControlPointOrientationQuat(double angle) { - - if (turnAxis == null) { - Vector3d dir = getPathLegDirection(Direction.NEXT); - if (dir.lengthSquared() > MathTools.NEAR_ZERO) - dir.normalize(); - return getControlPointOrientationQuat(dir, angle); - } else { - Vector3d dir = getPathLegDirection(Direction.PREVIOUS); - dir.negate(); - if (dir.lengthSquared() > MathTools.NEAR_ZERO) - dir.normalize(); - return getControlPointOrientationQuat(dir, turnAxis, angle); - } - } - - public Quat4d getControlPointOrientationQuat(double angle, boolean reversed) { - - if (turnAxis == null) { - Vector3d dir = getPathLegDirection(Direction.NEXT); - if (dir.lengthSquared() > MathTools.NEAR_ZERO) - dir.normalize(); - Quat4d q = getControlPointOrientationQuat(dir, angle); - if (reversed) { - Quat4d q2 = new Quat4d(); - q2.set(new AxisAngle4d(MathTools.Y_AXIS, Math.PI)); - q.mulInverse(q2); - } - return q; - } else { - Vector3d dir = getPathLegDirection(Direction.PREVIOUS); - dir.negate(); - if (dir.lengthSquared() > MathTools.NEAR_ZERO) - dir.normalize(); - return getControlPointOrientationQuat(dir, turnAxis, angle); - } - } - - + Vector3d dir = getPathLegDirection(); + if (turnAxis == null) { + return getControlPointOrientationQuat(dir, angle); + } else { + return getControlPointOrientationQuat(dir, turnAxis, angle); + } + } - public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) { - if (dir.lengthSquared() < MathTools.NEAR_ZERO) - return MathTools.getIdentityQuat(); - - - Vector3d up = new Vector3d(0.0, 1.0, 0.0); - double a = up.angle(dir); - if (a < 0.1 || (Math.PI - a) < 0.1) { - up.set(1.0, 0.0, 0.0); - } - + public Quat4d getControlPointOrientationQuat(Vector3d dir, double angle, boolean reversed) { + if (turnAxis == null) { + if (dir.lengthSquared() > MathTools.NEAR_ZERO) + dir.normalize(); + Quat4d q = getControlPointOrientationQuat(dir, angle); + if (reversed) { + Quat4d q2 = new Quat4d(); + q2.set(new AxisAngle4d(MathTools.Y_AXIS, Math.PI)); + q.mulInverse(q2); + } + return q; + } else { + if (dir.lengthSquared() > MathTools.NEAR_ZERO) + dir.normalize(); + return getControlPointOrientationQuat(dir, turnAxis, angle); + } + } - return getControlPointOrientationQuat(dir, up, angle); - } - - public static Quat4d getControlPointOrientationQuat(Vector3d dir, Vector3d up, double angle) { - if (dir.lengthSquared() < MathTools.NEAR_ZERO) - return MathTools.getIdentityQuat(); - - final Vector3d front = new Vector3d(1.0,0.0,0.0); - - Quat4d q1 = new Quat4d(); - - - Vector3d right = new Vector3d(); - - right.cross(dir, up); - up.cross(right, dir); - right.normalize(); - up.normalize(); - - Matrix3d m = new Matrix3d(); - m.m00 = dir.x; - m.m10 = dir.y; - m.m20 = dir.z; - m.m01 = up.x; - m.m11 = up.y; - m.m21 = up.z; - m.m02 = right.x; - m.m12 = right.y; - m.m22 = right.z; - - //q1.set(m); MathTools contains more stable conversion - MathTools.getQuat(m, q1); - -// if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right); - - Quat4d q2 = new Quat4d(); - q2.set(new AxisAngle4d(front, angle)); - q1.mul(q2); - return q1; - } - - public Vector3d getDirection(Direction direction) { - if (isDirected()) - return getDirectedControlPointDirection(); - if (isTurn() && isFixed()) { - if (direction == Direction.NEXT) { - if (previous != null) { - PipeControlPoint pcp = this; - Vector3d dir = new Vector3d(); - dir.sub(pcp.getWorldPosition(),previous.getWorldPosition()); - if (dir.lengthSquared() > MathTools.NEAR_ZERO) - dir.normalize(); - else - return null; - Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0); - AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle()); - Quat4d q2 = MathTools.getQuat(aa); - Vector3d v = new Vector3d(1.,0.,0.); - Vector3d offset = new Vector3d(); - MathTools.rotate(q2, v, offset); - MathTools.rotate(q, offset, dir); - return dir; - } - } else { - if (next != null) { - PipeControlPoint pcp = this; - Vector3d dir = new Vector3d(); - dir.sub(next.getWorldPosition(),pcp.getWorldPosition()); - if (dir.lengthSquared() > MathTools.NEAR_ZERO) - dir.normalize(); - else - return null; - Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0); - AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle()); - Quat4d q2 = MathTools.getQuat(aa); - Vector3d v = new Vector3d(1.,0.,0.); - Vector3d offset = new Vector3d(); - MathTools.rotate(q2, v, offset); - MathTools.rotate(q, offset, dir); - return dir; - } - } - } - return null; + public Quat4d getControlPointOrientationQuat(double angle, boolean reversed) { + Vector3d dir = getPathLegDirection(); + return getControlPointOrientationQuat(dir, angle, reversed); } - + + public Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) { + if (dir == null || dir.lengthSquared() < MathTools.NEAR_ZERO) + return MathTools.getIdentityQuat(); + + final P3DRootNode root = getRoot(); + Vector3d up = root != null ? new Vector3d(root.getUpVector()) : new Vector3d(0.0, 1.0, 0.0); + final Vector3d legDir = getPathLegEndpointVector(); + double a = up.angle(legDir); + if (a < 0.1 || (Math.PI - a) < 0.1) { + // Rotate components + up.set(up.getY(), up.getZ(), up.getX()); + } + + // Project up vector into a normal of the leg direction before applying to 'dir' + MathTools.mad(up, legDir, -legDir.dot(up)/legDir.lengthSquared()); + up.normalize(); + + return getControlPointOrientationQuat(dir, up, angle); + } + + public P3DRootNode getRoot() { + INode n = getParent(); + while (n != null && !(n instanceof P3DRootNode)) + n = n.getParent(); + return (P3DRootNode) n; + } + + public static Quat4d getControlPointOrientationQuat(Vector3d dir, Vector3d up, double angle) { + if (dir == null || dir.lengthSquared() < MathTools.NEAR_ZERO) + return MathTools.getIdentityQuat(); + + final Vector3d front = new Vector3d(1.0,0.0,0.0); + + Quat4d q1 = new Quat4d(); + + + Vector3d right = new Vector3d(); + + up = new Vector3d(up); + right.cross(dir, up); + up.cross(right, dir); + right.normalize(); + up.normalize(); + + Matrix3d m = new Matrix3d(); + m.m00 = dir.x; + m.m10 = dir.y; + m.m20 = dir.z; + m.m01 = up.x; + m.m11 = up.y; + m.m21 = up.z; + m.m02 = right.x; + m.m12 = right.y; + m.m22 = right.z; + + //q1.set(m); MathTools contains more stable conversion + MathTools.getQuat(m, q1); + + // if (DEBUG) System.out.println("PipingTools.getPipeComponentOrientationQuat() " + dir+ " " + up + " " + right); + + Quat4d q2 = new Quat4d(); + q2.set(new AxisAngle4d(front, angle)); + q1.mul(q2); + return q1; + } + public void insert(PipeControlPoint previous, PipeControlPoint next) { // inserting an offsetpoint is error, if (isDualSub()) throw new RuntimeException("Dual sub points cannot be inserted."); // size change control point cannot be inserted this way, because it ends PipeRun - if (isSizeChange()) - throw new RuntimeException("Size change points cannot be inserted."); +// if (isSizeChange()) +// throw new RuntimeException("Size change points cannot be inserted."); PipeRun piperun = previous.getPipeRun(); // and just to make sure that control point structure is not corrupted if (getPipeRun() != null) { @@ -533,14 +669,14 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } else { piperun.addChild(this); } - + // insert new BranchControlPoint between straight's control points PipeControlPoint previousNext = previous.getNext(); PipeControlPoint previousPrevious = previous.getPrevious(); - + PipeControlPoint offsetCP = null; if (isOffset()) { - offsetCP = getSubPoint().get(0); + offsetCP = getDualSub(); } if (previousNext != null && previousNext == next) { if (previous.isDualInline()) { @@ -555,7 +691,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { previous.getParentPoint().setNext(this); } this.setNext(next); - + if (offsetCP == null) { next.setPrevious(this); } else { @@ -563,17 +699,17 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { offsetCP.setNext(next); offsetCP.setPrevious(previous); } - + if (next.isDualInline()) { - next.getSubPoint().get(0).setPrevious(this); + next.getDualSub().setPrevious(this); } } else if (previousPrevious != null && previousPrevious == next) { - // control point were given in reverse order + // control point were given in reverse order if (next.isDualInline()) throw new RuntimeException(); if (previous.isDualSub()) throw new RuntimeException(); - + this.setNext(previous); if (offsetCP == null) { previous.setNext(this); @@ -583,23 +719,23 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { offsetCP.setPrevious(next); } if (previous.isDualInline()) { - previous.getSubPoint().get(0).setPrevious(this); + previous.getDualSub().setPrevious(this); } this.setPrevious(next); next.setNext(this); if (next.isDualSub()) { next.getParentPoint().setNext(this); } - + } else { throw new RuntimeException(); } - + PipingRules.validate(piperun); } - - - + + + public void insert(PipeControlPoint pcp, Direction direction) { if (isDualSub()) throw new RuntimeException(); @@ -614,9 +750,6 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { if (pcp.isDualSub()) { pcp.getParentPoint().setNext(this); } - if (isDualInline()) { - getSubPoint().get(0).setPrevious(this); - } } else { // if direction is previous, user must have given sizechange if (pcp.isDualSub()) @@ -625,7 +758,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { // we must link pcp to newCP's OffsetPoint PipeControlPoint nocp = null; if (isDualInline()) { - nocp = getSubPoint().get(0); + nocp = getDualSub(); nocp.setNext(pcp); } if (nocp == null) { @@ -635,17 +768,17 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } this.setNext(pcp); if (pcp.isDualInline()) { - PipeControlPoint ocp = pcp.getSubPoint().get(0); + PipeControlPoint ocp = pcp.getDualSub(); if (nocp == null) ocp.setPrevious(this); else ocp.setPrevious(nocp); } - + } PipingRules.validate(getPipeRun()); } - + public Vector3d getDirectedControlPointDirection() { assert (isDirected()); Vector3d dir = new Vector3d(); @@ -654,125 +787,210 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { return dir; } + /** + * Returns direction vector pointing towards an adjacent component for + * directed control points or turn control points with one open end. + * + * Always returns an outwards pointing vector. + * + * For any other type of component, the return value is null. + * + * For turn components this only return a non-null value for the unconnected + * end of the component. + * + * @param direction + * @return normalized vector, or null + */ + public Vector3d getDirection(Direction direction) { + if (isDirected()) + return getDirectedControlPointDirection(); + if (isTurn() && asFixedAngle()) { + if (direction == Direction.NEXT) { + if (previous != null) { + PipeControlPoint pcp = this; + Vector3d dir = new Vector3d(); + dir.sub(pcp.getWorldPosition(),previous.getWorldPosition()); + if (dir.lengthSquared() > MathTools.NEAR_ZERO) + dir.normalize(); + else + return null; + Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0); + AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle()); + Quat4d q2 = MathTools.getQuat(aa); + Vector3d v = new Vector3d(1.,0.,0.); + Vector3d offset = new Vector3d(); + MathTools.rotate(q2, v, offset); + MathTools.rotate(q, offset, dir); + dir.normalize(); + return dir; + } + } else { + if (next != null) { + PipeControlPoint pcp = this; + Vector3d dir = new Vector3d(); + dir.sub(next.getWorldPosition(),pcp.getWorldPosition()); + if (dir.lengthSquared() > MathTools.NEAR_ZERO) + dir.normalize(); + else + return null; + Quat4d q = getControlPointOrientationQuat(dir, pcp.getRotationAngle() != null ? pcp.getRotationAngle() : 0.0); + AxisAngle4d aa = new AxisAngle4d(MathTools.Y_AXIS,pcp.getTurnAngle() == null ? 0.0 : pcp.getTurnAngle()); + Quat4d q2 = MathTools.getQuat(aa); + Vector3d v = new Vector3d(1.,0.,0.); + Vector3d offset = new Vector3d(); + MathTools.rotate(q2, v, offset); + MathTools.rotate(q, offset, dir); + dir.negate(); + dir.normalize(); + return dir; + } + } + } + return null; + } + + /** + * Returns path leg direction of the control point. + * + * This method differs from getDirection by also returning inward pointing vectors for directed control points. + * + * @param direction + * @return + */ public Vector3d getPathLegDirection(Direction direction) { if (direction == Direction.NEXT) { - if (next != null) { - PipeControlPoint pcp = this; - if (pcp.isDualInline()) { - pcp = pcp.getSubPoint().get(0); - } - Vector3d v = new Vector3d(); - v.sub(next.getWorldPosition(),pcp.getWorldPosition()); - return v; - } else { - if (previous == null) { - if (!isDirected()) - throw new RuntimeException("Cannot calculate path leg direction for unconnected control point"); - return getDirectedControlPointDirection(); - - } else { - if (isVariableAngle()) - throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point"); - if (isInline()) { - PipeControlPoint pcp = this; - if (pcp.isDualSub()) { - pcp = pcp.getParentPoint(); - } - Vector3d v = new Vector3d(); - v.sub(pcp.getWorldPosition(),previous.getWorldPosition()); - return v; - } else if (isDirected()) { - return getDirectedControlPointDirection(); - } else if (isEnd()) { - Vector3d v = new Vector3d(); - v.sub(getWorldPosition(),previous.getWorldPosition()); - return v; - } else if (isTurn() && isFixed() && !_getReversed()) { - return getDirection(Direction.NEXT); - } - throw new RuntimeException("Missing implementation"); - } - } + return getPathLegDirectionNext(); } else { - if (previous != null) { - PipeControlPoint pcp = this; - if (isDualSub()) - pcp = getParentPoint(); - Vector3d v = new Vector3d(); - v.sub(previous.getWorldPosition(),pcp.getWorldPosition()); - return v; - } else { - if (next == null) { - if (!isDirected()) - throw new RuntimeException("Cannot calculate path leg direction for unconnected control point"); - Vector3d v = getDirectedControlPointDirection(); - v.negate(); - return v; - } else { - if (isVariableAngle()) - throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point"); - if (isInline()) { - PipeControlPoint pcp = this; - if (pcp.isDualInline()) { - pcp = pcp.getSubPoint().get(0); - } - Vector3d v = new Vector3d(); - v.sub(pcp.getWorldPosition(),next.getWorldPosition()); - return v; - } else if (isDirected()) { - Vector3d v = getDirectedControlPointDirection(); - v.negate(); - return v; - } else if (isEnd()) { - Vector3d v = new Vector3d(); - v.sub(getWorldPosition(),next.getWorldPosition()); - return v; - } else if (isTurn() && isFixed() && _getReversed()) { - return getDirection(Direction.PREVIOUS); - } - throw new RuntimeException("Missing implementation"); - } + return getPathLegDirectionPrevious(); + } + } + + public Vector3d getPathLegDirectionPrevious() { + if (previous != null) { + PipeControlPoint pcp = this; + if (isDualSub()) + pcp = getParentPoint(); + Vector3d v = new Vector3d(); + v.sub(previous.getWorldPosition(),pcp.getWorldPosition()); + if (v.lengthSquared() > MathTools.NEAR_ZERO) + v.normalize(); + else + return null; + return v; + } else if (isDirected()) { + Vector3d v = getDirectedControlPointDirection(); + v.negate(); + return v; + } else if (next == null) { + throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + this); + } else if (isVariableAngle() && !asFixedAngle()) { + throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + this); + } else if (isInline() || isEnd()) { + Vector3d v = getPathLegDirectionNext(); + if (v != null) v.negate(); + return v; + } else if (isTurn() && asFixedAngle() && _getReversed()) { + return getDirection(Direction.PREVIOUS); + } else { + throw new RuntimeException("Missing implementation " + this); + } + } + + public Vector3d getPathLegDirectionNext() { + if (next != null) { + PipeControlPoint pcp = this; + if (pcp.isDualInline()) { + pcp = pcp.getDualSub(); } + Vector3d v = new Vector3d(); + v.sub(next.getWorldPosition(),pcp.getWorldPosition()); + if (v.lengthSquared() > MathTools.NEAR_ZERO) + v.normalize(); + else + return null; + return v; + } else if (isDirected()) { + return getDirectedControlPointDirection(); + } else if (previous == null) { + throw new RuntimeException("Cannot calculate path leg direction for unconnected control point " + this); + } else if (isVariableAngle() && !asFixedAngle()) { + throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + this); + } else if (isInline() || isEnd()) { + Vector3d v = getPathLegDirectionPrevious(); + if (v != null) v.negate(); + return v; + } else if (isTurn() && asFixedAngle() && !_getReversed()) { + return getDirection(Direction.NEXT); + } else { + throw new RuntimeException("Missing implementation " + this); } } - + public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2) { assert (isInline()); + + PipeControlPoint sub = isAxial() ? this : getDualSub(); + Vector3d pos = getWorldPosition(), pos2 = sub == this ? pos : sub.getWorldPosition(); + Vector3d dir = sub.getInlineDir(); - Vector3d pos = getWorldPosition(); - Vector3d dir = getPathLegDirection(Direction.NEXT); - dir.normalize(); dir.scale(length * 0.5); p1.set(pos); - p2.set(pos); + p2.set(pos2); p1.sub(dir); p2.add(dir); } - + public void getControlPointEnds(Tuple3d p1, Tuple3d p2) { - Vector3d pos = getWorldPosition(); - Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS); - dir1.normalize(); - Vector3d dir2 = getPathLegDirection(Direction.NEXT); - dir2.normalize(); + PipeControlPoint sub = isAxial() || isDirected() || isTurn() ? this : getChildPoints().get(0); + Vector3d pos = getWorldPosition(), pos2 = sub == this ? pos : sub.getWorldPosition(); + + Vector3d dir1; + Vector3d dir2; if (isInline()) { - dir1.scale(length * 0.5); + dir2 = getInlineDir(); dir2.scale(length * 0.5); + dir1 = new Vector3d(dir2); + dir1.negate(); } else { + dir1 = getPathLegDirection(Direction.PREVIOUS); + dir2 = sub.getPathLegDirection(Direction.NEXT); dir1.scale(length); dir2.scale(length); } p1.set(pos); - p2.set(pos); + p2.set(pos2); p1.add(dir1); p2.add(dir2); } - + + /** + * Get both path leg directions, with (0,0,0) if no connection exists. The returned vectors are not normalized. + * + * @param v1 Set to the direction towards the previous control point on output + * @param v2 Set to the direction towards the next control point on output + */ + public void getEndDirections(Tuple3d v1, Tuple3d v2) { + PipeControlPoint sub = isAxial() ? this : getDualSub(); + + Vector3d dir1 = getPathLegDirection(Direction.PREVIOUS); + Vector3d dir2 = sub.getPathLegDirection(Direction.NEXT); + + if (dir1 != null) + v1.set(dir1); + else + v1.set(0,0,0); + + if (dir2 != null) + v2.set(dir2); + else + v2.set(0,0,0); + } + public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2, Vector3d dir) { assert (isInline()); - + Vector3d pos = getWorldPosition(); - dir.set(getPathLegDirection(Direction.NEXT)); + dir.set(getInlineDir()); dir.normalize(); dir.scale(length * 0.5); p1.set(pos); @@ -780,13 +998,13 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { p1.sub(dir); p2.add(dir); } - + public void getInlineControlPointEnds(Tuple3d center, Tuple3d p1, Tuple3d p2, Vector3d dir) { assert (isInline()); - + Vector3d pos = getWorldPosition(); center.set(pos); - dir.set(getPathLegDirection(Direction.NEXT)); + dir.set(getInlineDir()); dir.normalize(); dir.scale(length * 0.5); p1.set(pos); @@ -794,7 +1012,23 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { p1.sub(dir); p2.add(dir); } - + + public Vector3d getInlineDir() { + Vector3d dir = getPathLegDirection(Direction.NEXT); + if (dir == null) { + dir = getPathLegDirection(Direction.PREVIOUS); + if (dir != null) { + // Use reverse direction + dir.scale(-1.0); + } else { + // Control point is not connected at all, use current orientation + dir = new Vector3d(1,0,0); + MathTools.rotate(getWorldOrientation(), dir, dir); + } + } + return dir; + } + public double getInlineLength() { if (type == PointType.TURN) return length; @@ -802,22 +1036,38 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { return length * 0.5; return 0; } - + + /** + * Return the position indicated by the argument. If the indicated direction is not connected, the + * control point's wolrd position is returned instead. + * + * @param type A selector for the position to be returned + * @return The selected position + */ public Vector3d getRealPosition(PositionType type) { Vector3d pos = getWorldPosition(); switch (type) { case NEXT: { - Vector3d dir = getPathLegDirection(Direction.NEXT); double length = getInlineLength(); - dir.normalize(); + Vector3d dir; + if (isInline()) { + dir = getInlineDir(); + } else { + dir = getPathLegDirection(Direction.NEXT); + } dir.scale(length); pos.add(dir); break; } case PREVIOUS: { - Vector3d dir = getPathLegDirection(Direction.PREVIOUS); double length = getInlineLength(); - dir.normalize(); + Vector3d dir; + if (isInline()) { + dir = getInlineDir(); + dir.negate(); + } else { + dir = getPathLegDirection(Direction.PREVIOUS); + } dir.scale(length); pos.add(dir); break; @@ -829,11 +1079,11 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { case SPLIT: // do nothing break; - + } return pos; } - + public void getInlineMovement(Tuple3d start, Tuple3d end) { // FIXME : check type of neighbor components and allow movement on top of variable length components, // find proper range for movement (pcp's position is not) @@ -842,46 +1092,46 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { start.set(p.getWorldPosition()); end.set(n.getWorldPosition()); } - + public PipeControlPoint findNextEnd() { ArrayList t = new ArrayList(); - return findNextEnd( t); + return findNextEnd( t); } - + public PipeControlPoint findPreviousEnd() { ArrayList t = new ArrayList(); - return findPreviousEnd(t); + return findPreviousEnd(t); } - + public PipeControlPoint findNextEnd(List nextList) { - while (true) { - PipeControlPoint pcp = null; - PipeControlPoint p = null; - if (nextList.size() == 0) - p = this; - - else - p = nextList.get(nextList.size() - 1); - - pcp = p.getNext(); - if (pcp == null) { - pcp = p; - if (nextList.size() > 0) - nextList.remove(nextList.size() - 1); -// if (DEBUG) System.out.println(" " + pcp.getResource() + " not full"); - return pcp; - //break; - } - if (pcp.isPathLegEnd()) { - //if (DEBUG) System.out.println(" " + pcp.getResource()); - return pcp; - } else { - nextList.add(pcp); - // if (DEBUG) System.out.print(" " + pcp.getResource()); - } - } + while (true) { + PipeControlPoint pcp = null; + PipeControlPoint p = null; + if (nextList.size() == 0) + p = this; + + else + p = nextList.get(nextList.size() - 1); + + pcp = p.getNext(); + if (pcp == null) { + pcp = p; + if (nextList.size() > 0) + nextList.remove(nextList.size() - 1); + // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full"); + return pcp; + //break; + } + if (pcp.isPathLegEnd()) { + //if (DEBUG) System.out.println(" " + pcp.getResource()); + return pcp; + } else { + nextList.add(pcp); + // if (DEBUG) System.out.print(" " + pcp.getResource()); + } + } } - + public PipeControlPoint findPreviousEnd(List prevList) { while (true) { PipeControlPoint pcp = null; @@ -897,32 +1147,50 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { pcp = p; if (prevList.size() > 0) prevList.remove(prevList.size() - 1); -// if (DEBUG) System.out.println(" " + pcp.getResource() + " not full"); + // if (DEBUG) System.out.println(" " + pcp.getResource() + " not full"); return pcp; } if (pcp.isPathLegEnd()) { -// if (DEBUG) System.out.println(" " + pcp.getResource()); + // if (DEBUG) System.out.println(" " + pcp.getResource()); return pcp; } else { prevList.add(pcp); -// if (DEBUG)System.out.print(" " + pcp.getResource()); + // if (DEBUG)System.out.print(" " + pcp.getResource()); } } } public void _remove() { - if (component == null && next == null && previous == null) - return; - if (isDualInline() || isDualSub()) { - removeDualPoint(); - return; + _remove(true); + } + + + public PipeControlPoint getDualSub() { + if (isDualInline()) + return getChildPoints().get(0); + else + throw new IllegalStateException("Current control point is not dual inline"); + } + + + public void _remove(boolean renconnect) { + if (disposed) + return; + + if (DEBUG) System.out.println(this + " Remove " + renconnect); + + if (getParentPoint() != null) { + getParentPoint()._remove(renconnect); + return; } PipeRun pipeRun = getPipeRun(); - if (pipeRun == null) - return; - +// PipeRUn removal has been changed, so pipeRun may be null. +// if (pipeRun == null) +// return; + PipeControlPoint additionalRemove = null; if (!PipingRules.isEnabled()) { + component = null; setPrevious(null); setNext(null); } else { @@ -931,44 +1199,49 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { PipeControlPoint currentNext = next; if (currentNext == null && currentPrev == null) { removeComponent(); - pipeRun.remChild(this); + if (pipeRun != null) { + pipeRun.remChild(this); + checkRemove(pipeRun); + } return; } if (currentNext != null && currentPrev != null) { - boolean link = true; + boolean link = renconnect; if (currentNext.isBranchEnd()) { link = false; -// currentNext.setPrevious(null); -// currentNext.setNext(null); currentNext.remove(); currentNext = null; setNext(null); } if (currentPrev.isBranchEnd()) { link = false; -// currentPrev.setPrevious(null); -// currentPrev.setNext(null); currentPrev.remove(); currentPrev = null; setPrevious(null); } - if (link && currentPrev.isDirected() && currentNext.isDirected()) { - link = false; + if (link) { + if (currentPrev.isDirected() && currentNext.isDirected()) + link = false; + else if (this.isDualSub()) { + throw new RuntimeException("_remove() is called for parent point, somehow got to child point. " + this); + } } if (currentNext == null) { // Nothing to do } else if (currentNext.isDualInline()) { PipeControlPoint sccp = currentNext; - PipeControlPoint ocp = sccp.getSubPoint().get(0); + PipeControlPoint ocp = currentNext.getDualSub(); if (ocp == null) { throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point"); } if (link) { sccp.setPrevious(currentPrev); - ocp.setPrevious(currentPrev); + //ocp.setPrevious(currentPrev); + assert(ocp.getPrevious() == currentPrev); } else { sccp.setPrevious(null); - ocp.setPrevious(null); + //ocp.setPrevious(null); + assert(ocp.getPrevious() == null); } setNext(null); } else if (currentNext.isDualSub()) { @@ -980,6 +1253,16 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { currentNext.setPrevious(null); } setNext(null); + } else if (isDualInline()) { + if (currentNext.previous != getDualSub()) { + throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged"); + } + if (link) { + currentNext.setPrevious(currentPrev); + } else { + currentNext.setPrevious(null); + } + setNext(null); } else { throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged"); } @@ -989,15 +1272,17 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point"); } else if (currentPrev.isDualSub()) { PipeControlPoint ocp = currentPrev; - PipeControlPoint sccp = ocp.getParentPoint(); + PipeControlPoint sccp = currentPrev.getParentPoint(); if (sccp == null) throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point"); if (link) { - ocp.setNext(currentNext); + //ocp.setNext(currentNext); sccp.setNext(currentNext); + assert(ocp.getNext() == currentNext); } else { - ocp.setNext(null); + //ocp.setNext(null); sccp.setNext(null); + assert(ocp.getNext() == null); } setPrevious(null); } else if (currentPrev.next == this) { @@ -1005,7 +1290,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { currentPrev.setNext(currentNext); else currentPrev.setNext(null); - + setPrevious(null); } else { throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged"); @@ -1016,9 +1301,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { additionalRemove = currentPrev; // combine lengths and set the location of remaining control point to the center. Point3d ps = new Point3d(); - Point3d pe = new Point3d(); - Point3d ns = new Point3d(); - Point3d ne = new Point3d(); + Point3d pe = new Point3d(); + Point3d ns = new Point3d(); + Point3d ne = new Point3d(); currentPrev.getInlineControlPointEnds(ps, pe); currentNext.getInlineControlPointEnds(ns, ne); double l = currentPrev.getLength() + currentNext.getLength(); @@ -1031,36 +1316,42 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } else { // FIXME : pipe run must be split into two parts, since the control point structure is no more continuous. } - } else if (next != null) { - if (next.isDualInline()) { - PipeControlPoint sccp = next; - PipeControlPoint ocp = sccp.getSubPoint().get(0); + } else if (currentNext != null) { + if (currentNext.isDualInline()) { + PipeControlPoint sccp = currentNext; + PipeControlPoint ocp = currentNext.getDualSub(); if (ocp == null) { throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point"); } sccp.setPrevious(null); - ocp.setPrevious(null); - } else if (next.isDualSub()) { + assert(ocp.getPrevious() == null); + //ocp.setPrevious(null); + } else if (currentNext.isDualSub()) { throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point"); - } else if (next.previous == this) { - next.setPrevious(null); + } else if (currentNext.previous == this) { + currentNext.setPrevious(null); + } else if (isDualInline()) { + if (currentNext.previous != getDualSub()) { + throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged"); + } + currentNext.setPrevious(null); } else { throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged"); } setNext(null); } else { //(previous != null) - if(previous.isDualInline()) { + if(currentPrev.isDualInline()) { throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, previous control point is size change control point"); - } else if (previous.isDualSub()) { - PipeControlPoint ocp = previous; - PipeControlPoint sccp = ocp.getParentPoint(); + } else if (currentPrev.isDualSub()) { + PipeControlPoint ocp = currentPrev; + PipeControlPoint sccp = currentPrev.getParentPoint(); if (sccp == null) { throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point"); } - ocp.setNext(null); sccp.setNext(null); - } else if (previous.next == this) { - previous.setNext(null); + assert(ocp.getNext() == null); + } else if (currentPrev.next == this) { + currentPrev.setNext(null); } else { throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged"); } @@ -1071,97 +1362,163 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } else if (parent!= null) { removeParentPoint(); } - + } - + removeComponent(); - pipeRun.remChild(this); - checkRemove(pipeRun); - if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0) - PipingRules.validate(pipeRun); + if (pipeRun != null) { + pipeRun.remChild(this); + checkRemove(pipeRun); + if (PipingRules.isEnabled() && pipeRun.getParent() != null && pipeRun.getControlPoints().size() > 0) + PipingRules.validate(pipeRun); + } if (additionalRemove != null) additionalRemove.remove(); + disposed = true; } - + + /** + * Removes control point and attempts to reconnect next/prev + * + * If this point is size change (PipeRuns are different on both sides), then reconnection cannot be made. + */ public void remove() { PipeControlPoint currentPrev = previous; PipeControlPoint currentNext = next; _remove(); try { if (currentNext != null) - PipingRules.requestUpdate(currentNext); + if (!currentNext.checkRemove()) + PipingRules.requestUpdate(currentNext); if (currentPrev != null) - PipingRules.requestUpdate(currentPrev); + if (!currentPrev.checkRemove()) + PipingRules.requestUpdate(currentPrev); } catch (Exception e) { e.printStackTrace(); } } - private void checkRemove(PipeRun pipeRun) { + + /** + * Removes control point without attempting to reconnect next/prev. + * This usually leads to creation of another PipeRun for the control points after this point. + */ + public void removeAndSplit() { + PipeControlPoint currentPrev = previous; + PipeControlPoint currentNext = next; + + if (next != null && previous != null) { + P3DRootNode root = (P3DRootNode)getPipelineComponent().getRootNode(); + PipeRun nextPipeRun = new PipeRun(); + nextPipeRun.setName(root.getUniqueName("PipeRun")); + root.addChild(nextPipeRun); + + PipeRun previousRun = previous.getPipeRun(); + nextPipeRun.setPipeDiameter(previousRun.getPipeDiameter()); + nextPipeRun.setPipeThickness(previousRun.getPipeThickness()); + nextPipeRun.setTurnRadiusArray(previousRun.getTurnRadiusArray()); + + PipelineComponent n = next.getPipelineComponent(); + while (n != null) { + if (n.getPipeRun() != previousRun) + break; + if (! (n instanceof Nozzle)) { + n.deattach(); + nextPipeRun.addChild(n); + } else + n.setPipeRun(nextPipeRun); + n = n.getNext(); + } + } + _remove(false); + try { + if (currentNext != null) + if (!currentNext.checkRemove()) + PipingRules.requestUpdate(currentNext); + if (currentPrev != null) + if (!currentPrev.checkRemove()) + PipingRules.requestUpdate(currentPrev); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * This is called when adjacent control point is removed. + * + * This call should remove the give point, if the point cannot exist alone. + * At the moment there is one such case: branch. + * + * @return + */ + protected boolean checkRemove() { + if (getParentPoint() != null) { + return getParentPoint().checkRemove(); + } else { + if (getPipelineComponent() == null) + return true; // already removed + if (getPipelineComponent().getType().equals("Plant3D.URIs.Builtin_BranchSplitComponent")) { + if (getChildPoints().get(0).getNext() == null && getChildPoints().get(0).getPrevious() == null) { + remove(); + return true; + } + } + return checkRemove(getPipeRun()); + } + } + + private boolean checkRemove(PipeRun pipeRun) { + if (pipeRun == null) + return false; Collection points = pipeRun.getControlPoints(); if (points.size() == 0) { pipeRun.remove(); + return true; } else if (points.size() == 1) { PipeControlPoint pcp = points.iterator().next(); - if (pcp.isDeletable()) - pcp._remove(); - } - } - - private void removeDualPoint() { - if (previous != null) - previous.setNext(null); - if (next != null) - next.setPrevious(null); - PipeControlPoint ocp; - PipeControlPoint sccp; - if (isDualInline()) { - sccp = this; - ocp = getSubPoint().get(0); - } else { - ocp = this; - sccp = getParentPoint(); + if (pcp.isDeletable() && pcp.getNext() == null && pcp.getPrevious() == null) { + pcp._remove(); // This call will recursively call also this method... + return true; + } + } else if (points.size() == 2) { + } - PipeRun p1 = ocp.getPipeRun(); - PipeRun p2 = sccp.getPipeRun(); - - ocp.removeComponent(); - sccp.removeComponent(); - - p1.remChild(ocp); - p2.remChild(sccp); - - // TODO : now we assume that this is size change, and we do - if (ocp.next != null) - ocp.next.setPrevious(null); - if (ocp.previous != null) - ocp.previous.setNext(null); - if (sccp.next != null) - sccp.next.setPrevious(null); - if (sccp.previous != null) - sccp.previous.setNext(null); - ocp.setNext(null); - ocp.setPrevious(null); - sccp.setNext(null); - sccp.setPrevious(null); - - checkRemove(p1); - checkRemove(p2); + return false; } - + private void removeSubPoints() { for (PipeControlPoint p : children) { - // TODO : this may affect delete routine, since classification of the point changes. p.parent = null; - p._remove(); + p.component = null; + //p._remove(); + PipeControlPoint currentNext = p.getNext(); + PipeControlPoint currentPrev = p.getPrevious(); + p._setNext(null); + p._setPrevious(null); + PipeRun run = p.getPipeRun(); + if (run != null) { + run.remChild(p); + checkRemove(run); + } + if (currentNext != null) + if (!currentNext.checkRemove()) + PipingRules.requestUpdate(currentNext); + if (currentPrev != null) + if (!currentPrev.checkRemove()) + PipingRules.requestUpdate(currentPrev); + } children.clear(); } - + private void removeParentPoint() { throw new RuntimeException("Child points cannot be removed directly"); } + public boolean isRemoved() { + return component == null; + } + private void removeComponent() { if (component == null) return; @@ -1177,7 +1534,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { else if (next.getPrevious() == component) next.setPrevious(null); else if (next.getBranch0() == component) - next.setBranch0(null); + next.setBranch0(null); } if (prev != null) { if (prev.getNext() == component) @@ -1185,32 +1542,34 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { else if (prev.getPrevious() == component) prev.setPrevious(null); else if (prev.getBranch0() == component) - prev.setBranch0(null); + prev.setBranch0(null); } if (br0 != null) { - if (br0.getNext() == component) - br0.setNext(null); - else if (br0.getPrevious() == component) - br0.setPrevious(null); - else if (br0.getBranch0() == component) - br0.setBranch0(null); + if (br0.getNext() == component) + br0.setNext(null); + else if (br0.getPrevious() == component) + br0.setPrevious(null); + else if (br0.getBranch0() == component) + br0.setBranch0(null); } PipelineComponent comp = component; component = null; - + comp.remove(); } - + @Override public void setOrientation(Quat4d orientation) { if (MathTools.equals(orientation, getOrientation())) return; + if (getPipelineComponent() != null && (getPipelineComponent() instanceof Nozzle)) + System.out.println(); super.setOrientation(orientation); if (getParentPoint() == null && component != null) component._setWorldOrientation(getWorldOrientation()); updateSubPoint(); } - + @Override public void setPosition(Vector3d position) { if (MathTools.equals(position, getPosition())) @@ -1226,39 +1585,54 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { private void updateSubPoint() { if (isOffset()) { if (next == null && previous == null) { - for (PipeControlPoint sub : getSubPoint()) { + for (PipeControlPoint sub : getChildPoints()) { sub.setWorldPosition(getWorldPosition()); sub.setWorldOrientation(getWorldOrientation()); } return; } - for (PipeControlPoint sub : getSubPoint()) { + for (PipeControlPoint sub : getChildPoints()) { Vector3d wp = getWorldPosition(); wp.add(getSizeChangeOffsetVector()); sub.setWorldPosition(wp); sub.setWorldOrientation(getWorldOrientation()); } } else { - for (PipeControlPoint sub : getSubPoint()) { + for (PipeControlPoint sub : getChildPoints()) { sub.setWorldPosition(getWorldPosition()); sub.setWorldOrientation(getWorldOrientation()); } } } - + public void _setWorldPosition(Vector3d position) { Vector3d localPos = getLocalPosition(position); super.setPosition(localPos); updateSubPoint(); } - + public void _setWorldOrientation(Quat4d orientation) { Quat4d localOr = getLocalOrientation(orientation); super.setOrientation(localOr); updateSubPoint(); } - + + public void orientToDirection(Vector3d dir) { + Double angleO = getRotationAngle(); + double angle = 0.0; + if (angleO != null) + angle = angleO; + boolean reversed = _getReversed(); + Quat4d q = null; + if (dir != null) { + q = getControlPointOrientationQuat(dir, angle, reversed); + } else { + q = getControlPointOrientationQuat(angle, reversed); + } + setWorldOrientation(q); + } + @Override public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode());