--- /dev/null
+package org.simantics.plant3d.scenegraph.controlpoint;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Matrix3d;
+import javax.vecmath.Quat4d;
+import javax.vecmath.Tuple3d;
+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.plant3d.scenegraph.IP3DNode;
+import org.simantics.plant3d.scenegraph.PipeRun;
+import org.simantics.plant3d.scenegraph.PipelineComponent;
+
+import vtk.vtkRenderer;
+
+
+public class PipeControlPoint extends G3DNode implements IP3DNode {
+
+ public enum Type{INLINE,TURN,END};
+ public enum Direction{NEXT,PREVIOUS};
+ public enum PositionType {SPLIT,NEXT,PREVIOUS,PORT}
+
+ private PipelineComponent component;
+
+ private Type type;
+ private boolean fixed = true;
+ private boolean deletable = true;
+ private boolean sub = 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 {
+ PipingRules.requestUpdate(this);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ public PipeRun getPipeRun() {
+ return (PipeRun)getParent();
+ }
+
+ public PipelineComponent getPipelineComponent() {
+ return component;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+
+ @GetPropertyValue(name="Fixed",tabId="Debug",value="fixed")
+ public boolean isFixed() {
+ return fixed;
+ }
+
+
+ public void setFixed(boolean fixed) {
+ this.fixed = fixed;
+ }
+
+ public void setSub(boolean sub) {
+ this.sub = sub;
+ }
+
+ @GetPropertyValue(name="Deletable",tabId="Debug",value="deletable")
+ public boolean isDeletable() {
+ return deletable;
+ }
+
+ public void setDeletable(boolean deletable) {
+ this.deletable = deletable;
+ }
+
+ public boolean isPathLegEnd() {
+ return type != Type.INLINE;
+ }
+
+ public boolean isEnd() {
+ return type == Type.END;
+ }
+
+ public boolean isTurn() {
+ return type == Type.TURN;
+ }
+
+ public boolean isInline() {
+ return type == Type.INLINE;
+ }
+
+ public boolean isDirected() {
+ return fixed && isEnd();
+ }
+
+ public boolean isNonDirected() {
+ return !fixed && isEnd();
+ }
+
+ public boolean isVariableLength() {
+ return !fixed && isInline();
+ }
+
+ public boolean isVariableAngle() {
+ return !fixed && isTurn();
+ }
+
+ public boolean isBranchEnd() {
+ return deletable && isEnd();
+ }
+
+ public boolean isOffset() {
+ return offset != null;
+ }
+
+ public boolean isDualSub() {
+ return parent != null && sub;
+ }
+
+ public boolean isDualInline() {
+ return children.size() == 1 && children.get(0).isDualSub();
+ }
+
+ public boolean isSizeChange() {
+ if (children.size() == 0)
+ return false;
+ if (!isDualInline())
+ return false;
+ return getPipeRun() != children.get(0).getPipeRun();
+ }
+
+
+ private PipeControlPoint next;
+ private PipeControlPoint previous;
+
+ public PipeControlPoint getNext() {
+ return next;
+ }
+
+ public PipeControlPoint getPrevious() {
+ return previous;
+ }
+
+ public void setNext(PipeControlPoint next) {
+ if (isEnd() && previous != null && next != null)
+ throw new RuntimeException("End control points are allowed to have only one connection");
+// if (next != null && getPipeRun() == null)
+// throw new RuntimeException("Cannot connect control point befor piperun has been set");
+ this.next = next;
+ if (component != null) {
+ if (parent == null || sub)
+ component.setNext(next != null ? next.component : null);
+ else
+ component.setBranch0(next != null ? next.component : null);
+ }
+ }
+
+ public void setPrevious(PipeControlPoint previous) {
+ if (isEnd() && next != null && previous != null)
+ throw new RuntimeException("End control points are allowed to have only one connection");
+// if (previous != null && getPipeRun() == null)
+// throw new RuntimeException("Cannot connect control point befor piperun has been set");
+ this.previous = previous;
+ if (component != null)
+ if (parent == null || sub)
+ component.setPrevious(previous != null ? previous.component : null);
+ else
+ component.setBranch0(previous != null ? previous.component : null);
+ }
+
+ public PipeControlPoint parent;
+ public List<PipeControlPoint> children = new ArrayList<PipeControlPoint>();
+
+ public List<PipeControlPoint> getSubPoint() {
+ return children;
+ }
+
+ public PipeControlPoint getParentPoint() {
+ return parent;
+ }
+
+
+
+
+
+
+
+
+ private double length;
+ private Double turnAngle;
+ private Vector3d turnAxis;
+
+ private Double offset;
+ private Double rotationAngle;
+
+ @GetPropertyValue(name="Length",tabId="Debug",value="length")
+ public double getLength() {
+ return length;
+ }
+
+ public void setLength(double l) {
+ 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);
+ }
+
+ @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;
+ }
+
+ public void setTurnAngle(Double turnAngle) {
+ if (Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
+ return;
+ }
+ if (this.turnAngle != null && Math.abs(this.turnAngle-turnAngle) < MathTools.NEAR_ZERO)
+ return;
+ this.turnAngle = turnAngle;
+ firePropertyChanged("turnAngle");
+ }
+
+ public void setTurnAxis(Vector3d turnAxis) {
+ 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;
+ 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;
+ this.rotationAngle = rotationAngle;
+ firePropertyChanged("rotationAngle");
+ }
+
+ public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
+ if (rotationAngle == null)
+ rotationAngle = 0.0;
+ Quat4d q = getControlPointOrientationQuat(dir, rotationAngle);
+ Vector3d v = new Vector3d(0.0,0.0,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();
+ }
+
+ 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 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);
+ }
+
+
+ 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() {
+ return getDirectedControlPointDirection();
+ }
+
+
+
+
+
+
+
+ public void insert(PipeControlPoint previous, PipeControlPoint next) {
+ // inserting an offsetpoint is error,
+ if (isDualSub())
+ throw new RuntimeException();
+ // size change control point cannot be inserted this way, because it ends PipeRun
+ if (isSizeChange())
+ throw new RuntimeException();
+ PipeRun piperun = previous.getPipeRun();
+ // and just to make sure that control point structure is not corrupted
+ if (getPipeRun() != null) {
+ if (piperun != getPipeRun() || piperun != next.getPipeRun())
+ throw new RuntimeException();
+ } 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);
+ }
+ if (previousNext != null && previousNext == next) {
+ if (previous.isDualInline()) {
+ throw new RuntimeException();
+ }
+ if (next.isDualSub()) {
+ throw new RuntimeException();
+ }
+ previous.setNext(this);
+ this.setPrevious(previous);
+ if (previous.isDualSub()) {
+ previous.getParentPoint().setNext(this);
+ }
+ this.setNext(next);
+
+ if (offsetCP == null) {
+ next.setPrevious(this);
+ } else {
+ next.setPrevious(offsetCP);
+ offsetCP.setNext(next);
+ offsetCP.setPrevious(previous);
+ }
+
+ if (next.isDualInline()) {
+ next.getSubPoint().get(0).setPrevious(this);
+ }
+ } else if (previousPrevious != null && previousPrevious == next) {
+ // 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);
+ } else {
+ previous.setPrevious(offsetCP);
+ offsetCP.setNext(previous);
+ offsetCP.setPrevious(next);
+ }
+ if (previous.isDualInline()) {
+ previous.getSubPoint().get(0).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();
+ if (direction == Direction.NEXT) {
+ // if direction is next, user must have given OffsetPoint
+ if (pcp.isDualInline())
+ throw new RuntimeException();
+ // basic next/prev links
+ pcp.setNext(this);
+ this.setPrevious(pcp);
+ // and last take care of sizechange / offset points
+ 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())
+ throw new RuntimeException();
+ // previous direction is more complicated, since if newCP is SizeChangeControlPoint,
+ // we must link pcp to newCP's OffsetPoint
+ PipeControlPoint nocp = null;
+ if (isDualInline()) {
+ nocp = getSubPoint().get(0);
+ nocp.setNext(pcp);
+ }
+ if (nocp == null) {
+ pcp.setPrevious(this);
+ } else {
+ pcp.setPrevious(nocp);
+ }
+ this.setNext(pcp);
+ if (pcp.isDualInline()) {
+ PipeControlPoint ocp = pcp.getSubPoint().get(0);
+ if (nocp == null)
+ ocp.setPrevious(this);
+ else
+ ocp.setPrevious(nocp);
+ }
+
+ }
+ PipingRules.validate(getPipeRun());
+ }
+
+ public Vector3d getDirectedControlPointDirection() {
+ assert (isDirected());
+ Vector3d dir = new Vector3d();
+ MathTools.rotate(getWorldOrientation(), new Vector3d(1.0, 0.0, 0.0), dir);
+ dir.normalize();
+ return dir;
+ }
+
+ 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 (isVariableAngle())
+ throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
+ if (previous == null) {
+ if (!isDirected())
+ throw new RuntimeException("Cannot calculate path leg direction for unconnected control point");
+ return getDirectedControlPointDirection();
+
+ } else {
+ if (isInline()) {
+ Vector3d v = new Vector3d();
+ v.sub(getWorldPosition(),previous.getWorldPosition());
+ return v;
+ } else if (isDirected()) {
+ return getDirectedControlPointDirection();
+ } else if (isEnd()) {
+ Vector3d v = new Vector3d();
+ v.sub(getWorldPosition(),previous.getWorldPosition());
+ return v;
+ }
+ throw new RuntimeException("Missing implementation");
+ }
+ }
+ } 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 (isVariableAngle())
+ throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point");
+ 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 (isInline()) {
+ Vector3d v = new Vector3d();
+ v.sub(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;
+ }
+ throw new RuntimeException("Missing implementation");
+ }
+ }
+ }
+ }
+
+ public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2) {
+ assert (isInline());
+
+ Vector3d pos = getWorldPosition();
+ Vector3d dir = getPathLegDirection(Direction.NEXT);
+ dir.normalize();
+ dir.scale(length * 0.5);
+ p1.set(pos);
+ p2.set(pos);
+ 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();
+ if (isInline()) {
+ dir1.scale(length * 0.5);
+ dir2.scale(length * 0.5);
+ } else {
+ dir1.scale(length);
+ dir2.scale(length);
+ }
+ p1.set(pos);
+ p2.set(pos);
+ p1.add(dir1);
+ p2.add(dir2);
+ }
+
+ public void getInlineControlPointEnds(Tuple3d p1, Tuple3d p2, Vector3d dir) {
+ assert (isInline());
+
+ Vector3d pos = getWorldPosition();
+ dir.set(getPathLegDirection(Direction.NEXT));
+ dir.normalize();
+ dir.scale(length * 0.5);
+ p1.set(pos);
+ p2.set(pos);
+ 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.normalize();
+ dir.scale(length * 0.5);
+ p1.set(pos);
+ p2.set(pos);
+ p1.sub(dir);
+ p2.add(dir);
+ }
+
+ public double getInlineLength() {
+ if (type == Type.TURN)
+ return length;
+ else if (type == Type.INLINE)
+ return length * 0.5;
+ return 0;
+ }
+
+ public Vector3d getRealPosition(PositionType type) {
+ Vector3d pos = getWorldPosition();
+ switch (type) {
+ case NEXT: {
+ Vector3d dir = getPathLegDirection(Direction.NEXT);
+ double length = getInlineLength();
+ dir.normalize();
+ dir.scale(length);
+ pos.add(dir);
+ break;
+ }
+ case PREVIOUS: {
+ Vector3d dir = getPathLegDirection(Direction.PREVIOUS);
+ double length = getInlineLength();
+ dir.normalize();
+ dir.scale(length);
+ pos.add(dir);
+ break;
+ }
+ case PORT:
+ // IEntity portDir = pcp.getSingleRelatedObject(ProcessResource.plant3Dresource.HasDirection);
+ // TODO : how we calculated needed space for a port; does it has an offset from control point's position or not?
+ break;
+ 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)
+ PipeControlPoint p = previous.getPrevious();
+ PipeControlPoint n = next.getNext();
+ start.set(p.getWorldPosition());
+ end.set(n.getWorldPosition());
+ }
+
+ public PipeControlPoint findNextEnd() {
+ ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
+ return findNextEnd( t);
+ }
+
+ public PipeControlPoint findPreviousEnd() {
+ ArrayList<PipeControlPoint> t = new ArrayList<PipeControlPoint>();
+ return findPreviousEnd(t);
+ }
+
+ public PipeControlPoint findNextEnd(List<PipeControlPoint> 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());
+ }
+ }
+ }
+
+ public PipeControlPoint findPreviousEnd(List<PipeControlPoint> prevList) {
+ while (true) {
+ PipeControlPoint pcp = null;
+ PipeControlPoint p = null;
+ if (prevList.size() == 0)
+ p = this;
+
+ else
+ p = prevList.get(prevList.size() - 1);
+
+ pcp = p.getPrevious();
+ if (pcp == null) {
+ pcp = p;
+ if (prevList.size() > 0)
+ prevList.remove(prevList.size() - 1);
+// if (DEBUG) System.out.println(" " + pcp.getResource() + " not full");
+ return pcp;
+ }
+ if (pcp.isPathLegEnd()) {
+// if (DEBUG) System.out.println(" " + pcp.getResource());
+ return pcp;
+ } else {
+ prevList.add(pcp);
+// if (DEBUG)System.out.print(" " + pcp.getResource());
+ }
+ }
+ }
+
+ public void _remove() {
+ if (component == null && next == null && previous == null)
+ return;
+ if (isDualInline() || isDualSub()) {
+ removeDualPoint();
+ return;
+ }
+ PipeRun pipeRun = getPipeRun();
+ if (pipeRun == null)
+ return;
+
+ PipeControlPoint additionalRemove = null;
+ if (!PipingRules.isEnabled()) {
+ setPrevious(null);
+ setNext(null);
+ } else {
+
+ PipeControlPoint currentPrev = previous;
+ PipeControlPoint currentNext = next;
+ if (currentNext == null && currentPrev == null) {
+ removeComponent();
+ pipeRun.remChild(this);
+ return;
+ }
+ if (currentNext != null && currentPrev != null) {
+ boolean link = true;
+ 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 (currentNext == null) {
+ // Nothing to do
+ } else if (currentNext.isDualInline()) {
+ PipeControlPoint sccp = currentNext;
+ PipeControlPoint ocp = sccp.getSubPoint().get(0);
+ if (ocp == null) {
+ throw new RuntimeException("Removing PipeControlPoint " + this+ " structure damaged, no offset control point");
+ }
+ if (link) {
+ sccp.setPrevious(currentPrev);
+ ocp.setPrevious(currentPrev);
+ } else {
+ sccp.setPrevious(null);
+ ocp.setPrevious(null);
+ }
+ setNext(null);
+ } else if (currentNext.isDualSub()) {
+ throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
+ } else if (currentNext.previous == this) {
+ if (link) {
+ currentNext.setPrevious(currentPrev);
+ } else {
+ currentNext.setPrevious(null);
+ }
+ setNext(null);
+ } else {
+ throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
+ }
+ if (currentPrev == null) {
+ // Nothing to do
+ } else if (currentPrev.isDualInline()) {
+ 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();
+ if (sccp == null)
+ throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, no size change control point");
+ if (link) {
+ ocp.setNext(currentNext);
+ sccp.setNext(currentNext);
+ } else {
+ ocp.setNext(null);
+ sccp.setNext(null);
+ }
+ setPrevious(null);
+ } else if (currentPrev.next == this) {
+ if (link)
+ currentPrev.setNext(currentNext);
+ else
+ currentPrev.setNext(null);
+
+ setPrevious(null);
+ } else {
+ throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged");
+ }
+ if (link) {
+ if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
+ // we have to join them into single variable length component.
+ additionalRemove = currentPrev;
+ //currentPrev.remove();
+ }
+ } 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);
+ 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()) {
+ throw new RuntimeException("Removing PipeControlPoint " + this + " structure damaged, next control point is offset control point");
+ } else if (next.previous == this) {
+ next.setPrevious(null);
+ } else {
+ throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
+ }
+ setNext(null);
+ } else { //(previous != null)
+ if(previous.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();
+ 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);
+ } else {
+ throw new RuntimeException("Removing PipeControlPoint "+ this+ " structure damaged");
+ }
+ setPrevious(null);
+ }
+ if (children.size() > 0 ) {
+ removeSubPoints();
+ } 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 (additionalRemove != null)
+ additionalRemove.remove();
+ }
+
+ public void remove() {
+ PipeControlPoint currentPrev = previous;
+ PipeControlPoint currentNext = next;
+ _remove();
+ try {
+ if (currentNext != null)
+ PipingRules.requestUpdate(currentNext);
+ if (currentPrev != null)
+ PipingRules.requestUpdate(currentPrev);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void checkRemove(PipeRun pipeRun) {
+ Collection<PipeControlPoint> points = pipeRun.getControlPoints();
+ if (points.size() == 0) {
+ pipeRun.remove();
+ } 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();
+ }
+ PipeRun p1 = ocp.getPipeRun();
+ PipeRun p2 = sccp.getPipeRun();
+
+ ocp.removeComponent();
+ sccp.removeComponent();
+
+ p1.remChild(ocp);
+ p2.remChild(sccp);
+
+ ocp.setNext(null);
+ ocp.setPrevious(null);
+ sccp.setNext(null);
+ sccp.setPrevious(null);
+
+ checkRemove(p1);
+ checkRemove(p2);
+ }
+
+ private void removeSubPoints() {
+ for (PipeControlPoint p : children) {
+ // TODO : this may affect delete routine, since classification of the point changes.
+ p.parent = null;
+ p._remove();
+ }
+ children.clear();
+ }
+
+ private void removeParentPoint() {
+ throw new RuntimeException("Child points cannot be removed directly");
+ }
+
+ private void removeComponent() {
+ if (component == null)
+ return;
+ PipelineComponent next = component.getNext();
+ PipelineComponent prev = component.getNext();
+ if (next != null) {
+ if (next.getNext() == component)
+ next.setNext(null);
+ else if (next.getPrevious() == component)
+ next.setPrevious(null);
+ }
+ if (prev != null) {
+ if (prev.getNext() == component)
+ prev.setNext(null);
+ else if (prev.getPrevious() == component)
+ prev.setPrevious(null);
+ }
+ PipelineComponent comp = component;
+ component = null;
+ comp.remove();
+ }
+
+ @Override
+ public void setOrientation(Quat4d orientation) {
+ if (MathTools.equals(orientation, getOrientation()))
+ return;
+ super.setOrientation(orientation);
+ if (getParentPoint() == null && component != null)
+ component._setWorldOrientation(getWorldOrientation());
+ for (PipeControlPoint sub : getSubPoint()) {
+ sub.setWorldPosition(getWorldPosition());
+ sub.setWorldOrientation(getWorldOrientation());
+ }
+ }
+
+ @Override
+ public void setPosition(Vector3d position) {
+ if (MathTools.equals(position, getPosition()))
+ return;
+ super.setPosition(position);
+ if (getParentPoint() == null && component != null)
+ component._setWorldPosition(getWorldPosition());
+ for (PipeControlPoint sub : getSubPoint()) {
+ sub.setWorldPosition(getWorldPosition());
+ sub.setWorldOrientation(getWorldOrientation());
+ }
+ }
+
+
+ public void _setWorldPosition(Vector3d position) {
+ Vector3d localPos = getLocalPosition(position);
+ super.setPosition(localPos);
+ for (PipeControlPoint sub : getSubPoint()) {
+ sub.setWorldPosition(getWorldPosition());
+ sub.setWorldOrientation(getWorldOrientation());
+ }
+ }
+
+ public void _setWorldOrientation(Quat4d orientation) {
+ Quat4d localOr = getLocalOrientation(orientation);
+ super.setOrientation(localOr);
+ for (PipeControlPoint sub : getSubPoint()) {
+ sub.setWorldPosition(getWorldPosition());
+ sub.setWorldOrientation(getWorldOrientation());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "@" + Integer.toHexString(hashCode());
+ }
+
+}