From 3d5276c8b4b0ec8f440994f17b20bec34e6cc3fe Mon Sep 17 00:00:00 2001 From: Marko Luukkainen Date: Wed, 28 Aug 2019 17:55:06 +0300 Subject: [PATCH] Preliminary example of creating pipes with elbow coordinates * ComponentUtil.connect now works, if connected Component is not attached to a PipeRun * Modified Piping rules to use path leg ends for turn calculation gitlab #28 Change-Id: If16e6e63e44a697d5c07c0f3ec0d1a0c0fba3b9d --- .../scl/Plant3d/Test/Test2.scl | 100 ++++++ .../scenegraph/controlpoint/PipingRules.java | 309 +++++++----------- .../plant3d/utils/ComponentUtils.java | 11 +- 3 files changed, 234 insertions(+), 186 deletions(-) create mode 100644 org.simantics.plant3d/scl/Plant3d/Test/Test2.scl diff --git a/org.simantics.plant3d/scl/Plant3d/Test/Test2.scl b/org.simantics.plant3d/scl/Plant3d/Test/Test2.scl new file mode 100644 index 00000000..354a49f7 --- /dev/null +++ b/org.simantics.plant3d/scl/Plant3d/Test/Test2.scl @@ -0,0 +1,100 @@ +import "Plant3d/Utils/P3DUtil" +import "Simantics/DB" +import "Plant3d/Utils/Loader" +import "G3D/SCLUtil" +import "JavaBuiltin" +import "G3D/Math/Tuple3d" as T3D +import "G3D/Math/Vector3d" as V3D +import "G3D/Scenegraph/G3DNode" as G3D +import "Plant3d/Scenegraph/P3DRootNode" as P3R +import "Plant3d/Scenegraph/P3DNode" as P3N +import "Plant3d/Scenegraph/Equipment" as E +import "Plant3d/Scenegraph/PipelineComponent" as PC +import "Plant3d/Scenegraph/EndComponent" as EC +import "Plant3d/Scenegraph/InlineComponent" as IC +import "Plant3d/Scenegraph/TurnComponent" as TC +import "Plant3d/Utils/P3DScriptNodeMap" as P3S +import "Plant3d/Utils/P3DUtil" as P3DUtil +import "Plant3d/Utils/ComponentUtils" as CU +import "http://www.simantics.org/Layer0-1.1" as L0 + +doTest :: () +doTest = do + + myModel = syncWrite(\_ -> do + myModel = P3DUtil.createModel "Test2" + claim (resource "http://Projects/Development%20Project") L0.ConsistsOf myModel + myModel) + p3dmap = load myModel + rootMaybe = javaSafeCoerce (P3S.getRootNode p3dmap) :: Maybe P3R.P3DRootNode + root = fromJust rootMaybe + pump = CU.createEquipmentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Pump" + P3N.setName pump "My Pump" + P3S.commit p3dmap "Created a pump" + P3S.update p3dmap + n1 = CU.createDefaultNozzle root pump + P3S.commit p3dmap "Created a nozzle" + P3S.update p3dmap + pipe = CU.addComponent root (unsafeCoerce n1) (CU.createVariableLength "http://www.simantics.org/Plant3D-0.1/Builtin/Straight" PC.NEXT PC.NEXT 1.0) + P3S.commit p3dmap "Created a pipe" + P3S.update p3dmap + + elbow = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Elbow" + G3D.setPosition elbow (V3D.createVector3d (-1.6) 0.15 0.0) + CU.connect pipe elbow + + pipe = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Straight" + CU.connect elbow pipe + + elbow = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Elbow" + G3D.setPosition elbow (V3D.createVector3d (-1.6) 2.6 0.0) + CU.connect pipe elbow + + pipe = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Straight" + CU.connect elbow pipe + + elbow = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Elbow" + G3D.setPosition elbow (V3D.createVector3d (-1.6) 2.6 (-1.4)) + CU.connect pipe elbow + + pipe = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Straight" + CU.connect elbow pipe + + elbow = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Elbow" + G3D.setPosition elbow (V3D.createVector3d (2.9) 2.6 (-1.4)) + CU.connect pipe elbow + + pipe = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Straight" + CU.connect elbow pipe + + elbow = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Elbow" + G3D.setPosition elbow (V3D.createVector3d (2.9) 2.6 (3.0)) + CU.connect pipe elbow + + pipe = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Straight" + CU.connect elbow pipe + + elbow = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Elbow" + G3D.setPosition elbow (V3D.createVector3d (2.9) 0.15 (3.0)) + CU.connect pipe elbow + + pipe = CU.createComponentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/Straight" + CU.connect elbow pipe + G3D.setPosition pipe (V3D.createVector3d (1.8) 0.15 3.0) + P3S.commit p3dmap "Created a pipe" + P3S.update p3dmap + + tank = CU.createEquipmentWithURI root "http://www.simantics.org/Plant3D-0.1/Builtin/HorizontalTank" + P3N.setName tank "My Tank" + G3D.setPosition tank (V3D.createVector3d 0.0 0.0 3.0) + P3S.commit p3dmap "Created a tank" + P3S.update p3dmap + n2 = CU.createDefaultNozzle root tank + G3D.setPosition n2 (V3D.createVector3d 0.6 0.3 0.0) + P3S.commit p3dmap "Created a nozzle" + P3S.update p3dmap + + CU.connect pipe (unsafeCoerce n2) + P3S.commit p3dmap "Connected a pipe to a nozzle" + P3S.update p3dmap + () \ No newline at end of file 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 386cc56a..2fef57fb 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 @@ -296,41 +296,27 @@ public class PipingRules { } private static void updatePathLegNext(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception { - ArrayList list = new ArrayList(); - PipeControlPoint end = start.findNextEnd(list); - // this is for inline cp that is also path leg end - if (lengthChange == PathLegUpdateType.NONE) { - if (start.equals(updated)) - lengthChange = PathLegUpdateType.NEXT; - else if (end.equals(updated)) - lengthChange = PathLegUpdateType.PREV; - } - updatePathLegNext(start, list, end, updated, lengthChange); - } - private static void updatePathLegNext(PipeControlPoint start, ArrayList list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception { - updatePathLeg(start, list, end, false, 0, new ArrayList(), updated, lengthChange); + 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; + } + updatePathLeg(us, lengthChange); } private static void updatePathLegPrev(PipeControlPoint start, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception { - ArrayList list = new ArrayList(); - PipeControlPoint end = start.findPreviousEnd(list); // TODO: this method is not symmetric with updatePathLegNext, which may alter lengthChange parameter? - updatePathLegPrev(start, list, end, updated, lengthChange); - } - - private static void updatePathLegPrev(PipeControlPoint start, ArrayList list, PipeControlPoint end, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception { - // reverses the list - ArrayList nextList = new ArrayList(); - for (PipeControlPoint icp : list) { - if (icp.isDualSub()) { - nextList.add(0, icp.getParentPoint()); - } else { - nextList.add(0, icp); - } - } - updatePathLeg(end, nextList, start, true, 0, new ArrayList(), updated, lengthChange); - + 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; +// } + updatePathLeg(us, lengthChange); } private static class UpdateStruct2 { @@ -425,44 +411,38 @@ public class PipingRules { hasOffsets = true; } -// for (PipeControlPoint icp : list) { -// if (icp.isOffset()) { -// icp.setOffset(((InlineComponent)icp.getPipelineComponent()).getOffset()); -// hasOffsets = true; -// Vector3d v = icp.getSizeChangeOffsetVector(dir); -// offset.add(v); -// } else if (icp.isDualSub()) -// ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!")); -// } if (DEBUG && hasOffsets) System.out.println("calcOffset s:"+ startPoint + " e:" + endPoint + " d:" + dir + " o:"+offset) ; return hasOffsets; } - - /** - * @param start - * starting point of the pipe run - * @param list - * list of inline control points in the pipe run - * @param end - * ending point of the pipe run - * @param reversed - * boolean flag indicating wether start or end control point was - * modified (if true then end point was modified) - * @throws TransactionException - */ - private static void updatePathLeg(PipeControlPoint start, ArrayList list, PipeControlPoint end, boolean reversed, int iter, ArrayList toRemove, PipeControlPoint updated, PathLegUpdateType lengthChange) throws Exception { - if (start == end) - return; - // FIXME: direction is calculated wrong way! - boolean hasOffsets = false; - Vector3d offset = new Vector3d(); - Vector3d startPoint = start.getWorldPosition(); - Vector3d endPoint = end.getWorldPosition(); - Vector3d dir = new Vector3d(); - hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset); - updatePathLeg(new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, reversed, toRemove, updated), lengthChange); - + + private static UpdateStruct2 createUS(PipeControlPoint start, Direction direction, int iter, ArrayList toRemove, PipeControlPoint updated) { + ArrayList list = new ArrayList(); + PipeControlPoint end = null; + if (direction == Direction.NEXT) { + end = start.findNextEnd(list); + } else { + ArrayList prevList = new ArrayList(); + PipeControlPoint tend = start.findPreviousEnd(prevList); + for (PipeControlPoint icp : prevList) { + if (icp.isDualSub()) { + list.add(0, icp.getParentPoint()); + } else { + list.add(0, icp); + } + } + end = start; + start = tend; + } + if (start == end) + return null; + boolean hasOffsets = false; + Vector3d offset = new Vector3d(); + Vector3d startPoint = start.getWorldPosition(); + Vector3d endPoint = end.getWorldPosition(); + Vector3d dir = new Vector3d(); + hasOffsets = calculateOffset(startPoint, endPoint, list, dir, offset); + return new UpdateStruct2(start, startPoint, list, end, endPoint, dir, offset, hasOffsets, iter, direction == Direction.PREVIOUS, toRemove, updated); } private static boolean asDirected(PipeControlPoint pcp, Direction direction) { @@ -853,7 +833,8 @@ public class PipingRules { Vector3d directedDirection = direction(dcp, dcpStart ? Direction.NEXT : Direction.PREVIOUS); if (directedDirection == null) { - updateTurnControlPointTurn(dcp, dcp.getPrevious(), dcp.getNext()); + //updateTurnControlPointTurn(dcp, dcp.getPrevious(), dcp.getNext()); + updateTurnControlPointTurn(dcp, null, null); directedDirection = direction(dcp, dcpStart ? Direction.NEXT : Direction.PREVIOUS); if (directedDirection == null) { return; @@ -1148,15 +1129,7 @@ public class PipingRules { // this won't work properly if inline control points are not updated PipeControlPoint startPrev = u.start.getPrevious(); if (startPrev != null) { - double a; - if (!u.hasOffsets) { - a = updateTurnControlPointTurn(u.start, startPrev, u.end); - } else { - Vector3d ep = new Vector3d(u.endPoint); - ep.sub(u.offset); - a = updateTurnControlPointTurn(u.start, u.startPoint, startPrev.getPosition(), ep); - - } + double a = updateTurnControlPointTurn(u.start, null, u.dir); if (a < MIN_TURN_ANGLE && u.start.isDeletable()) startRemoved = true; else if (lengthChange == PathLegUpdateType.PREV || lengthChange == PathLegUpdateType.PREV_S) { @@ -1173,14 +1146,8 @@ public class PipingRules { PipeControlPoint endNext = u.end.getNext(); if (endNext != null) { - double a; - if (!u.hasOffsets) { - a = updateTurnControlPointTurn(u.end, u.start, endNext); - } else { - Vector3d sp = new Vector3d(u.startPoint); - sp.add(u.offset); - a = updateTurnControlPointTurn(u.end, u.endPoint, sp, endNext.getPosition()); - } + // TODO: u.end, u.dir, null + double a = updateTurnControlPointTurn(u.end, null, null); if (a < MIN_TURN_ANGLE && u.end.isDeletable()) endRemoved = true; else if (lengthChange == PathLegUpdateType.NEXT || lengthChange == PathLegUpdateType.NEXT_S) { @@ -1347,7 +1314,8 @@ public class PipingRules { if (updateEnds) { if (u.start.isTurn()) { - updateTurnControlPointTurn(u.start, u.start.getPrevious(), u.start.getNext()); + //updateTurnControlPointTurn(u.start, u.start.getPrevious(), u.start.getNext()); + updateTurnControlPointTurn(u.start, null, null); // updatePathLegPrev(u.start, u.start, PathLegUpdateType.NONE); } else if (u.start.isEnd()) { updateEndComponentControlPoint(u.start, u.startPoint, u.endPoint); @@ -1355,7 +1323,8 @@ public class PipingRules { updateControlPointOrientation(u.start); } if (u.end.isTurn()) { - updateTurnControlPointTurn(u.end, u.end.getPrevious(), u.end.getNext()); + //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); @@ -1568,58 +1537,75 @@ public class PipingRules { } } - /** - * Recalculates turn control point's internal data (turn angle and offset) - * - * @param tcp - * @param prev - * @param next - */ - private static double updateTurnControlPointTurn(PipeControlPoint tcp, PipeControlPoint prev, PipeControlPoint next) { - if (DEBUG) - System.out.println("PipingTools.updateTurnControlPointTurn()" + tcp); - - if (!tcp.isFixed()) { - if (next == null || prev == null) - return tcp.getTurnAngle(); - Vector3d middlePoint = tcp.getWorldPosition(); - Vector3d nextPoint = next.getWorldPosition(); - Vector3d prevPoint = prev.getWorldPosition(); - return updateTurnControlPointTurn(tcp, middlePoint, prevPoint, nextPoint); - } else { - // Verify that fixed turn is properly defined. - // TODO : when reversed flag is changed, rotation angle should be recalculated, otherwise the orientation will change. - // TODO : should reverse flag toggle to be done already when we are removing defining side? - if (prev != null && next != null) { - // Nothing to do - } else if (prev == null) { - if (!tcp._getReversed()) - tcp.setReversed(true); - } else if (next == null) { - if (tcp._getReversed()) - tcp.setReversed(false); - } - - Vector3d dir; - if (!tcp._getReversed()) { - if (prev == null) - return Math.PI; // FIXME : argh - - Vector3d middlePoint = tcp.getWorldPosition(); - Vector3d prevPoint = prev.getWorldPosition(); - dir = new Vector3d(); - dir.sub(middlePoint, prevPoint); - - } else { - if (next == null) - return Math.PI; // FIXME : argh - - Vector3d middlePoint = tcp.getWorldPosition(); - Vector3d nextPoint = next.getWorldPosition(); - dir = new Vector3d(); - dir.sub(middlePoint, nextPoint); - } - dir.normalize(); + private static double updateTurnControlPointTurn(PipeControlPoint tcp, Vector3d prev, Vector3d next) { + if (next == null) { + UpdateStruct2 us = createUS(tcp, Direction.NEXT, 0, new ArrayList(), tcp); + if (us != null) + next = us.dir; + } + if (prev == null) { + UpdateStruct2 us = createUS(tcp, Direction.PREVIOUS, 0, new ArrayList(), tcp); + if (us != null) { + prev = us.dir; + } + } + + if (!tcp.isFixed()) { + + + if (next == null || prev == null) { + if (tcp.getTurnAngle() != null) + return tcp.getTurnAngle(); + return Math.PI; // FIXME : argh + } + double turnAngle = prev.angle(next); + + double angle = Math.PI - turnAngle; + + Vector3d turnAxis = new Vector3d(); + turnAxis.cross(prev, next); + if (turnAxis.lengthSquared() > MathTools.NEAR_ZERO) { + double elbowRadius = tcp.getPipelineComponent().getPipeRun().getTurnRadius(); + double R = elbowRadius / Math.tan(angle * 0.5); + + turnAxis.normalize(); + tcp.setTurnAngle(turnAngle); + tcp.setLength(R);// setComponentOffsetValue(R); + tcp.setTurnAxis(turnAxis); + // tcp.setPosition(tcp.getPosition()); + } else { + turnAngle = 0.0; + tcp.setTurnAngle(0.0); + tcp.setLength(0.0); + tcp.setTurnAxis(new Vector3d(MathTools.Y_AXIS)); + } + + updateControlPointOrientation(tcp); + + if (DEBUG) + System.out.println("PipingTools.updateTurnControlPointTurn " + prev + " " + next + " " + turnAngle + " " + turnAxis); + return turnAngle; + } else { + + if (prev != null && next != null) { + // Nothing to do + } else if (prev == null) { + if (!tcp._getReversed()) + tcp.setReversed(true); + } else if (next == null) { + if (tcp._getReversed()) + tcp.setReversed(false); + } + + Vector3d dir = null; + if (!tcp._getReversed()) { + dir = prev; + } else { + dir = next; + } + if (dir == null) { + return Math.PI; // FIXME : argh + } Quat4d q = PipeControlPoint.getControlPointOrientationQuat(dir, tcp.getRotationAngle() != null ? tcp.getRotationAngle() : 0.0); Vector3d v = new Vector3d(); @@ -1627,54 +1613,9 @@ public class PipingRules { tcp.setTurnAxis(v); tcp.setWorldOrientation(q); return tcp.getTurnAngle(); - } - } - - /** - * Recalculates turn control point's internal data (turn angle and offset) - * - * @param tcp - * @param middlePoint - * @param nextPoint - * @param prevPoint - */ - private static double updateTurnControlPointTurn(PipeControlPoint tcp, Vector3d middlePoint, Vector3d prevPoint, Vector3d nextPoint) { - - Vector3d dir1 = new Vector3d(middlePoint); - dir1.sub(prevPoint); - Vector3d dir2 = new Vector3d(nextPoint); - dir2.sub(middlePoint); - if (DEBUG) - System.out.println("PipingTools.updateTurnControlPointTurn " + tcp + " " + prevPoint + " " + middlePoint + " " + nextPoint); - return updateTurnControlPointTurn(tcp, dir1, dir2); - } - - private static double updateTurnControlPointTurn(PipeControlPoint tcp, Vector3d dir1, Vector3d dir2) { - double turnAngle = dir1.angle(dir2); - - double angle = Math.PI - turnAngle; - - Vector3d turnAxis = new Vector3d(); - turnAxis.cross(dir1, dir2); - if (turnAxis.lengthSquared() > MathTools.NEAR_ZERO) { - double elbowRadius = tcp.getPipelineComponent().getPipeRun().getTurnRadius(); - double R = elbowRadius / Math.tan(angle * 0.5); - - turnAxis.normalize(); - tcp.setTurnAngle(turnAngle); - tcp.setLength(R);// setComponentOffsetValue(R); - tcp.setTurnAxis(turnAxis); -// tcp.setPosition(tcp.getPosition()); - } else { - turnAngle = 0.0; - tcp.setTurnAngle(0.0); - tcp.setLength(0.0); - tcp.setTurnAxis(new Vector3d(MathTools.Y_AXIS)); - } - updateControlPointOrientation(tcp); - if (DEBUG) - System.out.println("PipingTools.updateTurnControlPointTurn " + dir1 + " " + dir2 + " " + turnAngle + " " + turnAxis); - return turnAngle; + } + + } public static List getControlPoints(PipeRun pipeRun) { diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java b/org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java index cc19260b..15ee7918 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java @@ -516,7 +516,7 @@ public class ComponentUtils { requiresReverse = true; } PipeRun other = endCP.getPipeRun(); - boolean mergeRuns = pipeRun.equalSpecs(other); + boolean mergeRuns = other == null ? true : pipeRun.equalSpecs(other); if (requiresReverse) { // Pipe line must be traversible with next/previous relations without direction change. @@ -526,8 +526,15 @@ public class ComponentUtils { } if (mergeRuns) { // Runs have compatible specs and must be merged - if (pipeRun != other) // FIXME: temporary workaround. + if (other != null && pipeRun != other) PipingRules.merge(pipeRun, other); + else if (other == null) { + if (!(endTo instanceof Nozzle)) { + pipeRun.addChild(endTo); + } else { + endTo.setPipeRun(pipeRun); + } + } if (!reversed) { currentCP.setNext(endCP); endCP.setPrevious(currentCP); -- 2.45.2