Automatically placing an offset in the middle of two curves.

Hello GC Forum,

I'm trying to place an offset in the middle (desired red line) of two lines (purple and white). Purple and White however each recur multiple times in the same file (with the same LevelName that cannot be changed).

I want this offset to happen automatically with the script without the need to enter the offset distance (I have tried FunctionCalls, but I need to select the purple and white lines automatically as in Distance between point from Purple[0] and White[0]). AND without selecting each Color individually.

So the desired end result would be:

1.Script extracts Purple and White from range (This I have done!)

2. Calculate the middle between the nearest purple and white lines (Purple[A], White[A] must create Middle[A]. Middle[B] must be the middle from Purple[B] and White[B])

3. Place an Offset at the calculated distance

Does anybody have a clue on how to calculate each Middle point automatically? Any help is appreciated!

If other information is required or a .DGN i'd be no problem.

Parents
  • Hi Boaz,

    My first thought is the issue is getting the Purple and White lines in an order that suits the operation. I can see by the image it may not be as simple as ordering the Purple and White lines by say Y value. (Although that might work in some instances).

    Once you have the in two lists in the correct order, there are a few ways to find the middle distance you could measure it using the distance function but what I have done in the past is just draw 2 lines from the start of one to the start of the other line, then find the midpoint of that line. I do the same for the end point of each line then draw a line between the 2 new midpoints. That is if the line is straight! I have also done it using a bspline but then take multiple points along each line and join them together then run a bspline though the midpoints of all the lines, depending on how many sample takes gives a closer result to the bspline offset. Works well when the 2 lines are not exactly the same but you need to find some middle ground.

    This process could all be written into a single function but probably easier to build up using nodes to start. 

    Should be automatic once setup.

    I will see if I have an example.

    Thanks

    Wayne

    Answer Verified By: Boaz O 

  • Hello Wayne,

    The problem is indeed separating the colours in a correct order. I'll check on ordering them by Y value to see it it works.

    Do you perhaps know if it is possible to ''transfer'' the names of complex elements from ORD to GC? This would solve the problem by filtering through the different names (each purple and white line has a different name in ORD)

    Just as some extra info: In the posts' picture A A_Middle A is the same distance as C C_Middle C (standard road design).

  • I am not sure about ORD, sorry I don't have that one. 

    I did a bit more on the problem of finding the correct "White" line to work out if I could select the closest "White" line to any selected "Purple" line and I think I got something to work.

    Probably not the fastest or best approach but it appears to work.

    Basically it goes through and a list of "Purple" lines and then looks at all the "White" lines to determine which one is the closest by calculating the distance between the 2 EndPoints of the lines. Once it determines the closest "White" line it does draws some line between the ends and finds the middle and creates a new line. 

    Was a bit interesting to create. Slight smile

    The Yellow lines are the new lines created.

    Updated DGN file with an the example.

    The function is a bit messy but it might give you some ideas.

    Thanks

    Wayne

    4370.MiddleGround.dgn

  • Hello Wayne,

    I can't seem to open the Graph on the file that you sent. I don't have the Building_Examples workset (i don't have openbuildingsdesigner), might that be the cause?

    From what I can tell from your picture, this looks very promising!

    -Boaz

  • Maybe this would help. Just the transactions for the file.

    transaction 1 stateChange 'Add baseCS'
    {
        gcModel
        {
            node User.Objects.baseCS Bentley.GC.NodeTypes.CoordinateSystem
            {
                Technique                 = 'AtDGNModelOrigin';
                DGNModelName              = 'Design Model';
                SymbolSize                = 1.0;
                GraphLocation             = <auto> {40.0, 40.0};
            }
        }
    }
    
    transaction 2 stateChange 'Add point1, point2'
    {
        gcModel
        {
            node User.Objects.point1 Bentley.GC.NodeTypes.Point
            {
                Technique                 = 'ByCartesianCoordinates';
                CoordinateSystem          = baseCS;
                XTranslation              = <free> 36.4757390387357;
                YTranslation              = <free> 10611.8442629786;
                ZTranslation              = -100.0;
                GraphLocation             = <auto> {314.0, 40.0};
            }
            node User.Objects.point2 Bentley.GC.NodeTypes.Point
            {
                Technique                 = 'ByCartesianCoordinates';
                CoordinateSystem          = baseCS;
                XTranslation              = <free> 12550.5148308316;
                YTranslation              = <free> 1370.73356835185;
                ZTranslation              = 100.0;
                GraphLocation             = {316.667, 236.43};
            }
        }
    }
    
    transaction 3 stateChange 'Add range1'
    {
        gcModel
        {
            node User.Objects.range1 Bentley.GC.NodeTypes.Range
            {
                Technique                 = 'ByLowHighRangePoints';
                LowPoint                  = point1;
                HighPoint                 = point2;
                GraphLocation             = {673.667, 105.667};
            }
        }
    }
    
    transaction 4 stateChange 'Add PurpleLines, WhiteLines'
    {
        gcModel
        {
            node User.Objects.WhiteLines Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'FromElementsInRange';
                ElementRange              = range1;
                FilterByColors            = 0;
                RangeAction               = RangeOption.Inside;
                ScaleFactor               = 1.0;
                GraphLocation             = {941.667, 196.334, 0.0, 130.39};
            }
            node User.Objects.PurpleLines Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'FromElementsInRange';
                ElementRange              = range1;
                FilterByColors            = 5;
                RangeAction               = RangeOption.Inside;
                ScaleFactor               = 1.0;
                GraphLocation             = {935.0, 51.0};
            }
        }
    }
    
    transaction 5 stateChange 'Add OrderPurple, OrderWhite'
    {
        gcModel
        {
            node User.Objects.OrderWhite Bentley.GC.NodeTypes.Value
            {
                Technique                 = 'Default';
                Value                     = from ln in WhiteLines orderby ln.EndPoint.Y;
                GraphLocation             = {1201.067, 187.533, 0.0, 123.83};
            }
            node User.Objects.OrderPurple Bentley.GC.NodeTypes.Value
            {
                Technique                 = 'Default';
                Value                     = from ln in PurpleLines orderby ln.EndPoint.Y;
                GraphLocation             = {1189.667, 24.2, 0.0, 123.83};
            }
        }
    }
    
    transaction 6 stateChange 'Add EndLine, StartLine'
    {
        gcModel
        {
            node User.Objects.EndLine Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'ByPoints';
                StartPoint                = OrderPurple.EndPoint;
                EndPoint                  = OrderWhite.EndPoint;
                GraphLocation             = {1533.267, 156.333};
            }
            node User.Objects.StartLine Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'ByPoints';
                StartPoint                = OrderPurple.StartPoint;
                EndPoint                  = OrderWhite.StartPoint;
                GraphLocation             = {1508.467, -44.467, 0.0, 130.39};
            }
        }
    }
    
    transaction 7 stateChange 'Add MidPointEnd, MidPontStart'
    {
        gcModel
        {
            node User.Objects.MidPontStart Bentley.GC.NodeTypes.Point
            {
                Technique                 = 'ByParameterAlongCurve';
                Curve                     = StartLine;
                T                         = 0.5;
                GraphLocation             = {1813.267, -48.467, 0.0, 130.39};
            }
            node User.Objects.MidPointEnd Bentley.GC.NodeTypes.Point
            {
                Technique                 = 'ByParameterAlongCurve';
                Curve                     = EndLine;
                T                         = 0.5;
                GraphLocation             = {1861.067, 155.533, 0.0, 130.39};
            }
        }
    }
    
    transaction 8 stateChange 'Add MidLine1'
    {
        gcModel
        {
            node User.Objects.MidLine1 Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'ByPoints';
                StartPoint                = MidPontStart;
                EndPoint                  = MidPointEnd;
                GraphLocation             = {2176.467, 59.533};
            }
        }
    }
    
    transaction 9 stateChange 'Add point3, point4'
    {
        gcModel
        {
            node User.Objects.point3 Bentley.GC.NodeTypes.Point
            {
                Technique                 = 'ByCartesianCoordinates';
                CoordinateSystem          = baseCS;
                XTranslation              = <free> 26490.9111779995;
                YTranslation              = <free> 4534.4615465383;
                ZTranslation              = -10;
                GraphLocation             = {335.984, 525.219, 0.0, 156.43};
            }
            node User.Objects.point4 Bentley.GC.NodeTypes.Point
            {
                Technique                 = 'ByCartesianCoordinates';
                CoordinateSystem          = baseCS;
                XTranslation              = <free> 33101.6895856144;
                YTranslation              = <free> 2985.26064634051;
                ZTranslation              = 10;
                GraphLocation             = {335.984, 721.649};
            }
        }
    }
    
    transaction 10 stateChange 'Add range2'
    {
        gcModel
        {
            node User.Objects.range2 Bentley.GC.NodeTypes.Range
            {
                Technique                 = 'ByLowHighRangePoints';
                LowPoint                  = point3;
                HighPoint                 = point4;
                GraphLocation             = {809.392, 585.534};
            }
        }
    }
    
    transaction 11 stateChange 'Add AllLines'
    {
        gcModel
        {
            node User.Objects.AllLines Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'FromElementsInRange';
                ElementRange              = range2;
                FilterByColors            = 0;
                RangeAction               = RangeOption.Inside;
                ScaleFactor               = 1.0;
                ConstructionsVisible      = false;
                GraphLocation             = {1189.792, 679.578, 0.0, 130.39};
            }
        }
    }
    
    transaction 12 stateChange 'Add AllLines1'
    {
        gcModel
        {
            node User.Objects.AllLines1 Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'FromElementsInRange';
                ElementRange              = range2;
                FilterByColors            = 5;
                RangeAction               = RangeOption.Inside;
                ScaleFactor               = 1.0;
                ConstructionsVisible      = false;
                GraphLocation             = {1217.303, 462.326, 0.0, 130.39};
            }
        }
    }
    
    transaction 13 stateChange 'Add line1'
    {
        gcModel
        {
            node User.Objects.line1 Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'ByFunction';
                Function                  = function(Line InputLinesWhite, Line InputLinesPurple)
                                            
                                            {
                                            Line MidLines = {};
                                            int SelectedLine = null;
                                            //breakpoint;
                                            for (int i = 0; i < InputLinesPurple.Count; ++i)
                                            {
                                            
                                            for (int j = 0; j < InputLinesWhite.Count; ++j)
                                            {
                                            double MyDistance = 0;
                                            
                                            
                                            double ThisDistance = Distance(InputLinesPurple[i].EndPoint,InputLinesWhite[j].EndPoint);
                                            
                                            if (MyDistance == 0)
                                            {
                                            MyDistance = ThisDistance;
                                                    SelectedLine = j;
                                                    }
                                                            if (MyDistance > 0)
                                                            {
                                                                if (MyDistance < ThisDistance)
                                                                {
                                                                MyDistance = ThisDistance;
                                                                SelectedLine = j;
                                            
                                                                }
                                            
                                                            }
                                            
                                                    }
                                            
                                            
                                            
                                            Line EndpointLine = new Line().ByPoints(InputLinesWhite[SelectedLine].EndPoint,InputLinesPurple[i].EndPoint);
                                            Line StartpointLine = new Line().ByPoints(InputLinesWhite[SelectedLine].StartPoint,InputLinesPurple[i].StartPoint);
                                            Point MyEndMidPoint = new Point().ByParameterAlongCurve(EndpointLine,0.5);
                                            Point MyStartMidPoint = new Point().ByParameterAlongCurve(StartpointLine,0.5);
                                            Line MyMidPointLine = new Line().ByPoints(MyEndMidPoint,MyStartMidPoint);
                                            MidLines.Add(MyMidPointLine);
                                            }
                                            
                                            
                                            
                                            
                                            return MidLines;
                                            
                                            
                                            };
                DebuggerTrigger           = DebuggerTriggerLevel.Breakpoints;
                InputLinesWhite           = AllLines;
                InputLinesPurple          = AllLines1;
                GraphLocation             = {1626.852, 636.998, 0.0, 143.41};
            }
        }
    }
    
    transaction 14 stateChange 'Change point3'
    {
        gcModel
        {
            node User.Objects.point3 Bentley.GC.NodeTypes.Point
            {
                Technique                 = 'ByCartesianCoordinates';
                XTranslation              = <free> 26394.9560814764;
                YTranslation              = <free> 5101.82228125031;
                ZTranslation              = -10.0;
            }
        }
    }
    
    transaction 15 stateChange 'Change line1'
    {
        gcModel
        {
            node User.Objects.line1 Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'ByFunction';
                Function                  = function(Line InputLinesWhite, Line InputLinesPurple)
                                            
                                            {
                                            Line MidLines = {};
                                            int SelectedLine = null;
                                            //breakpoint;
                                            for (int i = 0; i < InputLinesPurple.Count; ++i)
                                            {
                                            double MyDistance = 0;
                                            for (int j = 0; j < InputLinesWhite.Count; ++j)
                                            {
                                            
                                            
                                            
                                            double ThisDistance = Distance(InputLinesPurple[i].EndPoint,InputLinesWhite[j].EndPoint);
                                            
                                            if (MyDistance == 0)
                                            {
                                            MyDistance = ThisDistance;
                                                    SelectedLine = j;
                                                    }
                                                            if (MyDistance > 0)
                                                            {
                                                                if (MyDistance < ThisDistance)
                                                                {
                                                                MyDistance = ThisDistance;
                                                                SelectedLine = j;
                                            
                                                                }
                                            
                                                            }
                                            
                                                    }
                                            
                                            
                                            
                                            Line EndpointLine = new Line().ByPoints(InputLinesWhite[SelectedLine].EndPoint,InputLinesPurple[i].EndPoint);
                                            Line StartpointLine = new Line().ByPoints(InputLinesWhite[SelectedLine].StartPoint,InputLinesPurple[i].StartPoint);
                                            Point MyEndMidPoint = new Point().ByParameterAlongCurve(EndpointLine,0.5);
                                            Point MyStartMidPoint = new Point().ByParameterAlongCurve(StartpointLine,0.5);
                                            Line MyMidPointLine = new Line().ByPoints(MyEndMidPoint,MyStartMidPoint);
                                            MidLines.Add(MyMidPointLine);
                                            }
                                            
                                            
                                            
                                            
                                            return MidLines;
                                            
                                            
                                            };
            }
        }
    }
    
    transaction 16 stateChange 'Change AllLines, line1'
    {
        gcModel
        {
            node User.Objects.AllLines Bentley.GC.NodeTypes.Line
            {
                Color                     = Colors.White;
            }
            node User.Objects.line1 Bentley.GC.NodeTypes.Line
            {
                Technique                 = 'ByFunction';
                Function                  = function(Line InputLinesWhite, Line InputLinesPurple)
                                            
                                            {
                                            Line MidLines = {};
                                            int SelectedLine = null;
                                            //breakpoint;
                                            for (int i = 0; i < InputLinesPurple.Count; ++i)
                                            {
                                            double MyDistance = 0;
                                            for (int j = 0; j < InputLinesWhite.Count; ++j)
                                            {
                                            
                                            
                                            
                                            double ThisDistance = Distance(InputLinesPurple[i].EndPoint,InputLinesWhite[j].EndPoint);
                                            
                                            if (MyDistance == 0)
                                            {
                                            MyDistance = ThisDistance;
                                                    SelectedLine = j;
                                                    }
                                                            if (MyDistance > 0)
                                                            {
                                                                if (MyDistance > ThisDistance)
                                                                {
                                                                MyDistance = ThisDistance;
                                                                SelectedLine = j;
                                            
                                                                }
                                            
                                                            }
                                            
                                                    }
                                            
                                            
                                            
                                            Line EndpointLine = new Line().ByPoints(InputLinesWhite[SelectedLine].EndPoint,InputLinesPurple[i].EndPoint);
                                            Line StartpointLine = new Line().ByPoints(InputLinesWhite[SelectedLine].StartPoint,InputLinesPurple[i].StartPoint);
                                            Point MyEndMidPoint = new Point().ByParameterAlongCurve(EndpointLine,0.5);
                                            Point MyStartMidPoint = new Point().ByParameterAlongCurve(StartpointLine,0.5);
                                            Line MyMidPointLine = new Line().ByPoints(MyEndMidPoint,MyStartMidPoint);
                                            MidLines.Add(MyMidPointLine);
                                            }
                                            
                                            
                                            
                                            
                                            return MidLines;
                                            
                                            
                                            };
                Color                     = Colors.Yellow;
                GraphLocation             = {1443.652, 576.998, 0.0, 143.41};
            }
        }
    }

  • Hello Wayne,

    The script works great! There are some caveats / situations that make the script unusable, a colleague and I have decided on a more ''manual work'' script that works better in more situations.

    I do thank you for sharing your knowledge and time!

Reply Children
No Data