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=57ee4ba86a382e9ac49ed7253ccdaf03f0a248e4;hb=a899aac9dd52296206f302a20a8e7bae2501cf2c;hp=393dc85e1ab005bae0e56c515e5ebc238cc99835;hpb=a1e1faa6915445e786f482170576b9c9d0f5d982;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 393dc85e..57ee4ba8 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 @@ -2,9 +2,7 @@ package org.simantics.plant3d.scenegraph.controlpoint; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.vecmath.Point3d; import javax.vecmath.Quat4d; @@ -12,21 +10,22 @@ import javax.vecmath.Vector3d; import org.simantics.g3d.math.MathTools; import org.simantics.plant3d.scenegraph.InlineComponent; -import org.simantics.plant3d.scenegraph.Nozzle; import org.simantics.plant3d.scenegraph.P3DRootNode; import org.simantics.plant3d.scenegraph.PipeRun; import org.simantics.plant3d.scenegraph.PipelineComponent; import org.simantics.plant3d.scenegraph.TurnComponent; import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.Direction; import org.simantics.plant3d.utils.ComponentUtils; +import org.simantics.utils.datastructures.Pair; import org.simantics.utils.ui.ErrorLogger; public class PipingRules { private static final boolean DEBUG = false; private static final boolean DUMMY = false; - private static double MIN_TURN_ANGLE = 0.001; // Threshold for removing turn components. - private static double ALLOWED_OFFSET = 0.001; // Allowed offset for directed path legs + private static double MIN_TURN_ANGLE = 0.001; // Threshold for removing turn components. + private static double ALLOWED_OFFSET = 0.001; // Allowed offset for directed path legs + private static double MIN_INLINE_LENGTH = 0.0005; // Minimum length of inline components, when component removal is not allowed. private static final int REMOVE_NONE = 0; private static final int REMOVE_START = 1; @@ -34,11 +33,16 @@ public class PipingRules { private static final int REMOVE_BOTH = 3; + // PathLeg iteration indicator. NEXT_S > NEXT > NONE PREV_S > PREV > NONE private enum PathLegUpdateType { - NONE, PREV, NEXT, PREV_S, NEXT_S + NONE, // Only current path leg needs to be updated (for example, inline comp was moved) + PREV, // Current and previous path leg need to be updated + NEXT, // Current and next path leg need to be updated + PREV_S, // Current and previous two path legs need to be updated (turn was moved, which affect other path leg end turns, and thus following path legs + NEXT_S // Current and next two path legs need to be updated }; - private static boolean enabled = true; + private static boolean enabled = true; // private static boolean updating = false; private static boolean allowInsertRemove = true; private static boolean triedIR = false; @@ -113,12 +117,14 @@ public class PipingRules { allowInsertRemove = allowIR; triedIR = false; validate(pcp.getPipeRun()); - if (pcp.isPathLegEnd()) { + 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); + //updatePathLegEndControlPoint(pcp); } else { updateInlineControlPoint(pcp); - updateInlineControlPoint(pcp); + //updateInlineControlPoint(pcp); } validate(pcp.getPipeRun()); if (!allowInsertRemove) @@ -139,10 +145,6 @@ public class PipingRules { public static boolean isEnabled() { return enabled; } - -// private void commit() { -// root.getNodeMap().commit(); -// } public static class ExpandIterInfo { // these two are turn control points @@ -218,15 +220,15 @@ public class PipingRules { System.out.println("PipingRules.insertElbow() " + pcp1 + " " + pcp2 + " " + pos); if (pcp1.getNext() == pcp2 && pcp2.getPrevious() == pcp1) { - } else if (pcp1.getNext() == pcp2 && pcp1.isDualInline() && pcp2.getPrevious() == pcp1.getSubPoint().get(0)) { - pcp1 = pcp1.getSubPoint().get(0); + } else if (pcp1.getNext() == pcp2 && pcp1.isDualInline() && pcp2.getPrevious() == pcp1.getDualSub()) { + pcp1 = pcp1.getDualSub(); } else if (pcp1.getPrevious() == pcp2 && pcp2.getNext() == pcp1) { PipeControlPoint t = pcp1; pcp1 = pcp2; pcp2 = t; - } else if (pcp2.isDualInline() && pcp1.getPrevious() == pcp2.getSubPoint().get(0) && pcp2.getNext() == pcp1) { + } else if (pcp2.isDualInline() && pcp1.getPrevious() == pcp2.getDualSub() && pcp2.getNext() == pcp1) { PipeControlPoint t = pcp1; - pcp1 = pcp2.getSubPoint().get(0); + pcp1 = pcp2.getDualSub(); pcp2 = t; } else { throw new RuntimeException(); @@ -234,7 +236,7 @@ public class PipingRules { TurnComponent elbow = ComponentUtils.createTurn((P3DRootNode)pcp1.getRootNode()); PipeControlPoint pcp = elbow.getControlPoint(); if (pcp1.isDualInline()) - pcp1 = pcp1.getSubPoint().get(0); + pcp1 = pcp1.getDualSub(); String name = pcp1.getPipeRun().getUniqueName("Elbow"); elbow.setName(name); pcp1.getPipeRun().addChild(elbow); @@ -251,15 +253,15 @@ public class PipingRules { System.out.println("PipingRules.insertStraight() " + pcp1 + " " + pcp2 + " " + pos); if (pcp1.getNext() == pcp2 && pcp2.getPrevious() == pcp1) { - } else if (pcp1.getNext() == pcp2 && pcp1.isDualInline() && pcp2.getPrevious() == pcp1.getSubPoint().get(0)) { - pcp1 = pcp1.getSubPoint().get(0); + } else if (pcp1.getNext() == pcp2 && pcp1.isDualInline() && pcp2.getPrevious() == pcp1.getDualSub()) { + pcp1 = pcp1.getDualSub(); } else if (pcp1.getPrevious() == pcp2 && pcp2.getNext() == pcp1) { PipeControlPoint t = pcp1; pcp1 = pcp2; pcp2 = t; - } else if (pcp2.isDualInline() && pcp1.getPrevious() == pcp2.getSubPoint().get(0) && pcp2.getNext() == pcp1) { + } else if (pcp2.isDualInline() && pcp1.getPrevious() == pcp2.getDualSub() && pcp2.getNext() == pcp1) { PipeControlPoint t = pcp1; - pcp1 = pcp2.getSubPoint().get(0); + pcp1 = pcp2.getDualSub(); pcp2 = t; } else { throw new RuntimeException(); @@ -267,7 +269,7 @@ public class PipingRules { InlineComponent component = ComponentUtils.createStraight((P3DRootNode)pcp1.getRootNode()); PipeControlPoint scp = component.getControlPoint(); if (pcp1.isDualInline()) - pcp1 = pcp1.getSubPoint().get(0); + pcp1 = pcp1.getDualSub(); String name = pcp1.getPipeRun().getUniqueName("Pipe"); component.setName(name); pcp1.getPipeRun().addChild(component); @@ -287,7 +289,7 @@ public class PipingRules { InlineComponent component = ComponentUtils.createStraight((P3DRootNode)pcp.getRootNode()); PipeControlPoint scp = component.getControlPoint(); if (pcp.isDualInline() && direction == Direction.NEXT) - pcp = pcp.getSubPoint().get(0); + pcp = pcp.getDualSub(); String name = pcp.getPipeRun().getUniqueName("Pipe"); component.setName(name); pcp.getPipeRun().addChild(component); @@ -301,14 +303,7 @@ public class PipingRules { } private static void updatePathLegNext(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception { - UpdateStruct2 us = createUS(start, Direction.NEXT, 0, new ArrayList(), updated); - if (lengthChange == PathLegUpdateType.NONE) { - if (start.equals(updated)) - lengthChange = PathLegUpdateType.NEXT; - else if (us.end.equals(updated)) - lengthChange = PathLegUpdateType.PREV; - } if (us == null) { System.out.println("Null update struct " + start); return; @@ -317,14 +312,7 @@ public class PipingRules { } private static void updatePathLegPrev(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception { - // TODO: this method is not symmetric with updatePathLegNext, which may alter lengthChange parameter? UpdateStruct2 us = createUS(start, Direction.PREVIOUS, 0, new ArrayList(), updated); -// if (lengthChange == PathLegUpdateType.NONE) { -// if (start.equals(updated)) -// lengthChange = PathLegUpdateType.NEXT; -// else if (us.end.equals(updated)) -// lengthChange = PathLegUpdateType.PREV; -// } if (us == null) { System.out.println("Null update struct " + start); return; @@ -375,9 +363,13 @@ public class PipingRules { } - private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, ArrayList list, Vector3d dir, Vector3d offset) { + @SuppressWarnings("unused") + private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, PipeControlPoint start, ArrayList list, PipeControlPoint end, Vector3d dir, Vector3d offset) { boolean hasOffsets = false; 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); @@ -454,7 +446,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); } @@ -475,11 +467,27 @@ public class PipingRules { } private static void updatePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange) throws Exception { + boolean rs = true; + boolean re = true; + if (lengthChange == PathLegUpdateType.NONE) { + rs = false; + re = false; + } + updatePathLeg(u, lengthChange, rs, re); + } + + private static void updatePathLeg(UpdateStruct2 u, PathLegUpdateType lengthChange, boolean rs, boolean re) throws Exception { int directed = 0; if (asDirected(u.start, Direction.NEXT)) directed++; if (asDirected(u.end, Direction.PREVIOUS)) directed++; + if (rs) + setErrorForce(u.start, null); + if (re) + setErrorForce(u.end, null); + for (PipeControlPoint pcp : u.list) + setErrorForce(pcp, null); switch (directed) { case 0: updateFreePathLeg(u, lengthChange); @@ -511,183 +519,336 @@ public class PipingRules { if (checkSizes) { // create offsets for leg ends. - MathTools.mad(start, u.dir, u.start.getInlineLength()); - MathTools.mad(end, u.dir, -u.end.getInlineLength()); + if (u.start.isTurn()) + MathTools.mad(start, u.dir, u.start.getInlineLength()); + if (u.end.isTurn()) + MathTools.mad(end, u.dir, -u.end.getInlineLength()); } - - boolean recalcline = false; - if (!u.hasOffsets) { - - - for (PipeControlPoint icp : u.list) { - updateInlineControlPoint(icp, start, end, u.dir); - - if (icp.isOffset()) { - // TODO : offset vector is already calculated and should be cached - Vector3d off = icp.getSizeChangeOffsetVector(u.dir); - updateOffsetPoint(icp, off); - } - } - if (!checkSizes) - return; - - ArrayList pathLegPoints = new ArrayList(); - pathLegPoints.add(u.start); - for (PipeControlPoint icp : u.list) { - // updateInlineControlPoint(icp, u.startPoint, - // u.endPoint,u.dir); - updateBranchControlPointBranches(icp); - pathLegPoints.add(icp); - } - pathLegPoints.add(u.end); - - // TODO : values can be cached in the loop - for (int i = 0; i < pathLegPoints.size(); i++) { - PipeControlPoint icp = pathLegPoints.get(i); - - PipeControlPoint prev = i > 0 ? pathLegPoints.get(i - 1) : null; - PipeControlPoint next = i < pathLegPoints.size() - 1 ? pathLegPoints.get(i + 1) : null; - - if (icp.isVariableLength()) { - if (prev != null && next != null) { - - recalcline = recalcline | updateVariableLength(icp, prev, next); - - } else { - // this is variable length component at the end of the - // piperun. - // the problem is that we want to keep unconnected end - // of the component in the same - // place, but center of the component must be moved. - updateVariableLengthEnd(icp, prev != null ? prev : next); - } + boolean recalcline = false; - } else if (prev != null && !prev.isVariableLength()) { - // If this and previous control point are not variable - // length pcps, we'll have to check if there is no empty - // space between them. - // I there is, we'll have to create new variable length - // component between them. - recalcline = recalcline | possibleVaribleLengthInsert(icp, prev); - } + Vector3d sp = new Vector3d(start); + 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()) { + // TODO : offset vector is already calculated and should be cached + Vector3d offset = icp.getSizeChangeOffsetVector(u.dir); + updateOffsetPoint(icp, offset); + sp.add(offset); + ep.add(offset); } - } else { // with offset - Vector3d sp = new Vector3d(start); - Vector3d ep = new Vector3d(end); - ep.sub(u.offset); - - ArrayList pathLegPoints = new ArrayList(); - pathLegPoints.add(u.start); + } + + if (!checkSizes) + return; + + // Collect all path leg points for updating variable length components. This list will also contain leg ends (usually turns) + ArrayList pathLegPoints = new ArrayList<>(); + // Collect all fixed length components with their offsets. + ArrayList> fixedLengthPoints = new ArrayList<>(); + + pathLegPoints.add(u.start); + fixedLengthPoints.add(new Pair(u.start, new Vector3d())); + Vector3d off = new Vector3d(); + for (PipeControlPoint icp : u.list) { + pathLegPoints.add(icp); + updateBranchControlPointBranches(icp); + if (icp.isOffset()) { + fixedLengthPoints.add(new Pair(icp, new Vector3d(off))); + Vector3d offset = icp.getSizeChangeOffsetVector(u.dir); + off.add(offset); + } else if (!icp.isVariableLength()) { + fixedLengthPoints.add(new Pair(icp, new Vector3d(off))); + } + } + pathLegPoints.add(u.end); + fixedLengthPoints.add(new Pair(u.end, new Vector3d(off))); + + sp = new Vector3d(start); + ep = new Vector3d(end); + ep.sub(u.offset); + + updateFixedLengths(fixedLengthPoints, sp, ep, u.dir); + + for (int i = 0; i < pathLegPoints.size(); i++) { + PipeControlPoint icp = pathLegPoints.get(i); - for (PipeControlPoint icp : u.list) { - updateInlineControlPoint(icp, sp, ep, u.dir); - updateBranchControlPointBranches(icp); - pathLegPoints.add(icp); - if (icp.isOffset()) { - // TODO : offset vector is already calculated and should be - // cached - Vector3d offset = icp.getSizeChangeOffsetVector(u.dir); - updateOffsetPoint(icp, offset); - sp.add(offset); - ep.add(offset); - } - } - pathLegPoints.add(u.end); - - if (!checkSizes) - return; + PipeControlPoint prev = i > 0 ? pathLegPoints.get(i - 1) : null; + PipeControlPoint next = i < pathLegPoints.size() - 1 ? pathLegPoints.get(i + 1) : null; - sp = new Vector3d(u.startPoint); - ep = new Vector3d(u.endPoint); - ep.sub(u.offset); - - for (int i = 0; i < pathLegPoints.size(); i++) { - PipeControlPoint icp = pathLegPoints.get(i); + if (prev != null && prev.isDualInline()) + prev = prev.getDualSub(); - PipeControlPoint prev = i > 0 ? pathLegPoints.get(i - 1) : null; - PipeControlPoint next = i < pathLegPoints.size() - 1 ? pathLegPoints.get(i + 1) : null; - - if (prev != null && prev.isDualInline()) - prev = prev.getSubPoint().get(0); - + if (icp.isVariableLength()) { + if (prev != null && next != null) { + recalcline = recalcline | updateVariableLength(icp, prev, next); - if (icp.isVariableLength()) { - if (prev != null && next != null) { - recalcline = recalcline | updateVariableLength(icp, prev, next); - - } else { - // this is variable length component at the end of the - // piperun. - // the problem is that we want to keep unconnected end - // of the component in the same - // place, but center of the component must be moved. - updateVariableLengthEnd(icp, prev != null ? prev : next); - } - } else if (prev != null && !prev.isVariableLength()) { - // If this and previous control point are not variable - // length pcps, we'll have to check if there is no empty - // space between them. - // I there is, we'll have to create new variable length - // component between them. - recalcline = recalcline | possibleVaribleLengthInsert(icp, prev); - } - if (icp.isOffset()) { - // TODO : offset vector is already calculated and should be - // cached - Vector3d offset = icp.getSizeChangeOffsetVector(u.dir); - sp.add(offset); - ep.add(offset); + } else { + // this is variable length component at the end of the piperun. + // the problem is that we want to keep unconnected end of the component in the same + // place, but center of the component must be moved. + updateVariableLengthEnd(icp, prev != null ? prev : next); } + } else if (prev != null && !prev.isVariableLength()) { + // If this and previous control point are not variable length pcps, + // we'll have to check if there is no empty space between them. + // I there is, we'll have to create new variable length component between them. + recalcline = recalcline | possibleVaribleLengthInsert(icp, prev); + } + if (icp.isOffset()) { + // TODO : offset vector is already calculated and should be cached + Vector3d offset = icp.getSizeChangeOffsetVector(u.dir); + sp.add(offset); + ep.add(offset); } } + if (recalcline) { u.list.clear(); u.start.findNextEnd(u.list); + } + if (checkSizes) { + sp = new Vector3d(u.startPoint); + ep = new Vector3d(u.endPoint); + ep.sub(u.offset); + double pathLegLength = MathTools.distance(sp, ep); + double availableLength = pathLegLength; + if (u.start.isTurn()) + availableLength -= u.start.getInlineLength(); + if (u.end.isTurn()) + availableLength -= u.end.getInlineLength(); + for (PipeControlPoint pcp : u.list) { + if (!pcp.isVariableLength()) + availableLength-= pcp.getLength(); + } + if (availableLength < 0.0) { + setError(u.start, "Not enough available space"); + setError(u.end, "Not enough available space"); + for (PipeControlPoint pcp : u.list) + setError(pcp, "Not enough available space"); + } +// System.out.println(u.start.getPipelineComponent().toString() + " " + pathLegLength + " " + availableLength + " " + u.end.getPipelineComponent().toString() + " " + u.start.getInlineLength() + " " + u.end.getInlineLength()); } } + private enum Gap{ATTACHED,OVERLAP,SPACE}; + + private static class GapObj { + Gap gap; + double d; + + Pair pcp1; + Pair pcp2; + } + + private static void updateFixedLengths(List> fixedLengthPoints, Vector3d s, Vector3d e, Vector3d dir) { + double totalLength = MathTools.distance(s, e); + double reservedLength = 0.0; + List distances = new ArrayList<>(fixedLengthPoints.size()); + distances.add(0.0); + for (int i = 1; i < fixedLengthPoints.size()-1; i++) { + Pair pcp = fixedLengthPoints.get(i); + reservedLength += pcp.first.getLength(); + Vector3d p = pcp.first.getWorldPosition(); + p.sub(pcp.second); + double d= MathTools.distance(s, p); + distances.add(d); + } + distances.add(totalLength); + + if (totalLength >= reservedLength) { + // There is enough space for all fixed length components. + List gaps = new ArrayList<>(fixedLengthPoints.size()-1); + int overlaps = 0; + // Analyze gaps between components + for (int i = 0; i < fixedLengthPoints.size()-1; i++) { + Pair pcp1 = fixedLengthPoints.get(i); + Pair pcp2 = fixedLengthPoints.get(i+1); + double d1 = distances.get(i); + double d2 = distances.get(i+1); + double ld1 = i == 0 ? 0.0 :pcp1.first.getInlineLength(); + double ld2 = i == fixedLengthPoints.size()-2 ? 0.0 : pcp2.first.getInlineLength(); + + double e1 = d1 + ld1; // End of comp1 + double s2 = d2 - ld2; // Start of comp2 + double diff =s2 - e1; + GapObj obj = new GapObj(); + obj.pcp1 = pcp1; + obj.pcp2 = pcp2; + obj.d = diff; + if (diff < -MIN_INLINE_LENGTH) { + obj.gap = Gap.OVERLAP; + overlaps++; + } else if (diff > MIN_INLINE_LENGTH) { + obj.gap = Gap.SPACE; + } else { + obj.gap = Gap.ATTACHED; + } + gaps.add(obj); + } + // If there are no overlaps, there is nothing to do. + if (overlaps == 0) + return; + // Get rid of overlapping components by using closest available free spaces. + for (int i = 0; i < gaps.size(); i++) { + GapObj gapObj = gaps.get(i); + if (gapObj.gap != Gap.OVERLAP) + continue; + double curr = gapObj.d; + int d = 1; + while (curr < -MIN_INLINE_LENGTH) { + GapObj next = i+d >= 0 ? 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); + curr+= move; + next.d -= move; + if (next.d < MIN_INLINE_LENGTH) + next.gap = Gap.ATTACHED; + Vector3d mv = new Vector3d(dir); + mv.normalize(); + mv.scale(move); + for (int j = i ; j < i+d; j++) { + Pair pcp = gaps.get(j).pcp2; + Vector3d p = new Vector3d(pcp.first.getWorldPosition()); + p.add(mv); + pcp.first.setWorldPosition(p); + } + } + if (curr < -MIN_INLINE_LENGTH && 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; + Vector3d mv = new Vector3d(dir); + mv.normalize(); + mv.scale(-move); + for (int j = i ; j > i-d; j--) { + Pair pcp = gaps.get(j).pcp1; + Vector3d p = new Vector3d(pcp.first.getWorldPosition()); + p.add(mv); + pcp.first.setWorldPosition(p); + } + } + } + } + } else { + for (int i = 1; i < fixedLengthPoints.size()-1; i++) { + Pair prev = i == 0 ? null : fixedLengthPoints.get(i-1); + Pair curr = fixedLengthPoints.get(i); + Pair next = i == fixedLengthPoints.size() -1 ? null : fixedLengthPoints.get(i+1); + updateFixedLength(curr, prev, next, s,e, dir); + } + } + } + + private static void updateFixedLength(Pair icp, Pair prev, Pair next, Vector3d s, Vector3d e, Vector3d dir) { + if (prev != null) { + checkOverlap(prev, icp, dir,true); + } + if (next != null) + checkOverlap(icp, next, dir,true); + } + + private static boolean checkOverlap(Pair icp, Pair icp2, Vector3d dir, boolean se) { + Vector3d p1 = icp.first.getWorldPosition(); + Vector3d p2 = icp2.first.getWorldPosition(); + p1.add(icp.second); + p2.add(icp2.second); + double u[] = new double[1]; + MathTools.closestPointOnStraight(p2, p1, dir, u); + if (u[0] < 0.0) { + p2.set(p1); + p2.sub(icp.second); + p2.add(icp2.second); + MathTools.mad(p2, dir, MIN_INLINE_LENGTH); + icp2.first.setWorldPosition(p2); + } + double d = MathTools.distance(p1, p2); + double r = icp.first.getInlineLength() + icp2.first.getInlineLength(); + + if ((d-r) < - MIN_INLINE_LENGTH) { + if (se) { + setError(icp.first, "Overlapping"); + setError(icp2.first, "Overlapping"); + } + return true; + } + return false; + } + + /** + * Overrides current error of a component + * @param pcp + * @param error + */ + private static void setErrorForce(PipeControlPoint pcp, String error) { + PipelineComponent comp = pcp.getPipelineComponent(); + if (comp == null) + return; + comp.setError(error); + } + + /** + * Sets error for a component, if there is no existing error. + * @param pcp + * @param error + */ + private static void setError(PipeControlPoint pcp, String error) { + PipelineComponent comp = pcp.getPipelineComponent(); + if (comp == null) + return; + if (comp.getError() != null) + return; + comp.setError(error); + } + private static boolean updateVariableLength(PipeControlPoint icp, PipeControlPoint prev, PipeControlPoint next) { Vector3d prevPos = prev.getWorldPosition(); Vector3d nextPos = next.getWorldPosition(); Vector3d dir = new Vector3d(nextPos); dir.sub(prevPos); - double l = dir.lengthSquared(); // distance between - // control points - // (square) - double l2prev = prev.getInlineLength(); // distance - // taken - // by - // components + double l = dir.length(); // distance between control points + double l2prev = prev.getInlineLength(); // distance taken by components double l2next = next.getInlineLength(); double l2 = l2prev + l2next; - double l2s = MathTools.square(l2); - if (l2s < l) { // check if there is enough space for - // variable length component. + double length = l - l2; // true length of the variable length component + if (length >= MIN_INLINE_LENGTH) { // check if there is enough space for variable length component. // components fit dir.normalize(); - double length = Math.sqrt(l) - l2; // true length of - // the variable - // length - // component - dir.scale(length * 0.5 + l2prev); // calculate - // center - // position of - // the component + dir.scale(length * 0.5 + l2prev); // calculate center position of the component dir.add(prevPos); icp.setWorldPosition(dir); icp.setLength(length); return false; } else { - // components leave no space to the component and it - // must be removed - + // components leave no space to the component and it must be removed if (icp.isDeletable()) { + if (!allowInsertRemove) { + icp.setLength(MIN_INLINE_LENGTH); + setError(icp, "Not enough available space"); + triedIR = true; + return false; + } if (DEBUG) System.out.println("PipingRules.updateVariableLength removing " + icp); icp._remove(); return true; + } else { + icp.setLength(MIN_INLINE_LENGTH); + icp.getPipelineComponent().setError("Not enough available space"); } return false; } @@ -703,17 +864,14 @@ 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 - dir.scale(length * 0.5 + l2prev); // calculate center - // position of the - // component + double length = Math.sqrt(l) - l2; // true length of the variable length component + dir.scale(length * 0.5 + l2prev); // calculate center position of the component dir.add(prevPos); - PipeControlPoint scp = insertStraight(prev, icp, dir, length); + insertStraight(prev, icp, dir, length); return true; } else { triedIR = true; @@ -791,7 +949,7 @@ 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); + hasOffsets = calculateOffset(startPoint, endPoint, start, list, end, dir, offset); ppNoOffset(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, null, hasOffsets, iter, reversed, toRemove, updated)); } @@ -832,7 +990,7 @@ public class PipingRules { position = u.startPoint; dcpStart = true; if (!u.reversed) - canMoveOther = true; + canMoveOther = true; inlineEnd = u.end.isInline(); } else { @@ -840,10 +998,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()); @@ -855,7 +1013,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]; @@ -872,6 +1030,16 @@ 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); @@ -895,15 +1063,14 @@ 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); } @@ -1079,11 +1246,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{ @@ -1101,9 +1311,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); @@ -1332,26 +1541,26 @@ public class PipingRules { updateTurnControlPointTurn(u.start, null, null); // updatePathLegPrev(u.start, u.start, PathLegUpdateType.NONE); } else if (u.start.isEnd()) { - updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint); + updateEndComponentControlPoint(u.start, u.dir); } else if (u.start.isInline()) { - updateControlPointOrientation(u.start); + updateControlPointOrientation(u.start, u.dir); } if (u.end.isTurn()) { //updateTurnControlPointTurn(u.end, u.end.getPrevious(), u.end.getNext()); updateTurnControlPointTurn(u.end, null, null); // updatePathLegNext(u.end, u.end, PathLegUpdateType.NONE); } else if (u.end.isEnd()) { - updateEndComponentControlPoint(u.end, u.startPoint, u.endPoint); + updateEndComponentControlPoint(u.end, u.dir); } else if (u.end.isInline()) { - updateControlPointOrientation(u.end); + updateControlPointOrientation(u.end, u.dir); } } else { if (u.start.isEnd()) { - updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint); + updateEndComponentControlPoint(u.start, u.dir); } if (u.end.isEnd()) { - updateEndComponentControlPoint(u.end, u.startPoint, u.endPoint); + updateEndComponentControlPoint(u.end, u.dir); } } if (updateInline) @@ -1367,6 +1576,7 @@ public class PipingRules { // end,Point3d endPoint, Vector3d dir, boolean hasOffsets,int iter, boolean // reversed, ArrayList toRemove) throws TransactionException // { + @SuppressWarnings("unused") private static void processPathLegNoOffset(UpdateStruct2 u) throws Exception { if (DEBUG) System.out.println("PipingRules.processPathLeg " + u.start + " " + u.end); @@ -1387,7 +1597,7 @@ public class PipingRules { private static void updateOffsetPoint(PipeControlPoint sccp, Vector3d offset) { Vector3d world = sccp.getWorldPosition(); world.add(offset); - PipeControlPoint ocp = sccp.getSubPoint().iterator().next(); + PipeControlPoint ocp = sccp.getDualSub(); ocp.setWorldPosition(world); } @@ -1423,7 +1633,7 @@ public class PipingRules { if (canCalc) { boolean branchUpdate = false; PipeControlPoint becp = null; - for (PipeControlPoint pcp : icp.getSubPoint()) + for (PipeControlPoint pcp : icp.getChildPoints()) if (pcp.isNonDirected()) { branchUpdate = true; becp = pcp; @@ -1471,7 +1681,7 @@ public class PipingRules { System.out.println(" " + newInlinePoint); icp.setWorldPosition(newInlinePoint); - updateControlPointOrientation(icp); + updateControlPointOrientation(icp, dir); } /** @@ -1483,34 +1693,31 @@ public class PipingRules { * @param nextPoint * @param prevPoint */ - private static void updateEndComponentControlPoint(PipeControlPoint ecp, Vector3d start, Vector3d end) throws Exception { + 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); + + if (!ecp.isFixed()) // prevent overriding nozzle orientations.. + updateControlPointOrientation(ecp, dir); - for (PipeControlPoint pcp : ecp.getSubPoint()) { + for (PipeControlPoint pcp : ecp.getChildPoints()) { // TODO update position updatePathLegEndControlPoint(pcp); } } - private static void updateControlPointOrientation(PipeControlPoint pcp) { - // FIXME : hack to bypass variable length components orientation -// if (pcp.getAtMostOneRelatedObject(ProcessResource.g3dResource.HasWorldOrientation) == null) -// return; -// if (pcp.rotationAngle == null) -// return; + private static void updateControlPointOrientation(PipeControlPoint pcp, Vector3d dir) { Double angleO = pcp.getRotationAngle(); double angle = 0.0; if (angleO != null) angle = angleO; - Boolean reversedO = pcp.getReversed(); - boolean reversed = false; - if (reversedO != null) - reversed = reversedO; - Quat4d q = pcp.getControlPointOrientationQuat(angle, reversed); + 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); } @@ -1524,7 +1731,7 @@ public class PipingRules { System.out.println("PipingRules.updateBranchControlPointBranches() " + bcp); if (bcp.isDualInline()) return; - Collection branches = bcp.getSubPoint(); + Collection branches = bcp.getChildPoints(); if (branches.size() == 0) { if (DEBUG) System.out.println("No Branches found"); @@ -1579,7 +1786,7 @@ public class PipingRules { tcp.setTurnAxis(new Vector3d(MathTools.Y_AXIS)); } - updateControlPointOrientation(tcp); + updateControlPointOrientation(tcp,prev); if (DEBUG) System.out.println("PipingTools.updateTurnControlPointTurn " + prev + " " + next + " " + turnAngle + " " + turnAxis); @@ -1650,8 +1857,11 @@ public class PipingRules { while (true) { List points = getControlPoints(pipeRun); PipeControlPoint pcp = points.get(0); - if (pcp.isSizeChange() && pcp.getSubPoint().size() > 0) { - pipeRun = pcp.getPipeRun(); + if (pcp.isSizeChange() && pcp.getChildPoints().size() > 0) { + PipeRun pr = pcp.getPipeRun(); + if (pr != pipeRun) + pipeRun = pr; + else break; } else { break; } @@ -1663,8 +1873,12 @@ public class PipingRules { List points = getControlPoints(pipeRun); pcps.add(points); PipeControlPoint pcp = points.get(points.size()-1); - if (pcp.getSubPoint().size() > 0) { - pipeRun = pcp.getSubPoint().get(0).getPipeRun(); + if (pcp.getChildPoints().size() > 0) { + PipeRun pipeRun2 = pcp.getChildPoints().get(0).getPipeRun(); + if (pipeRun == pipeRun2) + break; + else + pipeRun = pipeRun2; } else { break; } @@ -1681,7 +1895,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(); @@ -1712,11 +1925,11 @@ public class PipingRules { PipeControlPoint current = list.get(i); PipeControlPoint currentSub = null; if (current.isDualInline()) - currentSub = current.getSubPoint().get(0); + currentSub = current.getDualSub(); if (first) { PipeControlPoint next = list.get(i+1); if (next.isDualInline()) - next = next.getSubPoint().get(0); + next = next.getDualSub(); if (current.getNext() == next) current.setNext(null); current.setPrevious(next); @@ -1741,7 +1954,7 @@ public class PipingRules { PipeControlPoint prev = list.get(i-1); PipeControlPoint next = list.get(i+1); if (next.isDualInline()) - next = next.getSubPoint().get(0); + next = next.getDualSub(); current.setPrevious(next); @@ -1763,30 +1976,7 @@ public class PipingRules { } } - public static void merge(PipeRun run1, PipeRun r2) { - Map positions = new HashMap(); - Map orientations = new HashMap(); - for (PipeControlPoint pcp : r2.getControlPoints()) { - positions.put(pcp, pcp.getWorldPosition()); - orientations.put(pcp, pcp.getWorldOrientation()); - } - for (PipeControlPoint pcp : r2.getControlPoints()) { - r2.deattachChild(pcp); - run1.addChild(pcp); - PipelineComponent component = pcp.getPipelineComponent(); - if (component != null) { - if (!(component instanceof Nozzle)) { - component.deattach(); - run1.addChild(component); - } else { - Nozzle n = (Nozzle)component; - n.setPipeRun(run1); - } - } - } - r2.remove(); - - } + public static void validate(PipeRun pipeRun) { if (pipeRun == null) @@ -1818,7 +2008,7 @@ public class PipingRules { if (pcp.getParentPoint() == null) { PipeControlPoint sub = null; if (pcp.isDualInline()) - sub = pcp.getSubPoint().get(0); + sub = pcp.getDualSub(); PipeControlPoint next = pcp.getNext(); PipeControlPoint prev = pcp.getPrevious(); if (next != null) { @@ -1871,7 +2061,6 @@ public class PipingRules { // this should not be possible throw new RuntimeException("VariableLengthComponent " + splittingComponent + " is not connected to anything."); } - double reservedLength = splittingComponent.getControlPoint().getLength(); double newLength = newComponent.getControlPoint().getLength(); @@ -1907,21 +2096,20 @@ public class PipingRules { vn.interpolate(next, 0.5); - PipeControlPoint newVariableLengthCP = null;//insertStraight(pcp1, pcp2, pos, length); if (nextCP == null) { newCP.insert(splittingCP, Direction.NEXT); - newVariableLengthCP = insertStraight(newCP, Direction.NEXT, new Vector3d(vn), ln); + insertStraight(newCP, Direction.NEXT, new Vector3d(vn), ln); splittingCP.setWorldPosition(new Vector3d(vp)); // ControlPointTools.setWorldPosition(splittingCP, vp); // splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp); } else if (prevCP == null) { newCP.insert(splittingCP, Direction.PREVIOUS); - newVariableLengthCP = insertStraight(newCP, Direction.PREVIOUS, new Vector3d(vp), lp); + insertStraight(newCP, Direction.PREVIOUS, new Vector3d(vp), lp); splittingCP.setWorldPosition(new Vector3d(vn)); // splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, ln); } else { newCP.insert(splittingCP, nextCP); - newVariableLengthCP = insertStraight(newCP, nextCP, new Vector3d(vn), ln); + insertStraight(newCP, nextCP, new Vector3d(vn), ln); splittingCP.setWorldPosition(new Vector3d(vp)); // splittingCP.setRelatedScalarDouble(ProcessResource.plant3Dresource.HasLength, lp); } @@ -1931,7 +2119,7 @@ public class PipingRules { public static void addSizeChange(boolean reversed, PipeRun pipeRun, PipeRun other, InlineComponent reducer, PipeControlPoint previous, PipeControlPoint next) { PipeControlPoint pcp = reducer.getControlPoint(); - PipeControlPoint ocp = pcp.getSubPoint().get(0); + PipeControlPoint ocp = pcp.getDualSub(); if (!reversed) { String name = pipeRun.getUniqueName("Reducer"); reducer.setName(name);