Finding closest parallel lines in a drawing

Finding closest parallel lines in a drawing

Anonymous
Not applicable
4,693 Views
6 Replies
Message 1 of 7

Finding closest parallel lines in a drawing

Anonymous
Not applicable

Hi,

 

I'm trying to write some c# code that finds the closest parallel line to another line. So, if I had a drawing with 5 lines, and I select 1 line, I'd like to know which of the other 4 lines are parallel, and then (if there are any parallel lines) which is the closest. I think I can find out (yet to be tested) if 2 lines are parallel by checking their 'angle' variable. However, I'm unsure how I'm going to determine if two lines are close to eachother or far away.

 

Currently I'm trying to use their start and end points, however I haven't been able to find a solution. 

 

Any help would be greatly appreciated... Thank you in advance!

0 Likes
Accepted solutions (1)
4,694 Views
6 Replies
Replies (6)
Message 2 of 7

ActivistInvestor
Mentor
Mentor

@Anonymous wrote:

Hi,

 

I'm trying to write some c# code that finds the closest parallel line to another line. So, if I had a drawing with 5 lines, and I select 1 line, I'd like to know which of the other 4 lines are parallel, and then (if there are any parallel lines) which is the closest. I think I can find out (yet to be tested) if 2 lines are parallel by checking their 'angle' variable. However, I'm unsure how I'm going to determine if two lines are close to eachother or far away.

 

Currently I'm trying to use their start and end points, however I haven't been able to find a solution. 

 

Any help would be greatly appreciated... Thank you in advance!


An answer to your question depends on how you define 'closest'.

 

By 'closest', do you mean by a distance measured perpendicular to the parallel lines (e.g, as if all the lines were of infinite length), or by a distance from the point on one line that is closest to the nearest point on the other line?  

 

 

0 Likes
Message 3 of 7

Anonymous
Not applicable

Sorry, yes, I should have been a bit clearer.

 

Yes, if the lines were of an infinite length, how would you tell which lines were closest together, and travelling in the same direction. If you imagine a straight wall made up of two lines in a CAD drawing, how would you know those two lines were related. My thinking is that they are parallel, and they are 'close' to one another.

 

I hope this makes sense.

0 Likes
Message 4 of 7

_gile
Consultant
Consultant

Hi,

 

You can try something like this:

 

        /// <summary>
        /// Gets the closest parallel line to baseLine.
        /// </summary>
        /// <param name="baseLine">The line from wich search the closest parallel.</param>
        /// <param name="lines">The line collection where to find the closest parallel.</param>
        /// <param name="distance">The distance of the closest patrallel.</param>
        /// <returns>The closest parallel line or null if none.</returns>
        private Line GetClosestParallel (Line baseLine, IEnumerable<Line> lines, out double distance)
        {
            var basePoint = baseLine.StartPoint;
            var vector = baseLine.EndPoint - basePoint;
            Line result = null;
            distance = double.MaxValue;
            foreach (var line in lines)
            {
                if (line != baseLine && vector.IsParallelTo(line.EndPoint - line.StartPoint))
                {
                    double dist = line.GetClosestPointTo(basePoint, true).DistanceTo(basePoint);
                    if (dist < distance)
                    {
                        distance = dist;
                        result = line;
                    }
                }
            }
            return result;
        }

 

Testing command

 

        [CommandMethod("GCP")]
        public void GetClosestParallelCommand()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var peo = new PromptEntityOptions("\nSelect a line: ");
            peo.SetRejectMessage("\nSelected object is not a line.");
            peo.AddAllowedClass(typeof(Line), true);
            var per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK)
                return;

            var psr = ed.GetSelection(new SelectionFilter(new[] { new TypedValue(0, "LINE") }));
            if (psr.Status != PromptStatus.OK)
                return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                var line = (Line)tr.GetObject(per.ObjectId, OpenMode.ForRead);
                var lines = psr.Value
                    .Cast<SelectedObject>()
                    .Select(so => (Line)tr.GetObject(so.ObjectId, OpenMode.ForRead));
                var closestParallel = GetClosestParallel(line, lines, out double distance);
                if (closestParallel == null)
                {
                    ed.WriteMessage($"\nNo parallel line found.");
                }
                else
                {
                    ed.WriteMessage($"\nClosest parallel line found at: {distance} units.");
                    ed.SetImpliedSelection(new[] { closestParallel.ObjectId });
                }
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 7

ActivistInvestor
Mentor
Mentor

@Anonymous wrote:

Sorry, yes, I should have been a bit clearer.

 

Yes, if the lines were of an infinite length, how would you tell which lines were closest together, and travelling in the same direction. If you imagine a straight wall made up of two lines in a CAD drawing, how would you know those two lines were related. My thinking is that they are parallel, and they are 'close' to one another.

 

I hope this makes sense.


If this is the old 'find the line that represents the opposite side of a wall on a floor plan' problem, then a generic algorithm that finds the nearest parallel line (like what @_gile posted) will not solve that problem. The reason is because the problem (finding the line representing the opposite side of a double-line wall), is slightly more complicated. It must also reject parallel lines that are colinear, and parallel lines that are non-adjacent (two parallel lines are adjacent if a perpendicular line extending from either end of one parallel line intersects the other parallel line). In more realistic terms, on a floor plan where walls are represented by double-lines, there can be a parallel line that is closer to the line representing one side of a wall, than the line representing the other side of that wall. Usually, they are lines representing other intersecting walls. Consider an 8" wall that intersects a 4" wall. Draw that, look at it, and find the parallel line that is closest to one of the lines representing one side of the 8" wall. It will not be the parallel line representing the other side of that same wall, it will be the parallel (and colinear) line representing a side of the wall on the opposite side of the intersection.

 

