From 9e1e51825bfdcd72d7006e1bff703e7eb52919c6 Mon Sep 17 00:00:00 2001 From: Marko Luukkainen Date: Tue, 16 Jul 2019 13:50:28 +0300 Subject: [PATCH] Added support for eccentric reducers * Various fixes to PipingRules * At the moment, offset calculation is hard-coded. (Introduced component calculated offset, but that has not been tested) * AddComponentAction is able to place components in proper location after reducer * Reducer uses custom mesh gitlab #12 gitlab #10 Change-Id: I62fdd4df5acc9e8e02823d36b738b48f70f56ac4 --- .../graph/plant3d_builtins.pgraph | 1 + .../plant3d/actions/AddComponentAction.java | 13 +- .../geometry/ReducerGeometryProvider.java | 41 ++- .../geometry/StraightGeometryProvider.java | 2 +- .../plant3d/scenegraph/InlineComponent.java | 40 ++- .../controlpoint/ControlPointFactory.java | 1 + .../controlpoint/PipeControlPoint.java | 74 +++-- .../scenegraph/controlpoint/PipingRules.java | 289 ++++++++++++------ 8 files changed, 338 insertions(+), 123 deletions(-) diff --git a/org.simantics.plant3d.ontology/graph/plant3d_builtins.pgraph b/org.simantics.plant3d.ontology/graph/plant3d_builtins.pgraph index 5c386871..49bec3ea 100644 --- a/org.simantics.plant3d.ontology/graph/plant3d_builtins.pgraph +++ b/org.simantics.plant3d.ontology/graph/plant3d_builtins.pgraph @@ -26,6 +26,7 @@ P3D.Builtin.ConcentricReducer getModel() throws Exception { // GP_Circ circ = new GP_Circ(new double[]{-length*0.5, 0.0, 0.0,1.0,0.0,0.0}, radius); // GP_Circ circ2 = new GP_Circ(new double[]{length*0.5, 0.0, 0.0,1.0,0.0,0.0}, radius2); @@ -33,6 +43,29 @@ public class ReducerGeometryProvider extends BuiltinGeometryProvider { return Collections.singletonList(shape); } + @Override + public Mesh getMesh() { + double length = Math.max(0.1, Math.abs(radius-radius2)*4.0); + if (length < .0001) + return null; + Tube tube = new Tube(); + tube.setResolution(16); + List vertices = new ArrayList(); + List radius = new ArrayList(); + List tangents = new ArrayList(); + vertices.add(new Point3d(-length*0.5, 0.0, 0.0)); + vertices.add(new Point3d( length*0.5, offset, 0.0)); + radius.add(this.radius); + radius.add(this.radius2); + tangents.add(new Vector3d(1.0,0.0,0.0)); + tangents.add(new Vector3d(1.0,0.0,0.0)); + tube.setVertices(vertices); + tube.setRadiis(radius); + tube.setTangents(tangents); + tube.setCap(false); + return tube.create(); + } + @Override public void setProperties(Map props) { @@ -44,6 +77,10 @@ public class ReducerGeometryProvider extends BuiltinGeometryProvider { radius2 = (Double)props.get("radius2"); } + if (props.containsKey("offset")) { + offset = (Double)props.get("offset"); + } + } diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/StraightGeometryProvider.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/StraightGeometryProvider.java index df3281ec..6879b223 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/StraightGeometryProvider.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/StraightGeometryProvider.java @@ -32,7 +32,7 @@ public class StraightGeometryProvider extends BuiltinMeshProvider { @Override public Mesh getMesh() { - if (length < .0001) + if (length < .001) return null; Tube tube = new Tube(); tube.setResolution(16); diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/InlineComponent.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/InlineComponent.java index 88b1fab3..a1558c86 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/InlineComponent.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/InlineComponent.java @@ -16,6 +16,7 @@ public class InlineComponent extends PipelineComponent { private String type; private PipeControlPoint controlPoint; + private boolean componentCalculatedOffset = false; @GetType(Plant3D.URIs.InlineComponent) public String getType() { @@ -52,9 +53,39 @@ public class InlineComponent extends PipelineComponent { if (calculated.containsKey("length")) { controlPoint.setLength((Double)calculated.get("length")); } + if (calculated.containsKey("offset")) { + controlPoint.setOffset((Double)calculated.get("offset")); + componentCalculatedOffset = true; + } else { + componentCalculatedOffset = false; + } } } + @Override + public void setPipeRun(PipeRun pipeRun) { + // TODO Auto-generated method stub + super.setPipeRun(pipeRun); + if (getPipeRun() != null && getAlternativePipeRun() != null) { + updateOffset(); + } + } + + @Override + public void setAlternativePipeRun(PipeRun pipeRun) { + // TODO Auto-generated method stub + super.setAlternativePipeRun(pipeRun); + if (getPipeRun() != null && getAlternativePipeRun() != null) { + updateOffset(); + } + } + + private void updateOffset() { + if (!componentCalculatedOffset && getControlPoint().isOffset()) { + getControlPoint().setOffset(getPipeRun().getPipeDiameter()*0.5 - getAlternativePipeRun().getPipeDiameter()*0.5); + } + } + @Override public Map updateParameterMap() { Map map = new HashMap(); @@ -63,9 +94,12 @@ public class InlineComponent extends PipelineComponent { map.put("length", controlPoint.getLength()); if (controlPoint.isDualInline()) { PipeControlPoint sub = controlPoint.getSubPoint().get(0); - PipeRun pipeRun = sub.getPipeRun(); - if (pipeRun != null) { - map.put("radius2", pipeRun.getPipeDiameter() * 0.5); + PipeRun pipeRun2 = sub.getPipeRun(); + if (pipeRun2 != null) { + map.put("radius2", pipeRun2.getPipeDiameter() * 0.5); + } + if (controlPoint.isOffset() && !componentCalculatedOffset) { + map.put("offset", controlPoint.getOffset()); } } } diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java index 193cdd27..a6d1eb26 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/ControlPointFactory.java @@ -57,6 +57,7 @@ public class ControlPointFactory { sub.setType(inst.type); sub.setFixed(inst.fixed); sub.setSub(true); + sub.setDeletable(false); // pcp.setOffset(0.0); if (inst.isOffset) pcp.setOffset(0.0); diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java index 02bce622..21f2564d 100644 --- a/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java +++ b/org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java @@ -173,7 +173,9 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { component.setNext(next != null ? next.component : null); else component.setBranch0(next != null ? next.component : null); + updateSubPoint(); } + } public void setPrevious(PipeControlPoint previous) { @@ -182,11 +184,14 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { // if (previous != null && getPipeRun() == null) // throw new RuntimeException("Cannot connect control point befor piperun has been set"); this.previous = previous; - if (component != null) + if (component != null) { if (parent == null || sub) component.setPrevious(previous != null ? previous.component : null); else component.setBranch0(previous != null ? previous.component : null); + updateSubPoint(); + } + } public PipeControlPoint parent; @@ -290,7 +295,17 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { if (rotationAngle == null) rotationAngle = 0.0; Quat4d q = getControlPointOrientationQuat(dir, rotationAngle); - Vector3d v = new Vector3d(0.0,0.0,offset); + Vector3d v = new Vector3d(0.0,offset,0.0); + Vector3d offset = new Vector3d(); + MathTools.rotate(q, v, offset); + return offset; + } + + public Vector3d getSizeChangeOffsetVector() { + if (rotationAngle == null) + rotationAngle = 0.0; + Quat4d q = getControlPointOrientationQuat(rotationAngle); + Vector3d v = new Vector3d(0.0,offset,0.0); Vector3d offset = new Vector3d(); MathTools.rotate(q, v, offset); return offset; @@ -547,8 +562,12 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { } else { if (isInline()) { + PipeControlPoint pcp = this; + if (pcp.isDualSub()) { + pcp = pcp.getParentPoint(); + } Vector3d v = new Vector3d(); - v.sub(getWorldPosition(),previous.getWorldPosition()); + v.sub(pcp.getWorldPosition(),previous.getWorldPosition()); return v; } else if (isDirected()) { return getDirectedControlPointDirection(); @@ -579,8 +598,12 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { return v; } else { if (isInline()) { + PipeControlPoint pcp = this; + if (pcp.isDualInline()) { + pcp = pcp.getSubPoint().get(0); + } Vector3d v = new Vector3d(); - v.sub(getWorldPosition(),next.getWorldPosition()); + v.sub(pcp.getWorldPosition(),next.getWorldPosition()); return v; } else if (isDirected()) { Vector3d v = getDirectedControlPointDirection(); @@ -1031,10 +1054,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { super.setOrientation(orientation); if (getParentPoint() == null && component != null) component._setWorldOrientation(getWorldOrientation()); - for (PipeControlPoint sub : getSubPoint()) { - sub.setWorldPosition(getWorldPosition()); - sub.setWorldOrientation(getWorldOrientation()); - } + updateSubPoint(); } @Override @@ -1044,9 +1064,31 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { super.setPosition(position); if (getParentPoint() == null && component != null) component._setWorldPosition(getWorldPosition()); - for (PipeControlPoint sub : getSubPoint()) { - sub.setWorldPosition(getWorldPosition()); - sub.setWorldOrientation(getWorldOrientation()); + if (isDualSub()) + System.out.println(); + updateSubPoint(); + } + + private void updateSubPoint() { + if (isOffset()) { + if (next == null && previous == null) { + for (PipeControlPoint sub : getSubPoint()) { + sub.setWorldPosition(getWorldPosition()); + sub.setWorldOrientation(getWorldOrientation()); + } + return; + } + for (PipeControlPoint sub : getSubPoint()) { + Vector3d wp = getWorldPosition(); + wp.add(getSizeChangeOffsetVector()); + sub.setWorldPosition(wp); + sub.setWorldOrientation(getWorldOrientation()); + } + } else { + for (PipeControlPoint sub : getSubPoint()) { + sub.setWorldPosition(getWorldPosition()); + sub.setWorldOrientation(getWorldOrientation()); + } } } @@ -1054,19 +1096,13 @@ public class PipeControlPoint extends G3DNode implements IP3DNode { public void _setWorldPosition(Vector3d position) { Vector3d localPos = getLocalPosition(position); super.setPosition(localPos); - for (PipeControlPoint sub : getSubPoint()) { - sub.setWorldPosition(getWorldPosition()); - sub.setWorldOrientation(getWorldOrientation()); - } + updateSubPoint(); } public void _setWorldOrientation(Quat4d orientation) { Quat4d localOr = getLocalOrientation(orientation); super.setOrientation(localOr); - for (PipeControlPoint sub : getSubPoint()) { - sub.setWorldPosition(getWorldPosition()); - sub.setWorldOrientation(getWorldOrientation()); - } + updateSubPoint(); } @Override 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 d7c53d4a..8cbe5a8a 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 @@ -337,18 +337,64 @@ public class PipingRules { private static boolean calculateOffset(Vector3d startPoint, Vector3d endPoint, ArrayList list, Vector3d dir, Vector3d offset) { boolean hasOffsets = false; - dir.set(startPoint); - dir.sub(endPoint); - if (dir.lengthSquared() > MathTools.NEAR_ZERO) - dir.normalize(); - offset.set(0.0, 0.0, 0.0); + List offsets = new ArrayList(list.size()); for (PipeControlPoint icp : list) { if (icp.isOffset()) { - hasOffsets = true; - offset.add(icp.getSizeChangeOffsetVector(dir)); + offsets.add(icp); } else if (icp.isDualSub()) ErrorLogger.defaultLogError("Updating pipe run, found offset controlpoint " + icp, new Exception("ASSERT!")); } + if (offsets.size() == 0) { + dir.set(startPoint); + dir.sub(endPoint); + double l = dir.lengthSquared(); + if (l > MathTools.NEAR_ZERO) + dir.scale(1.0/Math.sqrt(l)); + offset.set(0.0, 0.0, 0.0); + return false; + } else { + Vector3d sp = new Vector3d(startPoint); + Point3d ep = new Point3d(endPoint); + dir.set(sp); + dir.sub(ep); + double l = dir.lengthSquared(); + if (l > MathTools.NEAR_ZERO) + dir.scale(1.0/Math.sqrt(l)); + int iter = 100; + while (iter >= 0) { + iter--; + offset.set(0.0, 0.0, 0.0); + + for (PipeControlPoint icp : offsets) { + Vector3d v = icp.getSizeChangeOffsetVector(dir); + offset.add(v); + } + Point3d nep = new Point3d(endPoint); + nep.sub(offset); + if (nep.distance(ep) < 0.0000000001) { + break; + } + ep = nep; + dir.set(sp); + dir.sub(ep); + l = dir.lengthSquared(); + if (l > MathTools.NEAR_ZERO) + dir.scale(1.0/Math.sqrt(l)); + } + 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; } @@ -420,6 +466,13 @@ public class PipingRules { MathTools.mad(end, u.dir, -0.1); 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); + } } return; } @@ -438,51 +491,13 @@ public class PipingRules { for (int i = 1; i < pathLegPoints.size(); i++) { PipeControlPoint icp = pathLegPoints.get(i); - PipeControlPoint prev; - Vector3d prevPos; - prev = pathLegPoints.get(i - 1); - prevPos = prev.getWorldPosition(); - Vector3d currentPos = icp.getWorldPosition(); + PipeControlPoint prev = pathLegPoints.get(i - 1); + if (icp.isVariableLength()) { if (i != pathLegPoints.size() - 1) { - PipeControlPoint next; - Vector3d nextPos; - next = pathLegPoints.get(i + 1); - 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 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. - // 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.add(prevPos); - icp.setWorldPosition(dir); - icp.setLength(length); - } else { - // components leave no space to the component and it - // must be removed - if (icp.isDeletable()) - icp._remove(); - } + PipeControlPoint next = pathLegPoints.get(i + 1); + updateVariableLength(icp, prev, next); } else { // this is variable length component at the end of the @@ -490,41 +505,7 @@ public class PipingRules { // 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. - double currentLength = icp.getLength(); - - Vector3d dir = new Vector3d(); - dir.sub(currentPos, prevPos); - - if (currentLength < MathTools.NEAR_ZERO) { - currentLength = (dir.length() - prev.getInlineLength()) * 2.0; - } - - if (dir.lengthSquared() > MathTools.NEAR_ZERO) - dir.normalize(); - Point3d endPos = new Point3d(dir); - endPos.scale(currentLength * 0.5); - endPos.add(currentPos); // this is the free end of the - // component - - double offset = prev.getInlineLength(); - Point3d beginPos = new Point3d(dir); - beginPos.scale(offset); - beginPos.add(prevPos); // this is the connected end of - // the component - - double l = beginPos.distance(endPos); - - if (Double.isNaN(l)) - System.out.println(); - - dir.scale(l * 0.5); - beginPos.add(dir); // center position - - if (DEBUG) - System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l); - icp.setLength(l); - - icp.setWorldPosition(new Vector3d(beginPos)); + updateVariableLengthEnd(icp, prev); } @@ -534,6 +515,8 @@ public class PipingRules { // space between them. // I there is, we'll have to create new variable length // component between them. + Vector3d currentPos = icp.getWorldPosition(); + Vector3d prevPos = prev.getWorldPosition(); Vector3d dir = new Vector3d(currentPos); dir.sub(prevPos); double l = dir.lengthSquared(); @@ -559,23 +542,143 @@ public class PipingRules { } } } else { - u.endPoint.sub(u.offset); - // FIXME : straights + Vector3d sp = new Vector3d(u.startPoint); + Vector3d ep = new Vector3d(u.endPoint); + ep.sub(u.offset); + + ArrayList pathLegPoints = new ArrayList(); + pathLegPoints.add(u.start); + for (PipeControlPoint icp : u.list) { - updateInlineControlPoint(icp, u.startPoint, u.endPoint, u.dir); + updateInlineControlPoint(icp, sp, ep, u.dir); updateBranchControlPointBranches(icp); - + pathLegPoints.add(icp); if (icp.isOffset()) { // TODO : offset vector is already calculated and should be // cached - u.offset = icp.getSizeChangeOffsetVector(u.dir); - updateOffsetPoint(icp, u.offset); - u.startPoint.add(u.offset); - u.endPoint.add(u.offset); + Vector3d offset = icp.getSizeChangeOffsetVector(u.dir); + updateOffsetPoint(icp, offset); + sp.add(offset); + ep.add(offset); + } + } + pathLegPoints.add(u.end); + + sp = new Vector3d(u.startPoint); + ep = new Vector3d(u.endPoint); + ep.sub(u.offset); + + for (int i = 1; i < pathLegPoints.size(); i++) { + PipeControlPoint icp = pathLegPoints.get(i); + + PipeControlPoint prev = pathLegPoints.get(i - 1); + if (prev.isDualInline()) + prev = prev.getSubPoint().get(0); + + + if (icp.isVariableLength()) { + if (i != pathLegPoints.size() - 1) { + PipeControlPoint next; + next = pathLegPoints.get(i + 1); + 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); + } + } else 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); } } } } + + private static void 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 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. + // 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.add(prevPos); + icp.setWorldPosition(dir); + icp.setLength(length); + } else { + // components leave no space to the component and it + // must be removed + if (icp.isDeletable()) + icp._remove(); + } + } + + private static void updateVariableLengthEnd(PipeControlPoint icp, PipeControlPoint prev) { + double currentLength = icp.getLength(); + Vector3d currentPos = icp.getWorldPosition(); + Vector3d prevPos = prev.getWorldPosition(); + + Vector3d dir = new Vector3d(); + dir.sub(currentPos, prevPos); + + if (currentLength < MathTools.NEAR_ZERO) { + currentLength = (dir.length() - prev.getInlineLength()) * 2.0; + } + + if (dir.lengthSquared() > MathTools.NEAR_ZERO) + dir.normalize(); + Point3d endPos = new Point3d(dir); + endPos.scale(currentLength * 0.5); + endPos.add(currentPos); // this is the free end of the + // component + + double offset = prev.getInlineLength(); + Point3d beginPos = new Point3d(dir); + beginPos.scale(offset); + beginPos.add(prevPos); // this is the connected end of + // the component + + double l = beginPos.distance(endPos); + + if (Double.isNaN(l)) + System.out.println(); + + dir.scale(l * 0.5); + beginPos.add(dir); // center position + + if (DEBUG) + System.out.println("PipingRules.updateInlineControlPoints() setting variable length to " + l); + icp.setLength(l); + + icp.setWorldPosition(new Vector3d(beginPos)); + } private static void ppNoOffset(UpdateStruct2 u) throws Exception { if (DEBUG) @@ -1076,7 +1179,7 @@ public class PipingRules { private static void processPathLeg(UpdateStruct2 u, boolean updateEnds, boolean updateInline) throws Exception { if (DEBUG) - System.out.println("PipingRules.processPathLeg " + u.start + " " + u.end); + System.out.println("PipingRules.processPathLeg " + (updateEnds ? "ends " : "") + (updateInline ? "inline " : "") + u.start + " " + u.end); if (u.toRemove.size() > 0) { for (ExpandIterInfo info : u.toRemove) { -- 2.45.2