]> gerrit.simantics Code Review - simantics/3d.git/commitdiff
Fixed variable angle turns when they are not connected 43/3443/1
authorMarko Luukkainen <marko.luukkainen@semantum.fi>
Mon, 4 Nov 2019 12:36:21 +0000 (14:36 +0200)
committerMarko Luukkainen <marko.luukkainen@semantum.fi>
Mon, 4 Nov 2019 12:36:21 +0000 (14:36 +0200)
Now unconnected variable angle turns behave like fixed angle turns until
they are connected from both sides.

Additionally, added default parameter loading for geometry provides so
that they get proper initial values.

gitlab #46

Change-Id: Id7dede974fcfc69370930dba01d5a87091be671d

org.simantics.plant3d.ontology/graph/plant3d_builtins.pgraph
org.simantics.plant3d/src/org/simantics/plant3d/actions/AddComponentAction.java
org.simantics.plant3d/src/org/simantics/plant3d/actions/RoutePipeAction.java
org.simantics.plant3d/src/org/simantics/plant3d/actions/TranslateFreeVariableLengthAction.java
org.simantics.plant3d/src/org/simantics/plant3d/actions/TranslateInlineAction.java
org.simantics.plant3d/src/org/simantics/plant3d/editor/Plant3DEditor.java
org.simantics.plant3d/src/org/simantics/plant3d/geometry/ParameterRead.java [new file with mode: 0644]
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/TurnComponent.java
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipeControlPoint.java
org.simantics.plant3d/src/org/simantics/plant3d/scenegraph/controlpoint/PipingRules.java
org.simantics.plant3d/src/org/simantics/plant3d/utils/ComponentUtils.java

index fc3c0083423ace76db3bddd2dd12c42c4d50fcee..4895630f4876409fdaae0fcda47192db873d9f67 100644 (file)
@@ -132,7 +132,8 @@ P3D.Builtin.Elbow90 <T P3D.TurnComponent : P3D.TurnComponent
     @L0.assert P3D.hasParameter
          _ :P3D.Parameter
            L0.HasName "turnAngle" : L0.String
-           P3D.hasParameterValue 90.0 : L0.Double
+           //P3D.hasParameterValue 90.0 : L0.Double
+           P3D.hasParameterValue 1.5707963267948966192313216916398 : L0.Double
     @L0.assert P3D.HasTurnAngle
          1.5707963267948966192313216916398 : L0.Double
          
@@ -143,6 +144,7 @@ P3D.Builtin.Elbow45 <T P3D.TurnComponent : P3D.TurnComponent
     @L0.assert P3D.hasParameter
          _ :P3D.Parameter
            L0.HasName "turnAngle" : L0.String
-           P3D.hasParameterValue 45.0 : L0.Double
+           //P3D.hasParameterValue 45.0 : L0.Double
+           P3D.hasParameterValue 0.78539816339744830961566084581988 : L0.Double
     @L0.assert P3D.HasTurnAngle
          0.78539816339744830961566084581988 : L0.Double
\ No newline at end of file
index d4cf03073d20214baafd5303d8ac06dfdb963a9f..88ab98383633de72e05bfb8b380528c1b8f5eaab 100644 (file)
@@ -8,6 +8,7 @@ import java.util.Set;
 
 import org.eclipse.swt.widgets.Display;
 import org.simantics.db.Resource;
+import org.simantics.g3d.math.MathTools;
 import org.simantics.g3d.scenegraph.NodeMap;
 import org.simantics.g3d.scenegraph.base.INode;
 import org.simantics.g3d.vtk.swt.InteractiveVtkComposite;
