@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);
}
}
}