package org.simantics.plant3d.scenegraph.controlpoint;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Matrix3d;
+import javax.vecmath.Point3d;
import javax.vecmath.Quat4d;
import javax.vecmath.Tuple3d;
import javax.vecmath.Vector3d;
public class PipeControlPoint extends G3DNode implements IP3DNode {
+
+ private static boolean DEBUG = false;
public enum Type{INLINE,TURN,END};
public enum Direction{NEXT,PREVIOUS};
private Type type;
private boolean fixed = true;
+ private boolean rotate = false;
+ private boolean reverse = false;
private boolean deletable = true;
private boolean sub = false;
this.fixed = fixed;
}
+ @GetPropertyValue(name="Rotate",tabId="Debug",value="rotate")
+ public boolean isRotate() {
+ return rotate;
+ }
+
+ public void setRotate(boolean rotate) {
+ this.rotate = rotate;
+ }
+
+ @GetPropertyValue(name="Reverse",tabId="Debug",value="reverse")
+ public boolean isReverse() {
+ return reverse;
+ }
+
+ public void setReverse(boolean reverse) {
+ this.reverse = reverse;
+ }
+
public void setSub(boolean sub) {
this.sub = sub;
}
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");
+ if (this.next == next)
+ return;
+ if (DEBUG) System.out.println(this + " next " + next);
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);
+ updateSubPoint();
}
+
}
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");
+ if (this.previous == previous)
+ return;
+ if (DEBUG) System.out.println(this + " previous " + previous);
this.previous = previous;
- if (component != null)
+ if (component != null) {
if (parent == null || sub)
component.setPrevious(previous != null ? previous.component : null);
else
component.setBranch0(previous != null ? previous.component : null);
+ updateSubPoint();
+ }
+
}
public PipeControlPoint parent;
public PipeControlPoint getParentPoint() {
return parent;
}
-
-
-
-
-
-
private double length;
private Double turnAngle;
private Vector3d turnAxis;
private Double offset;
private Double rotationAngle;
+ private Boolean reversed;
@GetPropertyValue(name="Length",tabId="Debug",value="length")
public double getLength() {
return rotationAngle;
}
+ @GetPropertyValue(name="Reversed",tabId="Debug",value="reversed")
+ public Boolean getReversed() {
+ return reversed;
+ }
+
+ public boolean _getReversed() {
+ if (reversed == null)
+ return false;
+ return reversed;
+ }
+
public void setTurnAngle(Double turnAngle) {
if (Double.isInfinite(turnAngle) || Double.isNaN(turnAngle)) {
return;
}
public void setTurnAxis(Vector3d turnAxis) {
- this.turnAxis = turnAxis;
+ if (this.turnAxis != null && MathTools.equals(turnAxis, this.turnAxis))
+ return;
+ this.turnAxis = turnAxis;
firePropertyChanged("turnAxis");
}
firePropertyChanged("rotationAngle");
}
+ public void setReversed(Boolean reversed) {
+ this.reversed = reversed;
+ firePropertyChanged("reversed");
+ }
+
public Vector3d getSizeChangeOffsetVector(Vector3d dir) {
+ Quat4d q;
+ if (rotationAngle == null)
+ q = getControlPointOrientationQuat(dir, 0.0);
+ 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;
+ }
+
+ public Vector3d getSizeChangeOffsetVector() {
+ Quat4d q;
if (rotationAngle == null)
- rotationAngle = 0.0;
- Quat4d q = getControlPointOrientationQuat(dir, rotationAngle);
- Vector3d v = new Vector3d(0.0,0.0,offset);
+ q = getControlPointOrientationQuat(0.0);
+ else
+ q = getControlPointOrientationQuat(rotationAngle);
+ Vector3d v = new Vector3d(0.0,offset,0.0);
Vector3d offset = new Vector3d();
MathTools.rotate(q, v, offset);
return offset;
return previous.toString();
}
- public Quat4d getControlPointOrientationQuat(double angle) {
+ @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 Quat4d getControlPointOrientationQuat(double angle) {
if (turnAxis == null) {
Vector3d dir = getPathLegDirection(Direction.NEXT);
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);
+ }
+ }
- public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
+ public static Quat4d getControlPointOrientationQuat(Vector3d dir, double angle) {
if (dir.lengthSquared() < MathTools.NEAR_ZERO)
return MathTools.getIdentityQuat();
return q1;
}
- public Vector3d getDirection() {
- return getDirectedControlPointDirection();
+ 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 void insert(PipeControlPoint previous, PipeControlPoint next) {
// inserting an offsetpoint is error,
if (isDualSub())
- throw new RuntimeException();
+ 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();
+ 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) {
if (piperun != getPipeRun() || piperun != next.getPipeRun())
- throw new RuntimeException();
+ throw new RuntimeException("All controls points must be located on the same pipe run");
} else {
piperun.addChild(this);
}
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 (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(getWorldPosition(),previous.getWorldPosition());
+ v.sub(pcp.getWorldPosition(),previous.getWorldPosition());
return v;
} else if (isDirected()) {
return getDirectedControlPointDirection();
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");
}
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");
v.negate();
return v;
} else {
- if (isInline()) {
+ 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(getWorldPosition(),next.getWorldPosition());
+ v.sub(pcp.getWorldPosition(),next.getWorldPosition());
return v;
} else if (isDirected()) {
Vector3d v = getDirectedControlPointDirection();
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");
}
}
if (currentNext.isVariableLength() && currentPrev.isVariableLength()) {
// we have to join them into single variable length component.
additionalRemove = currentPrev;
- //currentPrev.remove();
+ // 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();
+ currentPrev.getInlineControlPointEnds(ps, pe);
+ currentNext.getInlineControlPointEnds(ns, ne);
+ double l = currentPrev.getLength() + currentNext.getLength();
+ Vector3d cp = new Vector3d();
+ cp.add(ps, ne);
+ cp.scale(0.5);
+ currentNext.setLength(l);
+ currentNext.setWorldPosition(cp);
}
} else {
// FIXME : pipe run must be split into two parts, since the control point structure is no more continuous.
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);
if (component == null)
return;
PipelineComponent next = component.getNext();
- PipelineComponent prev = component.getNext();
+ PipelineComponent prev = component.getPrevious();
+ PipelineComponent br0 = component.getBranch0();
+ component.setNext(null);
+ component.setPrevious(null);
+ component.setBranch0(null);
if (next != null) {
if (next.getNext() == component)
next.setNext(null);
else if (next.getPrevious() == component)
next.setPrevious(null);
+ else if (next.getBranch0() == component)
+ next.setBranch0(null);
}
if (prev != null) {
if (prev.getNext() == component)
prev.setNext(null);
else if (prev.getPrevious() == component)
prev.setPrevious(null);
+ else if (prev.getBranch0() == component)
+ prev.setBranch0(null);
+ }
+ if (br0 != null) {
+ if (br0.getNext() == component)
+ prev.setNext(null);
+ else if (br0.getPrevious() == component)
+ prev.setPrevious(null);
+ else if (br0.getBranch0() == component)
+ br0.setBranch0(null);
}
PipelineComponent comp = component;
component = null;
+
comp.remove();
}
super.setOrientation(orientation);
if (getParentPoint() == null && component != null)
component._setWorldOrientation(getWorldOrientation());
- for (PipeControlPoint sub : getSubPoint()) {
- sub.setWorldPosition(getWorldPosition());
- sub.setWorldOrientation(getWorldOrientation());
- }
+ updateSubPoint();
}
@Override
public void setPosition(Vector3d position) {
if (MathTools.equals(position, getPosition()))
return;
+ if (Double.isNaN(position.x) || Double.isNaN(position.y) || Double.isNaN(position.z))
+ throw new IllegalArgumentException("NaN is not supported");
super.setPosition(position);
if (getParentPoint() == null && component != null)
component._setWorldPosition(getWorldPosition());
- for (PipeControlPoint sub : getSubPoint()) {
- sub.setWorldPosition(getWorldPosition());
- sub.setWorldOrientation(getWorldOrientation());
+ updateSubPoint();
+ }
+
+ private void updateSubPoint() {
+ if (isOffset()) {
+ if (next == null && previous == null) {
+ for (PipeControlPoint sub : getSubPoint()) {
+ sub.setWorldPosition(getWorldPosition());
+ sub.setWorldOrientation(getWorldOrientation());
+ }
+ return;
+ }
+ for (PipeControlPoint sub : getSubPoint()) {
+ Vector3d wp = getWorldPosition();
+ wp.add(getSizeChangeOffsetVector());
+ sub.setWorldPosition(wp);
+ sub.setWorldOrientation(getWorldOrientation());
+ }
+ } else {
+ 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());
- }
+ updateSubPoint();
}
public void _setWorldOrientation(Quat4d orientation) {
Quat4d localOr = getLocalOrientation(orientation);
super.setOrientation(localOr);
- for (PipeControlPoint sub : getSubPoint()) {
- sub.setWorldPosition(getWorldPosition());
- sub.setWorldOrientation(getWorldOrientation());
- }
+ updateSubPoint();
}
@Override