@@ -71,7 +72,7 @@ public class AddComponentAction extends vtkSwtAction {
                        if (component.getPrevious() == null) {
                                allowed.add(PositionType.PREVIOUS);
                        }
-                       if (component instanceof InlineComponent && !component.getControlPoint().isFixed()){
+                       if (component instanceof InlineComponent && !component.getControlPoint().isFixedLength()){
                                allowed.add(PositionType.SPLIT);
                        }
                }
@@ -169,7 +170,7 @@ public class AddComponentAction extends vtkSwtAction {
                try  {
                        InsertInstruction inst = new InsertInstruction();
                        inst.typeUri = toAdd.getUri();
-                       inst.angle = angle;
+                       inst.angle = angle != null ? MathTools.degToRad(angle) : null;
                        inst.diameter = diameter;
                        inst.length = length;
                        inst.turnRadius = turnRadius;
index 0f82184bbda8ed287be0c2a0fee8e9c3067cf788..dac9d2c11b004c428a5103116db1fd8c88eed920 100644 (file)
@@ -112,7 +112,7 @@ public class RoutePipeAction extends vtkSwtAction {
                        allowed.add(PositionType.NEXT);
                if (this.startComponent.getPrevious() == null && !(this.startComponent instanceof Nozzle))
                        allowed.add(PositionType.PREVIOUS);
-               if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixed())
+               if (allowBranches && this.startComponent instanceof InlineComponent && !this.startComponent.getControlPoint().isFixedLength())
                        allowed.add(PositionType.SPLIT);
                setEnabled(allowed.size() > 0);
        }
@@ -326,7 +326,7 @@ public class RoutePipeAction extends vtkSwtAction {
                                        start.getControlPointEnds(previousPosition,v);
                                }
                        } else if (startComponent instanceof TurnComponent) {
-                               if (start.isFixed()) {
+                               if (start.asFixedAngle()) {
                                        direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
                                        lock = LockType.CUSTOM;
                                } else {
index e693f1fb2163a6658e6ac86c1f93c9f453c6b278..16a388208be3c1713f7c9a0bc813b7e11fcb08a6 100644 (file)
@@ -108,7 +108,7 @@ public class TranslateFreeVariableLengthAction extends RoutePipeAction{
                     start.getControlPointEnds(previousPosition,v);
                 }
             } else if (startComponent instanceof TurnComponent) {
-                if (start.isFixed()) {
+                if (start.asFixedAngle()) {
                     direction = startComponent.getControlPoint().getPathLegDirection(reversed ? Direction.PREVIOUS : Direction.NEXT);
                     lock = LockType.CUSTOM;
                 } else {
index 92a88b53ecdf21ba55b84feed4bbc914f8b611d5..594c73d3688808109c03d86de18d1a1671007cda 100644 (file)
@@ -53,9 +53,9 @@ public class TranslateInlineAction extends TranslateAction{
                                        setEnabled(false);
                                        return;
                                }
-                               if (prev.getControlPoint().isInline() && !prev.getControlPoint().isFixed() && prev.getPrevious() != null)
+                               if (prev.getControlPoint().isInline() && !prev.getControlPoint().isFixedLength() && prev.getPrevious() != null)
                                        prev = prev.getPrevious();
-                               if (next.getControlPoint().isInline() && !next.getControlPoint().isFixed() && next.getNext() != null) {
+                               if (next.getControlPoint().isInline() && !next.getControlPoint().isFixedLength() && next.getNext() != null) {
                                        next = next.getNext();
                                }
                                Point3d ns = new Point3d();
index 44e6529287bfb3ba9fd875098b8af6a2ca121668..e7db15d11e3b8adb47f68429c17202c2348f89cb 100644 (file)
@@ -75,11 +75,15 @@ import org.simantics.utils.ui.ExceptionUtils;
 import vtk.vtkActor;
 import vtk.vtkCameraPass;
 import vtk.vtkDefaultPass;
+import vtk.vtkGaussianBlurPass;
 import vtk.vtkLightsPass;
 import vtk.vtkProp;
 import vtk.vtkRenderPassCollection;
 import vtk.vtkRenderer;
+import vtk.vtkSSAAPass;
 import vtk.vtkSequencePass;
+import vtk.vtkSimpleMotionBlurPass;
+import vtk.vtkSobelGradientMagnitudePass;
 
 
 public class Plant3DEditor extends ResourceEditorPart {
@@ -308,6 +312,10 @@ public class Plant3DEditor extends ResourceEditorPart {
                vtkRenderer ren1 = panel.getRenderer();
                
                boolean multiPass = false;
+               boolean blur = false;
+               boolean ssaa = false;
+               //boolean sobel = true;
+               boolean mblur = false;
                if (multiPass) {
                        
                        vtkLightsPass lightsPass = new vtkLightsPass();
@@ -324,8 +332,26 @@ public class Plant3DEditor extends ResourceEditorPart {
                        vtkCameraPass cameraPass = new vtkCameraPass();
                        cameraPass.SetDelegatePass(seq);
                        
-                       ren1.SetPass(cameraPass);
-                       
+                       if (blur) {
+                           vtkGaussianBlurPass blurPass = new vtkGaussianBlurPass();
+                           blurPass.SetDelegatePass(cameraPass);
+                           ren1.SetPass(blurPass);
+                       } else if (ssaa) {
+                           vtkSSAAPass ssaaPass = new vtkSSAAPass();
+                           ssaaPass.SetDelegatePass(cameraPass);
+                           ren1.SetPass(ssaaPass);
+                       } else if (mblur) {
+                           vtkSimpleMotionBlurPass mBlurPass = new vtkSimpleMotionBlurPass();
+                           mBlurPass.SetDelegatePass(cameraPass);
+                ren1.SetPass(mBlurPass);
+//                     } else if (sobel) {
+//                         vtkSobelGradientMagnitudePass sobelPass = new vtkSobelGradientMagnitudePass();
+//                         sobelPass.SetDelegatePass(sobelPass);
+//                         ren1.SetPass(sobelPass);
+               } else {
+                   ren1.SetPass(cameraPass);
+               }
+                        
                }
 //             ren1.GetRenderWindow().LineSmoothingOn();
 //             ren1.GetRenderWindow().PointSmoothingOn();
diff --git a/org.simantics.plant3d/src/org/simantics/plant3d/geometry/ParameterRead.java b/org.simantics.plant3d/src/org/simantics/plant3d/geometry/ParameterRead.java
new file mode 100644 (file)
index 0000000..e69b1b9
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.plant3d.geometry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.layer0.Layer0;
+import org.simantics.plant3d.ontology.Plant3D;
+
+public class ParameterRead extends ResourceRead<Map<String, Object>> {
+           
+           public ParameterRead(Resource resource) {
+            super(resource);
+        }
+           
+           @Override
+           public Map<String, Object> perform(ReadGraph graph) throws DatabaseException {
+               Map<String,Object> parameters = new HashMap<>();
+               Layer0 L0 = Layer0.getInstance(graph);
+               Plant3D P3D = Plant3D.getInstance(graph);
+               
+               for (Resource assertion : graph.getObjects(resource, L0.Asserts)) {
+                Resource rel = graph.getSingleObject(assertion, L0.HasPredicate);
+                if (!rel.equals(P3D.hasParameter))
+                    continue;
+                Resource param = graph.getSingleObject(assertion, L0.HasObject);
+                String name = graph.getRelatedValue(param, L0.HasName, Bindings.STRING);
+                Object value = graph.getRelatedValue(param, P3D.hasParameterValue);
+                parameters.put(name, value);
+            }
+               for (Resource param : graph.getObjects(resource, P3D.hasParameter)) {
+                   String name = graph.getRelatedValue(param, L0.HasName, Bindings.STRING);
+                   Object value = graph.getRelatedValue(param, P3D.hasParameterValue);
+                   parameters.put(name, value);
+               }
+               
+               return parameters;
+           }
+
+       }
\ No newline at end of file
index 0e307a471eba496fbe1c93d5727b56cee1b5d4e8..a1374def587c857a3b0327cba4510891896838be 100644 (file)
@@ -70,7 +70,7 @@ public class TurnComponent extends PipelineComponent {
        @Override
        public void updateParameters() {
                super.updateParameters();
-               if (!isVariableAngle()) {
+               if (controlPoint.asFixedAngle()) {
                        Map<String,Object> calculated = getCalculatedParameters();
                        if (calculated.containsKey("length")) {
                                controlPoint.setLength((Double)calculated.get("length"));
@@ -81,12 +81,14 @@ public class TurnComponent extends PipelineComponent {
        
        @RelatedGetValue(Plant3D.URIs.HasTurnAngle)
        public Double getTurnAngle() {
+           if (!getControlPoint().asFixedAngle())
+               return null;
                return getControlPoint().getTurnAngle();
        }
        
        @RelatedSetValue(Plant3D.URIs.HasTurnAngle)
        public void setTurnAngle(Double a) {
-               if (!getControlPoint().isFixed())
+               if (!getControlPoint().asFixedAngle())
                        return;
                getControlPoint().setTurnAngle(a);            
        }
@@ -140,7 +142,7 @@ public class TurnComponent extends PipelineComponent {
        @RelatedGetValue(Plant3D.URIs.HasRotationAngle)
        @GetPropertyValue(name="Rotation Angle", value=Plant3D.URIs.HasRotationAngle, tabId = "Default")
        public Double getRotationAngle() {
-               if (!controlPoint.isFixed())
+               if (!controlPoint.asFixedAngle())
                        return null;
                Double d = controlPoint.getRotationAngle();
                if (d == null)
@@ -150,7 +152,7 @@ public class TurnComponent extends PipelineComponent {
        @RelatedSetValue(Plant3D.URIs.HasRotationAngle)
        @SetPropertyValue(value=Plant3D.URIs.HasRotationAngle)
        public void setRotationAngle(Double angle) {
-               if (!controlPoint.isFixed())
+               if (!controlPoint.asFixedAngle())
                        return;
                
                if (angle == null || Double.isInfinite(angle) || Double.isNaN(angle)) {
@@ -166,14 +168,14 @@ public class TurnComponent extends PipelineComponent {
        @RelatedGetValue(Plant3D.URIs.IsReversed)
        @GetPropertyValue(name="Reverse", value=Plant3D.URIs.IsReversed, tabId = "Default")
        public Boolean isReversed() {
-               if (!controlPoint.isFixed())
+               if (!controlPoint.asFixedAngle())
                        return null;
                Boolean d = controlPoint._getReversed();
                return d;
        }
        @RelatedSetValue(Plant3D.URIs.IsReversed)
        public void setReversed(Boolean reverse) {
-               if (!controlPoint.isFixed())
+               if (!controlPoint.asFixedAngle())
                        return;
                
                if (reverse == null) {
index cb76b74fe292d553215376c9468c0edb22809098..8219c1d686d146ba60c982658ab419e07b0d375b 100644 (file)
@@ -35,12 +35,12 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        private PipelineComponent component;
 
        private PointType type;
-       private boolean isFixed = true;
-       private boolean isRotate = false;
-       private boolean isReverse = false;
-       private boolean isDeletable = true;
-       private boolean isSizeChange = false;
-       private boolean isSub = false;
+       private boolean isFixed = true;        // In-line: fixed-length Turn: fixed-angle
+       private boolean isRotate = false;      // rotates around path leg axis.
+       private boolean isReverse = false;     // definition direction can be swapped
+       private boolean isDeletable = true;    // can be removed by rules
+       private boolean isSizeChange = false;  // changes size of the pipe. The next control point / component is on different PipeRun
+       private boolean isSub = false;         // child point
 
        public PipeControlPoint(PipelineComponent component) {
                this.component = component;
@@ -85,7 +85,6 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                return isFixed;
        }
 
-
        public void setFixed(boolean fixed) {
                this.isFixed = fixed;
        }
@@ -137,10 +136,20 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                return type == PointType.INLINE;
        }
 
+       /**
+        * True for end components, if control point defines absolute position direction, which rules cannot modify. 
+        * This is typical for nozzles.
+        * @return
+        */
        public boolean isDirected() {
                return isFixed && isEnd();
        }
 
+       /**
+     * True for end components, if control is opposite to directed, and rules can modify position and orientation.
+     * This is typical for caps, and other end components.
+     * @return
+     */
        public boolean isNonDirected() {
                return !isFixed && isEnd();
        }
@@ -148,10 +157,35 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        public boolean isVariableLength() {
                return !isFixed && isInline();
        }
+       
+       /**
+        * Fixed length in-line component is such that piping rules cannot modify the length.
+        * @return
+        */
+       public boolean isFixedLength() {
+        return isFixed && isInline();
+    }
 
        public boolean isVariableAngle() {
                return !isFixed && isTurn();
        }
+       
+       /**
+        * Fixed angle turn component is such that piping rules cannot modify the angle.
+        * @return
+        */
+       public boolean isFixedAngle() {
+        return isFixed && isTurn();
+    }
+       
+       /**
+        * Does the turn behave like fixed angle?
+        * For variable angle turns, the turn angle is defined by connected components, and without them, we must handle the component as fixed angle. 
+        * @return
+        */
+       public boolean asFixedAngle() {
+        return isTurn() && (isFixed || next == null || previous == null);
+    }
 
        public boolean isBranchEnd() {
                return isDeletable && isEnd();
@@ -628,7 +662,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
        public Vector3d getDirection(Direction direction) {
         if (isDirected())
             return getDirectedControlPointDirection();
-        if (isTurn() && isFixed()) {
+        if (isTurn() && asFixedAngle()) {
             if (direction == Direction.NEXT) {
                 if (previous != null) {
                     PipeControlPoint pcp = this;
@@ -687,7 +721,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                        return getDirectedControlPointDirection();
 
                                } else {
-                                       if (isVariableAngle())
+                                       if (isVariableAngle() && !asFixedAngle())
                                                throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + this);
                                        if (isInline()) {
                                                PipeControlPoint pcp = this;
@@ -703,7 +737,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                                Vector3d v = new Vector3d();
                                                v.sub(getWorldPosition(),previous.getWorldPosition());
                                                return v;
-                                       } else if (isTurn() && isFixed() && !_getReversed()) {
+                                       } else if (isTurn() && asFixedAngle() && !_getReversed()) {
                                                return getDirection(Direction.NEXT);
                                        }
                                        throw new RuntimeException("Missing implementation " + this);
@@ -725,7 +759,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                        v.negate();
                                        return v;
                                } else {
-                                       if (isVariableAngle())
+                                       if (isVariableAngle() && !asFixedAngle())
                                                throw new RuntimeException("Cannot calculate path leg direction for unconnected variable angle control point " + this);
                                        if (isInline()) {
                                                PipeControlPoint pcp = this;
@@ -743,7 +777,7 @@ public class PipeControlPoint extends G3DNode implements IP3DNode {
                                                Vector3d v = new Vector3d();
                                                v.sub(getWorldPosition(),next.getWorldPosition());
                                                return v;
-                                       } else if (isTurn() && isFixed() && _getReversed()) {
+                                       } else if (isTurn() && asFixedAngle() && _getReversed()) {
                                                return getDirection(Direction.PREVIOUS);
                                        }
                                        throw new RuntimeException("Missing implementation " + this);
index 727cf1a882e8d513fa1ab583ef2584a692054954..393dc85e1ab005bae0e56c515e5ebc238cc99835 100644 (file)
@@ -461,7 +461,7 @@ public class PipingRules {
        private static boolean asDirected(PipeControlPoint pcp, Direction direction) {
                if (pcp.isDirected())
                        return true;
-               if (pcp.isTurn() && pcp.isFixed()) {
+               if (pcp.asFixedAngle()) {
                        if (!pcp._getReversed())
                                return direction == Direction.NEXT;
                        else
@@ -498,7 +498,7 @@ public class PipingRules {
                if (DEBUG)
                        System.out.println("PipingRules.updateFreePipeRun " + u + " " + lengthChange);
                checkExpandPathLeg(u, lengthChange);
-               if (u.start.isInline() || u.end.isInline() || u.start.isFixed() || u.end.isFixed())
+               if (u.start.isInline() || u.end.isInline() || u.start.asFixedAngle()|| u.end.asFixedAngle())
                        processPathLeg(u, true, false);
        }
 
@@ -873,7 +873,7 @@ public class PipingRules {
                double distance = t.length();
                boolean aligned = (distance < ALLOWED_OFFSET);
                if (aligned) {
-                       if (u.start.isInline() || u.end.isInline() || u.start.isFixed() || u.end.isFixed())
+                       if (u.start.isInline() || u.end.isInline() || u.start.asFixedAngle() || u.end.asFixedAngle())
                                processPathLeg(u, true, false);
                        checkExpandPathLeg(u, lengthChange, inlineEnd);
                        
@@ -1486,24 +1486,9 @@ public class PipingRules {
        private static void updateEndComponentControlPoint(PipeControlPoint ecp, Vector3d start, Vector3d end) throws Exception {
                if (DEBUG)
                        System.out.println("PipingRules.updateEndComponentControlPoint() " + ecp);
-               // PipeControlPoint next = ecp.getNext();
-               // PipeControlPoint prev = ecp.getPrevious();
-               // if (next != null) {
-               // end = G3DTools.getPoint(next.getLocalPosition());
-               // start = G3DTools.getPoint(ecp.getLocalPosition());
-               // } else if (prev != null) {
-               // end = G3DTools.getPoint(ecp.getLocalPosition());
-               // start = G3DTools.getPoint(prev.getLocalPosition());
-               // } else {
-               // // TODO : warning?
-               // return;
-               // }
-               // Vector3d dir = new Vector3d (end);
-               // dir.sub(start);
-               // dir.normalize();
-               // G3DTools.setTuple(ecp.getDirection(), dir);
-               if (!ecp.isFixed())
-                       updateControlPointOrientation(ecp);
+               //FIXME : end control point cannot be fixed!
+               //if (!ecp.isFixed())
+               updateControlPointOrientation(ecp);
 
                for (PipeControlPoint pcp : ecp.getSubPoint()) {
                        // TODO update position
@@ -1564,7 +1549,7 @@ public class PipingRules {
                        }
                }
                
-               if (!tcp.isFixed()) {
+               if (!tcp.asFixedAngle()) {
                        
                        
                        if (next == null || prev == null) {
@@ -1768,7 +1753,8 @@ public class PipingRules {
                                }
                                
                        }
-                       if (current.isTurn() && current.isFixed()) {
+                       //if (current.isTurn() && current.isFixed()) {
+                       if (current.asFixedAngle()) {
                                current.setReversed(!current._getReversed());
                        }
                        if (current.isInline() && current.isReverse()) {
@@ -1856,8 +1842,8 @@ public class PipingRules {
        }
        
        public static void splitVariableLengthComponent(PipelineComponent newComponent, InlineComponent splittingComponent, boolean assignPos) throws Exception{
-               assert(!splittingComponent.getControlPoint().isFixed());
-               assert(!(newComponent instanceof  InlineComponent && !newComponent.getControlPoint().isFixed()));
+               assert(!splittingComponent.getControlPoint().isFixedLength());
+               assert(!(newComponent instanceof  InlineComponent && !newComponent.getControlPoint().isFixedLength()));
                PipeControlPoint newCP = newComponent.getControlPoint();
                PipeControlPoint splittingCP = splittingComponent.getControlPoint();
                PipeControlPoint nextCP = splittingCP.getNext();
index 4bee16b61bd94660beae05d0fe96f0295b260b07..fb065f111f98b84c9d7ebf4ee27cb85ac4517190 100644 (file)
@@ -16,7 +16,9 @@ import org.simantics.db.common.utils.NameUtils;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.g3d.math.MathTools;
 import org.simantics.g3d.scenegraph.GeometryProvider;
+import org.simantics.g3d.scenegraph.ParametricGeometryProvider;
 import org.simantics.layer0.Layer0;
+import org.simantics.plant3d.geometry.ParameterRead;
 import org.simantics.plant3d.ontology.Plant3D;
 import org.simantics.plant3d.scenegraph.EndComponent;
 import org.simantics.plant3d.scenegraph.Equipment;
@@ -49,6 +51,8 @@ public class ComponentUtils {
                                types.add(Plant3D.URIs.Builtin_ConcentricReducer);
                                types.add(Plant3D.URIs.Builtin_BranchSplitComponent);
                                types.add(Plant3D.URIs.Builtin_EccentricReducer);
+                               types.add(Plant3D.URIs.Builtin_Elbow45);
+                               types.add(Plant3D.URIs.Builtin_Elbow90);
                                
                                for (String typeURI : types) {
                                        load(graph, typeURI);
@@ -72,6 +76,11 @@ public class ComponentUtils {
                }
                if (geom != null) {
                        GeometryProvider provider = graph.adapt(geom, GeometryProvider.class);
+                       if (provider instanceof ParametricGeometryProvider) {
+                       Map<String,Object> params = graph.syncRequest(new ParameterRead(type));
+                       if (params.size() > 0)
+                           ((ParametricGeometryProvider)provider).setProperties(params);
+                       }
                        return provider;
                }
                return null;
@@ -368,7 +377,7 @@ public class ComponentUtils {
                } else if (toPcp.isDirected()) {
                        dir = new Vector3d(toPcp.getDirection(Direction.NEXT));
                        pos = new Vector3d(toPcp.getWorldPosition());
-               } else if (toPcp.isTurn() && toPcp.isFixed()) {
+               } else if (toPcp.isTurn() && toPcp.asFixedAngle()) {
                        dir = new Vector3d(toPcp.getDirection(position == PositionType.NEXT ? Direction.NEXT : Direction.PREVIOUS));
                        pos = new Vector3d(toPcp.getWorldPosition());
                        if (!lengthAdjustable) {