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=50b22571874c46482359ec8b2472e4ce7673f28f;hb=c51024ff285310c85d0d5ed56a8932216e841dec;hp=b64a9e93cce04a303747931499753e76d002645b;hpb=2c16b9949ab2b8cdbdbff7bbda91eb862b1176ed;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 b64a9e93..50b22571 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 @@ -117,6 +117,8 @@ public class PipingRules { allowInsertRemove = allowIR; triedIR = false; validate(pcp.getPipeRun()); + if (pcp.getParentPoint() != null) + pcp = pcp.getParentPoint(); if (pcp.asPathLegEnd()) { updatePathLegEndControlPoint(pcp); // FIXME: Rules won't work properly, if they are not run twice. //updatePathLegEndControlPoint(pcp); @@ -136,8 +138,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() { @@ -275,6 +280,9 @@ public class PipingRules { scp.insert(pcp1, pcp2); scp.setWorldPosition(pos); + Vector3d dir = new Vector3d(); + dir.sub(pcp2.getWorldPosition(), pcp1.getWorldPosition()); + updateControlPointOrientation(scp, dir); scp.setLength(length); validate(scp.getPipeRun()); return scp; @@ -361,23 +369,18 @@ public class PipingRules { } - @SuppressWarnings("unused") - private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, ArrayList list, Vector3d dir, Vector3d offset) { - boolean hasOffsets = false; - List offsets = new ArrayList(list.size()); - for (PipeControlPoint icp : list) { - if (icp.isOffset()) { - offsets.add(icp); - } else if (icp.isDualSub()) - ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!")); - } + 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); + } + + 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); + } + + private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList list, PipeControlPoint end, Vector3d dir, Vector3d offset, boolean directed) { + List offsets = getOffsetPoints(start, list); if (offsets.size() == 0) { - dir.set(endPoint); - dir.sub(startPoint); - double l = dir.lengthSquared(); - if (l > MathTools.NEAR_ZERO) - dir.scale(1.0/Math.sqrt(l)); - offset.set(0.0, 0.0, 0.0); + setZeroOffset(startPoint, endPoint, dir, offset); return false; } else { Vector3d sp = new Vector3d(startPoint); @@ -387,6 +390,7 @@ public class PipingRules { double l = dir.lengthSquared(); if (l > MathTools.NEAR_ZERO) dir.scale(1.0/Math.sqrt(l)); + int iter = 100; while (iter >= 0) { iter--; @@ -396,11 +400,16 @@ public class PipingRules { Vector3d v = icp.getSizeChangeOffsetVector(dir); offset.add(v); } + + if (directed) + break; + Point3d nep = new Point3d(endPoint); nep.sub(offset); if (nep.distance(ep) < 0.0000000001) { break; - } + } + ep = nep; dir.set(ep); dir.sub(sp); @@ -408,14 +417,37 @@ public class PipingRules { if (l > MathTools.NEAR_ZERO) dir.scale(1.0/Math.sqrt(l)); } - hasOffsets = true; + + if (DEBUG) + System.out.println("calcOffset s:"+ startPoint + " e:" + endPoint + " d:" + dir + " o:"+offset) ; + + return true; } - - if (DEBUG && hasOffsets) - System.out.println("calcOffset s:"+ startPoint + " e:" + endPoint + " d:" + dir + " o:"+offset) ; - return hasOffsets; } + public static void setZeroOffset(Vector3d startPoint, Vector3d endPoint, Vector3d dir, Vector3d offset) { + dir.set(endPoint); + dir.sub(startPoint); + double l = dir.lengthSquared(); + if (l > MathTools.NEAR_ZERO) + dir.scale(1.0/Math.sqrt(l)); + offset.set(0.0, 0.0, 0.0); + } + + public static List getOffsetPoints(PipeControlPoint start, ArrayList list) { + List offsets = new ArrayList(list.size()); + // Only start offset affects the calculation + if (start.isOffset()) + offsets.add(start); + for (PipeControlPoint icp : list) { + if (icp.isOffset()) { + offsets.add(icp); + } else if (icp.isDualSub()) + ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!")); + } + return offsets; + } + private static UpdateStruct2 createUS(PipeControlPoint start, Direction direction, int iter, ArrayList toRemove, PipeControlPoint updated) { ArrayList list = new ArrayList(); PipeControlPoint end = null; @@ -441,7 +473,7 @@ public class PipingRules { Vector3d startPoint = start.getWorldPosition(); Vector3d endPoint = end.getWorldPosition(); Vector3d dir = new Vector3d(); - hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset); + hasOffsets = calculateOffset(startPoint, endPoint, start, list, end, dir, offset); return new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, direction == Direction.PREVIOUS, toRemove, updated); } @@ -526,7 +558,13 @@ public class PipingRules { Vector3d ep = new Vector3d(end); ep.sub(u.offset); - + if (u.start.isOffset()) { + Vector3d offset = u.start.getSizeChangeOffsetVector(u.dir); + updateOffsetPoint(u.start, offset); + sp.add(offset); + ep.add(offset); + } + for (PipeControlPoint icp : u.list) { updateInlineControlPoint(icp, sp, ep, u.dir); if (icp.isOffset()) { @@ -853,7 +891,8 @@ public class PipingRules { double l2next = icp.getInlineLength(); double l2 = l2prev + l2next; double l2s = l2 * l2; - if (l > l2s) { + double diff = l - l2s; + if (diff >= MIN_INLINE_LENGTH) { if (allowInsertRemove) { dir.normalize(); double length = Math.sqrt(l) - l2; // true length of the variable length component @@ -875,7 +914,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; @@ -914,12 +957,17 @@ public class PipingRules { } } - private static void ppNoOffset(UpdateStruct2 u) throws Exception { + /** + * Recalculates offset vector based on current direction, and calls checkExpandPathLeg + * @param u + * @param updateEnds + * @throws Exception + */ + private static void ppNoOffset(UpdateStruct2 u, boolean updateEnds) throws Exception { if (DEBUG) System.out.println("PipingRules.ppNoOffset() " + u); Vector3d offset = new Vector3d(); if (u.hasOffsets) { - u.dir.normalize(); for (PipeControlPoint icp : u.list) { if (icp.isOffset()) { offset.add(icp.getSizeChangeOffsetVector(u.dir)); @@ -928,7 +976,7 @@ public class PipingRules { } } u.offset = offset; - checkExpandPathLeg(u, PathLegUpdateType.NONE); + checkExpandPathLeg(u, PathLegUpdateType.NONE, updateEnds); } private static void ppNoDir(PipeControlPoint start, Vector3d startPoint, ArrayList list, PipeControlPoint end, Vector3d endPoint, boolean hasOffsets, int iter, boolean reversed, ArrayList toRemove, PipeControlPoint updated) throws Exception { @@ -937,8 +985,8 @@ public class PipingRules { // FIXME : extra loop (dir should be calculated here) Vector3d dir = new Vector3d(); Vector3d offset = new Vector3d(); - hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset); - ppNoOffset(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, null, hasOffsets, iter, reversed, toRemove, updated)); + hasOffsets = calculateOffset(startPoint, endPoint, start, list, end, dir, offset); + ppNoOffset(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, null, hasOffsets, iter, reversed, toRemove, updated),true); } private static void checkExpandPathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception { @@ -978,7 +1026,7 @@ public class PipingRules { position = u.startPoint; dcpStart = true; if (!u.reversed) - canMoveOther = true; + canMoveOther = true; inlineEnd = u.end.isInline(); } else { @@ -986,10 +1034,10 @@ public class PipingRules { other = u.start; position = u.endPoint; if (u.reversed) - canMoveOther = true; + canMoveOther = true; inlineEnd = u.start.isInline(); } - + Vector3d directedDirection = direction(dcp, dcpStart ? Direction.NEXT : Direction.PREVIOUS); if (directedDirection == null) { //updateTurnControlPointTurn(dcp, dcp.getPrevious(), dcp.getNext()); @@ -1001,7 +1049,7 @@ public class PipingRules { } Point3d directedEndPoint = new Point3d(u.endPoint); if (u.hasOffsets) - directedEndPoint.add(u.offset); + directedEndPoint.sub(u.offset); double mu[] = new double[2]; @@ -1018,11 +1066,20 @@ public class PipingRules { double distance = t.length(); boolean aligned = (distance < ALLOWED_OFFSET); + double requiredSpace = 0.0; + if (other.isVariableAngle()) { + requiredSpace = spaceForTurn(other, dcp); + } + if (mu[0] < requiredSpace) { + // At the moment, if next component is directly behind the nozzle, we must force moving the other component. + // Trying to solve the situation by adding new turn creates infinite loop... + aligned = false; + canMoveOther = true; + } if (aligned) { - if (u.start.isInline() || u.end.isInline() || u.start.asFixedAngle() || u.end.asFixedAngle()) - processPathLeg(u, true, false); - checkExpandPathLeg(u, lengthChange, inlineEnd); - + //if (u.start.isInline() || u.end.isInline() || u.start.asFixedAngle() || u.end.asFixedAngle()) + // processPathLeg(u, true, false); + checkExpandPathLeg(u, lengthChange, inlineEnd || u.start.isInline() || u.end.isInline() || u.start.asFixedAngle() || u.end.asFixedAngle()); } else { if (u.iter > 0) { backIter(u); @@ -1041,28 +1098,40 @@ public class PipingRules { if (other.isVariableAngle()) { // TODO calculate needed space from next run end. - double space = spaceForTurn(other); - if (mu[0] < space) { + if (mu[0] < requiredSpace) { if (dcpStart) { closest.set(u.startPoint); } else { closest.set(u.endPoint); } Vector3d v = new Vector3d(directedDirection); - v.scale(space); + v.scale(requiredSpace); closest.add(v); } if (canMoveOther) { if (DEBUG) System.out.println("PipingRules.updateDirectedPipeRun() moved end " + other + " to " + closest); + + // Not aligned - we need to recalculate the offset to reflect new end points. + Vector3d offset; + if (u.hasOffsets) { + offset = new Vector3d(); + Vector3d newDir = new Vector3d(); + calculateDirectedOffset(position, closest, u.start, u.list, u.end, newDir, offset); + closest.add(offset); + } else { + offset = new Vector3d(); + } + other.setWorldPosition(closest); + if (dcpStart) { - ppNoOffset(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Vector3d(closest), directedDirection, null, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated)); + checkExpandPathLeg(new UpdateStruct2(u.start, u.startPoint, u.list, u.end, new Vector3d(closest), directedDirection, offset, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated), PathLegUpdateType.NONE, true); if (u.end.getNext() != null) updatePathLegNext(u.end, u.updated, PathLegUpdateType.NEXT); } else { - ppNoOffset(new UpdateStruct2(u.start, new Vector3d(closest), u.list, u.end, u.endPoint, directedDirection, null, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated)); + checkExpandPathLeg(new UpdateStruct2(u.start, new Vector3d(closest), u.list, u.end, u.endPoint, directedDirection, offset, u.hasOffsets, u.iter, u.reversed, u.toRemove, u.updated), PathLegUpdateType.NONE, true); if (u.start.getPrevious() != null) updatePathLegPrev(u.start, u.updated, PathLegUpdateType.PREV); } @@ -1134,14 +1203,19 @@ public class PipingRules { PipeControlPoint dcp2 = u.end; Point3d position1 = new Point3d(u.startPoint); Point3d position2 = new Point3d(u.endPoint); + + Vector3d dir = new Vector3d(), 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)); @@ -1181,9 +1255,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) @@ -1225,11 +1299,54 @@ public class PipingRules { } - private static double spaceForTurn(PipeControlPoint tcp) { - // TODO : this returns now space for 90 deg turn. - // The challenge: position of tcp affects the turn angle, which then affects the required space. Perhaps we need to iterate... - // Additionally, if the path legs contain offset, using just positions of opposite path leg ends is not enough, - return ((TurnComponent)tcp.getPipelineComponent()).getTurnRadius(); + private static double spaceForTurn(PipeControlPoint tcp, PipeControlPoint dcp) { + // TODO : if the path legs contain offset, using just positions of opposite path leg ends is not enough. + // TODO : current iterative way for calculating required space may return longer length that is required. + double tr = ((TurnComponent)tcp.getPipelineComponent()).getTurnRadius(); + if (dcp == null) + return tr; // space for 90 deg + PipeControlPoint ne = tcp.findNextEnd(); + PipeControlPoint pe = tcp.findPreviousEnd(); + PipeControlPoint other = null; + if (dcp == ne) + other = pe; + else if (dcp == pe) + other = ne; + else + return tr; // space for 90 deg + 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... + } + double curr = tr*0.1; + 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--; + } + return curr; } private static void insertElbowUpdate(UpdateStruct2 u, PipeControlPoint dcp, PipeControlPoint next, boolean dcpStart, Vector3d position, Vector3d directedDirection) throws Exception{ @@ -1247,9 +1364,8 @@ public class PipingRules { closest = MathTools.closestPointOnStraight(dcp.getWorldPosition(), position, directedDirection); tcp = insertElbow(next, dcp, closest); } - // TODO properly calculate required distance between start and inserted elbow. double d = MathTools.distance(position, closest); - double s = spaceForTurn(tcp); + double s = spaceForTurn(tcp,dcp); if (d < s) { d = s - d; Vector3d p = new Vector3d(directedDirection); @@ -1633,9 +1749,9 @@ public class PipingRules { private static void updateEndComponentControlPoint(PipeControlPoint ecp, Vector3d dir) throws Exception { if (DEBUG) System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp); - //FIXME : end control point cannot be fixed! - //if (!ecp.isFixed()) - updateControlPointOrientation(ecp, dir); + + if (!ecp.isFixed()) // prevent overriding nozzle orientations.. + updateControlPointOrientation(ecp, dir); for (PipeControlPoint pcp : ecp.getChildPoints()) { // TODO update position @@ -1795,7 +1911,10 @@ public class PipingRules { List points = getControlPoints(pipeRun); PipeControlPoint pcp = points.get(0); if (pcp.isSizeChange() && pcp.getChildPoints().size() > 0) { - pipeRun = pcp.getPipeRun(); + PipeRun pr = pcp.getPipeRun(); + if (pr != pipeRun) + pipeRun = pr; + else break; } else { break; } @@ -1829,7 +1948,6 @@ public class PipingRules { List list2 = pcps.get(i+1); PipeControlPoint prev = list.get(list.size()-1); PipeControlPoint next = list2.get(0); - System.out.println(); if (prev == next) { // Reverse the component on the boundary. InlineComponent ic = (InlineComponent)prev.getPipelineComponent();