X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.plant3d%2Fsrc%2Forg%2Fsimantics%2Fplant3d%2Fscenegraph%2Fcontrolpoint%2FPipingRules.java;h=e930b8d6d07094035a188933141c4519085c5382;hb=47edf45b081e0b06aa8839a39098edba737b162f;hp=d27de99b2fd4142be90cfc34a458f50d0228ed36;hpb=b0990f056daad24134642fd7a2406d17397002ae;p=simantics%2F3d.git diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java index d27de99b..e930b8d6 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java @@ -68,11 +68,12 @@ public class PipingRules { if (!PipingRules.enabled) return false; - if (requestUpdates.size() == 0) - return false; - - List temp = new ArrayList(requestUpdates.size()); - synchronized(updateMutex) { + List temp; + synchronized(updateMutex) { + if (requestUpdates.size() == 0) + return false; + + temp = new ArrayList(requestUpdates.size()); temp.addAll(requestUpdates); requestUpdates.clear(); } @@ -138,8 +139,11 @@ public class PipingRules { public static void setEnabled(boolean enabled) { PipingRules.enabled = enabled; - if(!enabled) - currentUpdates.clear(); + if(!enabled) { + synchronized (ruleMutex) { + currentUpdates.clear(); + } + } } public static boolean isEnabled() { @@ -213,6 +217,17 @@ public class PipingRules { System.out.println("PipingRules.updateInlineControlPoint() " + pcp); PipeControlPoint start = pcp.findPreviousEnd(); updatePathLegNext(start, pcp, PathLegUpdateType.NONE); + + if (pcp.isOffset()) { + // Adjusting the rotation angle of an offset component may change variable angle turns + PipeControlPoint end = pcp.findNextEnd(); + if (end.isVariableAngle()) { + updatePathLegNext(end, end, PathLegUpdateType.NONE); + } + if (start.isVariableAngle()) { + updatePathLegPrev(start, start, PathLegUpdateType.NONE); + } + } } private static PipeControlPoint insertElbow(PipeControlPoint pcp1, PipeControlPoint pcp2, Vector3d pos) throws Exception{ @@ -277,6 +292,9 @@ public class PipingRules { scp.insert(pcp1, pcp2); scp.setWorldPosition(pos); + Vector3d dir = new Vector3d(); + dir.sub(pcp2.getWorldPosition(), pcp1.getWorldPosition()); + scp.orientToDirection(dir); scp.setLength(length); validate(scp.getPipeRun()); return scp; @@ -363,11 +381,44 @@ public class PipingRules { } - private static boolean calculateDirectedOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList list, PipeControlPoint end, Vector3d dir, Vector3d offset) { + /** + * Calculate offset based on a given fixed component direction. + * + * The desired component direction is provided as an input to this method, + * unlike the direction vector that is calculated by calculateOffset. + * + * The returned offset vector is always perpendicular to the given direction + * vector. + * + * @param startPoint Start point of leg + * @param endPoint End point of leg + * @param start Starting component of leg + * @param list Inline components between start and end + * @param end Ending component of leg + * @param dir Direction at which the offset is calculated + * @param offset A vector object to receive the offset vector values + * @return True if offsets are present + */ + public static boolean calculateDirectedOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList list, PipeControlPoint end, Vector3d dir, Vector3d offset) { return calculateOffset(startPoint, endPoint, start, list, end, dir, offset, true); } - private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList list, PipeControlPoint end, Vector3d dir, Vector3d offset) { + /** + * Calculate offset and direction vectors for a path leg so that the given chain + * of components starts and ends at the given coordinates + * + * The returned direction and offset vectors are perpendicular to each other. + * + * @param startPoint Start point of the leg + * @param endPoint End point of the leg + * @param start Starting component of the leg + * @param list Inline components between start and end + * @param end Ending component of the leg + * @param dir A vector object to receive the component direction vector + * @param offset A vector object to receive the offset vector + * @return True if offsets are present + */ + public static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList list, PipeControlPoint end, Vector3d dir, Vector3d offset) { return calculateOffset(startPoint, endPoint, start, list, end, dir, offset, false); } @@ -379,14 +430,17 @@ public class PipingRules { } else { Vector3d sp = new Vector3d(startPoint); Point3d ep = new Point3d(endPoint); - dir.set(ep); - dir.sub(sp); + if (!directed) { + dir.set(ep); + dir.sub(sp); + } + double l = dir.lengthSquared(); if (l > MathTools.NEAR_ZERO) dir.scale(1.0/Math.sqrt(l)); int iter = 100; - while (iter >= 0) { + while (true) { iter--; offset.set(0.0, 0.0, 0.0); @@ -400,7 +454,7 @@ public class PipingRules { Point3d nep = new Point3d(endPoint); nep.sub(offset); - if (nep.distance(ep) < 0.0000000001) { + if (nep.distance(ep) < 0.0000000001 || iter <= 0) { break; } @@ -471,6 +525,21 @@ public class PipingRules { return new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, direction == Direction.PREVIOUS, toRemove, updated); } + private static Vector3d pathLegDirection(PipeControlPoint start) { + ArrayList list = new ArrayList(); + PipeControlPoint end = start.findNextEnd(list); + if (start == end) { + return start.getDirection(Direction.NEXT); + } + + Vector3d offset = new Vector3d(); + Vector3d startPoint = start.getWorldPosition(); + Vector3d endPoint = end.getWorldPosition(); + Vector3d dir = new Vector3d(); + calculateOffset(startPoint, endPoint, start, list, end, dir, offset); + return dir; + } + private static boolean asDirected(PipeControlPoint pcp, Direction direction) { if (pcp.isDirected()) return true; @@ -727,8 +796,8 @@ public class PipingRules { continue; double curr = gapObj.d; int d = 1; - while (curr < -MIN_INLINE_LENGTH) { - GapObj next = i+d >= 0 ? gaps.get(i+d) : null; + while (d < gaps.size() && curr < -MIN_INLINE_LENGTH) { + GapObj next = i+d < gaps.size() ? gaps.get(i+d) : null; GapObj prev = i-d >= 0 ? gaps.get(i-d) : null; if (next != null && next.gap == Gap.SPACE) { double move = Math.min(-curr, next.d); @@ -746,12 +815,12 @@ public class PipingRules { pcp.first.setWorldPosition(p); } } - if (curr < -MIN_INLINE_LENGTH && prev != null && prev.gap == Gap.SPACE) { + else if (prev != null && prev.gap == Gap.SPACE) { double move = Math.min(-curr, prev.d); curr+= move; - next.d -= move; - if (next.d < MIN_INLINE_LENGTH) - next.gap = Gap.ATTACHED; + prev.d -= move; + if (prev.d < MIN_INLINE_LENGTH) + prev.gap = Gap.ATTACHED; Vector3d mv = new Vector3d(dir); mv.normalize(); mv.scale(-move); @@ -762,6 +831,9 @@ public class PipingRules { pcp.first.setWorldPosition(p); } } + else { + d++; + } } } } else { @@ -908,7 +980,11 @@ public class PipingRules { Vector3d dir = new Vector3d(); dir.sub(currentPos, prevPos); - boolean simple = currentUpdates.contains(icp); + boolean simple; + synchronized (ruleMutex) { + simple = currentUpdates.contains(icp); + } + if (simple) { // Update based on position -> adjust length double currentLength = (dir.length() - prev.getInlineLength()) * 2.0; @@ -1037,22 +1113,31 @@ public class PipingRules { return; } } - Point3d directedEndPoint = new Point3d(u.endPoint); - if (u.hasOffsets) - directedEndPoint.sub(u.offset); + + Point3d otherPosition = new Point3d(dcpStart ? u.endPoint : u.startPoint); + if (u.hasOffsets) { + Vector3d dir = dcp.getDirection(dcpStart ? Direction.NEXT : Direction.PREVIOUS); + if (!dcpStart) + dir.negate(); + + Vector3d offset = new Vector3d(); + calculateDirectedOffset(u.startPoint, u.endPoint, u.start, u.list, u.end, dir, offset); + u.dir = dir; + u.offset = offset; + + if (dcpStart) + otherPosition.sub(offset); + else + otherPosition.add(offset); + } double mu[] = new double[2]; Vector3d closest; Vector3d t = new Vector3d(); - if (dcpStart) { - closest = MathTools.closestPointOnStraight(directedEndPoint, u.startPoint, directedDirection, mu); - t.sub(closest, directedEndPoint); - } else { - closest = MathTools.closestPointOnStraight(u.startPoint, directedEndPoint, directedDirection, mu); - t.sub(closest, u.startPoint); - } + closest = MathTools.closestPointOnStraight(otherPosition, position, directedDirection, mu); + t.sub(closest, otherPosition); double distance = t.length(); boolean aligned = (distance < ALLOWED_OFFSET); @@ -1129,7 +1214,6 @@ public class PipingRules { // TODO : calculate needed space from next run end. if (allowInsertRemove) insertElbowUpdate(u, dcp, nextToMoved, dcpStart, position, directedDirection); - else triedIR = true; } @@ -1181,8 +1265,6 @@ public class PipingRules { } } } - - } private static void updateDualDirectedPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception { @@ -1193,14 +1275,19 @@ public class PipingRules { PipeControlPoint dcp2 = u.end; Point3d position1 = new Point3d(u.startPoint); Point3d position2 = new Point3d(u.endPoint); + + Vector3d dir = u.start.getDirection(Direction.NEXT), offset = new Vector3d(); + calculateDirectedOffset(new Vector3d(position1), new Vector3d(position2), u.start, u.list, u.end, dir, offset); + Point3d position1offset = new Point3d(position1); - position1offset.sub(u.offset); + position1offset.add(offset); Point3d position2offset = new Point3d(position2); - position2offset.add(u.offset); + position2offset.sub(offset); Vector3d dir1 = direction(dcp1, Direction.NEXT); Vector3d dir2 = direction(dcp2, Direction.PREVIOUS); - Vector3d p1 = MathTools.closestPointOnStraight(position1offset, position2, dir2); - Vector3d p2 = MathTools.closestPointOnStraight(position2offset, position1, dir1); + + Vector3d p1 = MathTools.closestPointOnStraight(position1, position2offset, dir2); + Vector3d p2 = MathTools.closestPointOnStraight(position2, position1offset, dir1); double d1 = position1.distance(new Point3d(p1)); double d2 = position2.distance(new Point3d(p2)); @@ -1240,9 +1327,9 @@ public class PipingRules { p1.add(v); if (!u.reversed) - p2 = MathTools.closestPointOnStraight(new Point3d(p1), position2, dir2); + p2 = MathTools.closestPointOnStraight(new Point3d(p1), position2offset, dir2); else - p2 = MathTools.closestPointOnStraight(new Point3d(p1), position1, dir1); + p2 = MathTools.closestPointOnStraight(new Point3d(p1), position1offset, dir1); // By default, the elbows are placed next to each other, by using 90 deg angles. // If the distance between elbows is not enough, we must move the other elbow (and create more shallow angle elbows) @@ -1302,34 +1389,51 @@ public class PipingRules { if (other == null) return tr; // space for 90 deg Vector3d dir = dcp.getDirectedControlPointDirection(); - Vector3d dp = dcp.getWorldPosition(); - Vector3d op = other.getWorldPosition(); - double u[] = new double[1]; - Vector3d closest = MathTools.closestPointOnStraight(op, dp, dir,u); - if (MathTools.distanceSquared(closest, op) <= MIN_INLINE_LENGTH) { - if (u[0] > -MIN_INLINE_LENGTH) - return 0.0; // point following turn is directly in the front of the nozzle. - else - return tr*2.0; // point following turn is directly behind the nozzle, in theory, we should return Double.Inf... + Vector3d dir2; + if (other == ne) { + dir2 = pathLegDirection(tcp); + } else { + dir2 = pathLegDirection(pe); + dir2.negate(); } - double curr = tr*0.1; + + double d = dir.dot(dir2); + if (d > 0.9999) + return 0.0; // point following turn is directly in the front of the nozzle. + else if (d < -0.9999) + return tr*2.0; // point following turn is directly behind the nozzle, in theory, we should return Double.Inf... + + double curr = 0.0; int iter = 10; - Vector3d v1 = new Vector3d(); - Vector3d v2 = new Vector3d(); - while (iter > 0) { - Vector3d tp = new Vector3d(dp); - MathTools.mad(tp, dir, curr); - v1.sub(tp, dp); // Vector from nozzle to turn - v2.sub(op,tp); // Vector from turn to other - double a = v1.angle(v2); - double t = Math.tan((Math.PI - a) * 0.5); - double R = 0.0; - if (t > MathTools.NEAR_ZERO) - R = tr / t; - if (R <= curr) - break; - curr = R*1.001; - iter--; + Vector3d tp0 = tcp.getPosition(); + try { + Vector3d dp = dcp.getWorldPosition(); + while (iter > 0) { + Vector3d tp = new Vector3d(dir); + tp.scaleAdd(curr, dp); + tcp._setPosition(tp); // no firing of listeners here + if (other == ne) { + dir2 = pathLegDirection(tcp); + } else { + dir2 = pathLegDirection(pe); + dir2.negate(); + } + + double a = dir.angle(dir2); + + // other is directly between dcp and tcp, a zero angle turn should do + if (Math.PI - a <= MathTools.NEAR_ZERO) + return 0.0; + + double R = tr * Math.tan(a * 0.5); + if (R <= curr) + break; + curr = R*1.001; + iter--; + } + } + finally { + tcp._setPosition(tp0); // return the original value } return curr; } @@ -1341,26 +1445,19 @@ public class PipingRules { // closest.add(directedDirection); PipeControlPoint tcp = null; - Vector3d closest; + Vector3d closest = new Vector3d(directedDirection); + closest.scaleAdd(dcp.getPipeRun().getTurnRadius(), position); if (dcpStart) { - closest = MathTools.closestPointOnStraight(next.getWorldPosition(), position, directedDirection); tcp = insertElbow(dcp, next, closest); } else { - closest = MathTools.closestPointOnStraight(dcp.getWorldPosition(), position, directedDirection); tcp = insertElbow(next, dcp, closest); } - double d = MathTools.distance(position, closest); - double s = spaceForTurn(tcp,dcp); - if (d < s) { - d = s - d; - Vector3d p = new Vector3d(directedDirection); - p.scale(d); - p.add(closest); - tcp.setPosition(p); - closest = p; - } - + double s = spaceForTurn(tcp,dcp); + Vector3d p = new Vector3d(directedDirection); + p.scaleAdd(s, position); + tcp.setPosition(p); + closest = p; if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() inserted " + tcp); @@ -1581,7 +1678,7 @@ public class PipingRules { } else if (u.start.isEnd()) { updateEndComponentControlPoint(u.start, u.dir); } else if (u.start.isInline()) { - updateControlPointOrientation(u.start, u.dir); + u.start.orientToDirection(u.dir); } if (u.end.isTurn()) { //updateTurnControlPointTurn(u.end, u.end.getPrevious(), u.end.getNext()); @@ -1590,7 +1687,7 @@ public class PipingRules { } else if (u.end.isEnd()) { updateEndComponentControlPoint(u.end, u.dir); } else if (u.end.isInline()) { - updateControlPointOrientation(u.end, u.dir); + u.end.orientToDirection(u.dir); } } else { @@ -1719,7 +1816,7 @@ public class PipingRules { System.out.println(" " + newInlinePoint); icp.setWorldPosition(newInlinePoint); - updateControlPointOrientation(icp, dir); + icp.orientToDirection(dir); } /** @@ -1736,7 +1833,7 @@ public class PipingRules { System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp); if (!ecp.isFixed()) // prevent overriding nozzle orientations.. - updateControlPointOrientation(ecp, dir); + ecp.orientToDirection(dir); for (PipeControlPoint pcp : ecp.getChildPoints()) { // TODO update position @@ -1744,21 +1841,6 @@ public class PipingRules { } } - private static void updateControlPointOrientation(PipeControlPoint pcp, Vector3d dir) { - Double angleO = pcp.getRotationAngle(); - double angle = 0.0; - if (angleO != null) - angle = angleO; - boolean reversed = pcp._getReversed(); - Quat4d q = null; - if (dir != null) { - q = pcp.getControlPointOrientationQuat(dir, angle, reversed); - } else { - q = pcp.getControlPointOrientationQuat(angle, reversed); - } - pcp.setWorldOrientation(q); - } - /** * Updates all branches when branch's position has been changed * @@ -1802,15 +1884,15 @@ public class PipingRules { return tcp.getTurnAngle(); return Math.PI; // FIXME : argh } - double turnAngle = prev.angle(next); - - double angle = Math.PI - turnAngle; + + final boolean isDegenerate = prev.lengthSquared() < MathTools.NEAR_ZERO || next.lengthSquared() < MathTools.NEAR_ZERO; + double turnAngle = isDegenerate ? 0.0 : prev.angle(next); Vector3d turnAxis = new Vector3d(); turnAxis.cross(prev, next); if (turnAxis.lengthSquared() > MathTools.NEAR_ZERO) { double elbowRadius = ((TurnComponent)tcp.getPipelineComponent()).getTurnRadius(); - double R = elbowRadius / Math.tan(angle * 0.5); + double R = elbowRadius * Math.tan(turnAngle * 0.5); turnAxis.normalize(); tcp.setTurnAngle(turnAngle); @@ -1824,7 +1906,7 @@ public class PipingRules { tcp.setTurnAxis(new Vector3d(MathTools.Y_AXIS)); } - updateControlPointOrientation(tcp,prev); + tcp.orientToDirection(prev); if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + prev + " " + next + " " + turnAngle + " " + turnAxis); @@ -1852,7 +1934,7 @@ public class PipingRules { return Math.PI; // FIXME : argh } - Quat4d q = PipeControlPoint.getControlPointOrientationQuat(dir, tcp.getRotationAngle() != null ? tcp.getRotationAngle() : 0.0); + Quat4d q = tcp.getControlPointOrientationQuat(dir, tcp.getRotationAngle() != null ? tcp.getRotationAngle() : 0.0); Vector3d v = new Vector3d(); MathTools.rotate(q, MathTools.Y_AXIS,v); tcp.setTurnAxis(v); @@ -2019,50 +2101,52 @@ public class PipingRules { public static void validate(PipeRun pipeRun) { if (pipeRun == null) return; - Collection pcps = pipeRun.getControlPoints(); - int count = 0; - //System.out.println("Validate " + pipeRun.getName()); - for (PipeControlPoint pcp : pcps) { - if (pcp.getParentPoint() == null || pcp.getParentPoint().getPipeRun() != pipeRun) - count++; - } - List runPcps = getControlPoints(pipeRun); - if (runPcps.size() != count) { - System.out.println("Run " + pipeRun.getName() + " contains unconnected control points, found " + runPcps.size() + " connected, " + pcps.size() + " total."); + synchronized (ruleMutex) { + Collection pcps = pipeRun.getControlPoints(); + int count = 0; + //System.out.println("Validate " + pipeRun.getName()); for (PipeControlPoint pcp : pcps) { - if (!runPcps.contains(pcp)) { - System.out.println("Unconnected " + pcp + " " + pcp.getPipelineComponent()); - } + if (pcp.getParentPoint() == null || pcp.getParentPoint().getPipeRun() != pipeRun) + count++; } - } - for (PipeControlPoint pcp : pcps) { - if (pcp.getPipeRun() == null) { - System.out.println("PipeRun ref missing " + pcp + " " + pcp.getPipelineComponent()); - } - if (!pcp.isDirected() && pcp.getNext() == null && pcp.getPrevious() == null) - System.out.println("Orphan undirected " + pcp + " " + pcp.getPipelineComponent()); - } - for (PipeControlPoint pcp : pcps) { - if (pcp.getParentPoint() == null) { - PipeControlPoint sub = null; - if (pcp.isDualInline()) - sub = pcp.getDualSub(); - PipeControlPoint next = pcp.getNext(); - PipeControlPoint prev = pcp.getPrevious(); - if (next != null) { - if (!(next.getPrevious() == pcp || next.getPrevious() == sub)) { - System.out.println("Inconsistency between " + pcp + " -> " +next ); - } + List runPcps = getControlPoints(pipeRun); + if (runPcps.size() != count) { + System.out.println("Run " + pipeRun.getName() + " contains unconnected control points, found " + runPcps.size() + " connected, " + pcps.size() + " total."); + for (PipeControlPoint pcp : pcps) { + if (!runPcps.contains(pcp)) { + System.out.println("Unconnected " + pcp + " " + pcp.getPipelineComponent()); + } } - if (prev != null) { - PipeControlPoint prevParent = null; - if (prev.isDualSub()) { - prevParent = prev.getParentPoint(); - } else if (prev.isDualInline()) { - System.out.println("Inconsistency between " + pcp + " <-- " +prev ); + } + for (PipeControlPoint pcp : pcps) { + if (pcp.getPipeRun() == null) { + System.out.println("PipeRun ref missing " + pcp + " " + pcp.getPipelineComponent()); + } + if (!pcp.isDirected() && pcp.getNext() == null && pcp.getPrevious() == null) + System.out.println("Orphan undirected " + pcp + " " + pcp.getPipelineComponent()); + } + for (PipeControlPoint pcp : pcps) { + if (pcp.getParentPoint() == null) { + PipeControlPoint sub = null; + if (pcp.isDualInline()) + sub = pcp.getDualSub(); + PipeControlPoint next = pcp.getNext(); + PipeControlPoint prev = pcp.getPrevious(); + if (next != null) { + if (!(next.getPrevious() == pcp || next.getPrevious() == sub)) { + System.out.println("Inconsistency between " + pcp + " -> " +next ); + } } - if (!(prev.getNext() == pcp && (prevParent == null || prevParent.getNext() == pcp))) { - System.out.println("Inconsistency between " + pcp + " <-- " +prev ); + if (prev != null) { + PipeControlPoint prevParent = null; + if (prev.isDualSub()) { + prevParent = prev.getParentPoint(); + } else if (prev.isDualInline()) { + System.out.println("Inconsistency between " + pcp + " <-- " +prev ); + } + if (!(prev.getNext() == pcp && (prevParent == null || prevParent.getNext() == pcp))) { + System.out.println("Inconsistency between " + pcp + " <-- " +prev ); + } } } }