Well, you can modify @_gile's code to test for and reject colinear and non-adjacent lines, and that should work.

 

 

0 Likes
Message 6 of 7

ActivistInvestor
Mentor
Mentor
Accepted solution

@Activist_Investor wrote:

@Anonymous wrote:

Sorry, yes, I should have been a bit clearer.

 

Yes, if the lines were of an infinite length, how would you tell which lines were closest together, and travelling in the same direction. If you imagine a straight wall made up of two lines in a CAD drawing, how would you know those two lines were related. My thinking is that they are parallel, and they are 'close' to one another.

 

I hope this makes sense.


 

Well, you can modify @_gile's code to test for and reject colinear and non-adjacent lines, and that should work.

 

 


I think the code below should do what you ask (find the line representing the opposite side of a wall, given the line representing one side).

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using AcRx = Autodesk.AutoCAD.Runtime;

namespace FindNearestExamples
{
   public static class NearestLineCommands
   {
      [CommandMethod("NEAREST_PARALLEL_LINE", CommandFlags.Redraw)]
      public static void NearestParallelLineExample()
      {
         Document doc = Application.DocumentManager.MdiActiveDocument;
         Database db = doc.Database;
         Editor ed = doc.Editor;
         var peo = new PromptEntityOptions("\nSelect query line: ");
         peo.SetRejectMessage("\nRequires a line,");
         peo.AddAllowedClass(typeof(Line), false);
         var per = ed.GetEntity(peo);
         if(per.Status != PromptStatus.OK)
            return;
         using(var trans = new OpenCloseTransaction())
         {
            var lineId = per.ObjectId;
            var block = (BlockTableRecord) trans.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
            var selected = (Line) trans.GetObject(per.ObjectId, OpenMode.ForRead);
            var items = block.Cast<ObjectId>()
                  .Where(id => id.ObjectClass.IsDerivedFrom(lineClass) && id != lineId)
                  .Select(id => (Line) trans.GetObject(id, OpenMode.ForRead))
                  .Select(line => new {Line = line, Offset = GetOffset(selected, line)})
                  .Where(item => item.Offset > 0.0);

            if(items.Any())
            {
               var result = items.Aggregate((a, b) => a.Offset < b.Offset ? a : b);
               ed.SetImpliedSelection(new[] { result.Line.ObjectId });
               ed.WriteMessage("\nDistance to nearest line: {0}",
                  Converter.DistanceToString(Math.Sqrt(result.Offset)));
            }
            else
               ed.WriteMessage("\nNo lines matching query criteria were found.");
            trans.Commit();
         }
      }

      static RXClass lineClass = RXObject.GetClass(typeof(Line));

      /// <summary>
      /// Computes the offset distance between two lines 
      /// provided they meet all of the following criteria:
      ///
      ///    The lines are parallel
      ///    The lines are not colinear
      ///    The lines are adjacent
      ///    Neither endpoint of one line is
      ///    coincident with either endpoint
      ///    of the other line.
      ///    
      /// If all criteria are satisfied the method returns
      /// the sum of the squares of the x & y components 
      /// of the vector between the lines (slightly faster 
      /// than computing the distance, and has the same 
      /// result for relative comparisons).
      /// 
      /// If the lines don't meet the criteria, the method
      /// returns a negative value.
      /// </summary>
      
      public static double GetOffset(Line a, Line b)
      {
         Point2d a1 = AsPoint2d(a.StartPoint);
         Point2d a2 = AsPoint2d(a.EndPoint);
         Point2d b1 = AsPoint2d(b.StartPoint);
         Point2d b2 = AsPoint2d(b.EndPoint);

         double result = -1.0;

         // reject lines with coincident endpoints
         if(a1.IsEqualTo(b1) || a1.IsEqualTo(b2) || a2.IsEqualTo(b1) || a2.IsEqualTo(b2))
            return result;

         var line1 = new LineSegment2d(a1, a2);
         var line2 = new LineSegment2d(b1, b2);

         // reject non-parallel lines
         if(!line1.IsParallelTo(line2))
            return result;

         // reject colinear lines
         if(line1.IsColinearTo(line2))
            return result;

         var cp = line1.GetClosestPointTo(line2);
         Point2d cp1 = cp[0].Point;
         Point2d cp2 = cp[1].Point;

         Vector2d vx = cp1.GetVectorTo(cp2);

         // reject non-adjacent lines:
         if(vx.IsPerpendicularTo(line1.Direction))
            result = vx.LengthSqrd;

         return result;
      }

      public static Point2d AsPoint2d(this Point3d p)
      {
         return new Point2d(p.X, p.Y);
      }
   }

}

 

Message 7 of 7

mecoman6GF27
Advocate
Advocate

Hello everyone and sorry if I re-open this thread after some time.
Also I would like to locate the parallel line of a wall but in this post we use C#. I would like to do the same thing but use the VB.net.
Can someone help me? I would be very grateful.
Thanks a lot, bye.

0 Likes