Author Topic: .NET GEOMETRY Routines  (Read 11877 times)

0 Members and 1 Guest are viewing this topic.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 10707
  • class keyThumper<T>:ILazy<T>
.NET GEOMETRY Routines
« on: January 27, 2010, 03:34:28 am »
LIBRARY THREAD for  AutoCAD GEOMETRY
 Members are encouraged to post any functions, methods, snips regarding
AutoCAD GEOMETRY in .NET : C# ,  VB , F# , Python , etc

Feel free to include comments, descriptive notes, limitations,  and images to document your post.

Please post questions in a regular thread.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate<--

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #1 on: January 27, 2010, 05:28:26 pm »
Hi,

Some geometry extensions methods for Point2d, Point3d, CircularArc2d, Polyline and Polyline2d classes and two little (maybe usefull) classes: Triangle2d, Triangle3d.

All these classes work together and have to be compiled in a single DLL.

The extension methods requires to reference System.Core (.NET Framework 3.5)

EDIT: extended

The GeomExt class, contains the following extension methods:

Matrix3d Editor.UCS2WCS()
Matrix3d Editor.WCS2UCS()
Matrix3d Editor.DCS2WCS()
Matrix3d Editor.WCS2DCS()
Matrix3d Editor.DCS2PSDCS()
Matrix3d Editor.PSDCS2DCS()

Matrix3d Viewport.DCS2WCS()
Matrix3d Viewport.WCS2DCS()
Matrix3d Viewport.PSDCS2DCS()
Matrix3d Viewport.DCS2PSDCS()

Point3d Point2d.Convert3d()
Point3d Point2d.Convert3d(Plane plane)
Point3d Point2d.Convert3d(Vector3d normal, double elevation)
Point2d Point2d.Flatten(Vector3d normal)
bool IsBetween(Point2d p1, Point2d p2)
bool IsBetween(Point2d p1, Point2d p2, Tolerance tol)
Point2d Point2d.Polar(double angle, double distance)

Point3d Point3d.Convert2d()
Point3d Point3d.Flatten()
bool IsBetween(Point3d p1, Point3d p2)
bool IsBetween(Point3d p1, Point3d p2, Tolerance tol)
Point3d Point3d.Polar(double angle, double distance)
Point3d Point3d.Trans(int from, int to)
Point3d Point3d.Trans(Editor ed, int from, int to)
Point3d Point3d.Trans(CoordSystem from, CoordSystem to)
Point3d Point3d.Trans(Editor ed, CoordSystem from, CoordSystem to)

Vector3d Vector3d .Flatten()

void Point2dCollection.RemoveDuplicate()
void Point2dCollection.RemoveDuplicate(Tolerance tol)
bool Point2dCollection.Contains(Point2d pt, Tolerance tol)

void Point3dCollection.RemoveDuplicate()
void Point3dCollection.RemoveDuplicate(Tolerance tol)
bool Point3dCollection.Contains(Point3d pt, Tolerance tol)

double CircularArc2d.AlgebricArea()
Point2d CircularArc2d.Centroid()

Point2d Polyline.Centroid2d()
Point3d Polyline.Centroid()
Polyline Polyline.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline.GetOrthoProjectedPolyline(Plane plane)

Point3d Polyline2d.Centroid()
CircularArc3d Polyline2d.GetArcSegmentAt(int index)
CircularArc2d Polyline2d.GetArcSegment2dAt(int index)
LineSegment3d Polyline2d.GetLineSegmentAt(int index)
LineSegment2d Polyline2d.GetLineSegment2dAt(int index)
Polyline Polyline2d.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline2d.GetOrthoProjectedPolyline(Plane plane)
List<Vertex2d> Polyline2d.GetVertices()

Polyline Polyline3d.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline3d.GetOrthoProjectedPolyline(Plane plane)

Point3d Region.Centroid()

Point3d Spline.Centroid()

Polyline Ellipse.ToPolyline()


Triangle<T> abstract class

Constructors
Triangle()
Triangle(T[] pts)
Triangle(T a, T b, T c)

Indexor
T Item

Methods
T Inverse()
void Set(T[] pts)
void Set(T a, T b, T c)
T[] ToArray()


Triangle2d : Triangle<Point2d> class

Constructors
Triangle2d() : base()
Triangle2d(Point2d[] pts) : base(pts)
Triangle2d(Point2d a, Point2d b, Point2d c) : base(a, b, c)
Triangle2d(Point2d org, Vector2d v1, Vector2d v2)

Properties
double AlgebricArea
Point2d Centroid
CircularArc2d CircumscribedCircle
CircularArc2d InscribedCircle
bool IsClockwise

Methods
Triangle3d Convert3d(Plane plane)
Triangle3d Convert3d(Vector3d normal, double elevation)
double GetAngleAt(int index)
LineSegment2d GetSegmentAt(int index)
List<Point2d> IntersectWith(LinearEntity2d le2d)
List<Point2d> IntersectWith(LinearEntity2d le2d, Tolerance tol)
bool IsEqualTo(Triangle2d t2d)
bool IsEqualTo(Triangle2d t2d, Tolerance tol)
bool IsPointInside(Point2d pt)
bool IsPointOn(Point2d pt)
void Set(Point2d org, Vector2d v1, Vector2d v2)
Triangle2d TransformBy(Matrix2d mat)


Triangle3d : Triangle<Point3d> class

Constructors
Triangle3d() : base()
Triangle3d(Point3d[] pts) : base(pts)
Triangle3d(Point3d a, Point3d b, Point3d c) : base(a, b, c)
Triangle3d(Point3d org, Vector3d v1, Vector3d v2)

Properties
double Area
Point3d Centroid
CircularArc3d CircumscribedCircle
double Elevation
Vector3d GreatestSlope
Vector3d Horizontal
CircularArc3d InscribedCircle
bool IsHorizontal
Vector3d Normal
double SlopePerCent
Matrix3d SlopeUCS

Methods
Triangle2d Convert2d()
Triangle2d Flatten()
double GetAngleAt(int index)
BoundedPlane GetBoundedPlane()
Plane GetPlane()
LineSegment3d GetSegmentAt(int index)
bool IsEqualTo(Triangle3d t3d)
bool IsEqualTo(Triangle3d t3d, Tolerance tol)
bool IsPointInside(Point3d pt)
bool IsPointOn(Point3d pt)
void Set(Point3d org, Vector3d v1, Vector3d v2)
Triangle3d Transformby(Matrix3d mat)


PolylineSegment class

Constructors

PolylineSegment(Point2d startPoint, Point2d endPoint)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double constantWidth)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double startWidth, double endWidth)
PolylineSegment(Line2dSegment line)
PolylineSegment(CircularArc2d arc)

Properties

double Bulge
Point2d EndPoint
double EndWidth
bool IsLinear
Point2d StartPoint
double StartWidth

Methods

bool Equals(object obj)
PolylineSegment Clone()
int GetHashCode()
double GetParameterOf(Point3d pt)
void Inverse()
CircularArc2d ToCircularArc()
Curve2d ToCurve2d()
LineSegment2d ToLineSegment()
string ToString()


PolylineSegmentCollection : IList<PolylineSegment> class

Constructors

PolylineSegmentCollection()
PolylineSegmentCollection(Circle circle)
PolylineSegmentCollection(Ellipse ellipse)
PolylineSegmentCollection(Polyline pline)
PolylineSegmentCollection(Polyline2d pline)
PolylineSegmentCollection(IEnumerable<PolylineSegment> segments)

Methods

void Add(PolylineSegment segment)
void AddRange(IEnumerable<PolylineSegment> range)
void Clear()
bool Contains(PolylineSegment segment)
int FinIindex(Predicate<PolylineSegment> match)
int GetClosestSegmentTo(Point2d pt)
IEnumerator<PolylineSegment> GetEnumerator()
int IndexOf(PolylineSegment item)
void Insert(int index, PolylineSegment item)
void InsertRange(int index, IEnumerable<PolylineSegment> collection)
List<PolylineSegmentCollection> Join()
List<PolylineSegmentCollection> Join(Tolerance tol)
bool Remove(PolylineSegment item)
void RemoveAt(int index)
public void RemoveRange(int index, int count)
Polyline ToPolyline()

For more information, see the attached documentation.

GeomExtDoc.zip contains a .chm documentation file.
GeometryExtensions(1.6).zip contains the C# source code files and the DLLs (GeometryExtensions_18.dll for A2010-2012 and GeometryExtensions_19 for A2013+)

<EDIT: version 1.6> added CircularArc2d and CircularArc3d GetTangentsTo methods, reorganized: one class per extended type.
« Last Edit: September 15, 2013, 05:30:34 pm by gile »
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #2 on: February 11, 2010, 04:31:52 pm »
Added some extension methods for Polyline2d.
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #3 on: February 16, 2010, 06:03:22 pm »
I added some more extensions and rewrite the Triangle2d and Triangle3d classes
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #4 on: April 17, 2010, 08:56:17 am »
Hi,

I added some properties and methods to the Triangle2d and Triangle3d classes that I needed to deal with 3dfaces (ground modeling).

Triangle2d class:
- Inverse() method returns the triangle in inverse order (Triangle2d)

Triangle3d class :
- GreatestSlope property returns the single unit vector of the triangle plane greatest slope (Vector3d)
- Horizontal property returns the single unit vector of the triangle plane horizontal (Vector3d)
- IsHorizontal property returns true if the triangle plane is parallel to WCS XY plane (Boolean)
- SlopePerCent property returns the percent expression of the greatest slope (Double)
- SlopeUCS property returns a coordinates system matrix which origin is the triangle centroid, X axis is horizontal vector, Y axis the negated greatest slope vector (Matrix3d)
- Flatten() method returns the flatten triangle (Triangle2d)
- Inverse() method returns the triangle in inverse order (Triangle3d)


Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #5 on: August 22, 2010, 02:18:56 pm »
Hi,

Some more adds:

Point3d and Point2d extension methods:
- IsBetween returns true if the first point (first parameter) is strictly between the two others (with or without Tolerance).

Triangle2d methods:
- GetSegmentAt: returns the LinearSegment2d at specified index.
- IntersecWith: returns a List<Point2d> of the intersection points between the triangle and a LinearEntity2d (with or without Tolerance).
- IsPointInside: returns true if the point is strictly inside the triangle.
- IsPointOn: returns true if the point lies on an edge.

Triangle3d methods:
- GetBoundedPlane: returns a BoundedPlane object.
- IsPointInside: returns true if the point is strictly inside the triangle.
- IsPointOn: returns true if the point lies on an edge.
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #6 on: August 23, 2010, 03:49:33 am »
 :oops:

There was a mistake in the Triangle2d.IsPointInside() method.
Attached file in the first post is updated.
Speaking English as a French Frog

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 10707
  • class keyThumper<T>:ILazy<T>
Re: .NET GEOMETRY Routines
« Reply #7 on: August 23, 2010, 04:45:37 am »

Thanks gile, that should be a handy library.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

--> Donate<--

fixo

  • Swamp Rat
  • Posts: 856
  • My location is not in the Hitleropa
Re: .NET GEOMETRY Routines
« Reply #8 on: August 23, 2010, 05:23:12 am »
:oops:

There was a mistake in the Triangle2d.IsPointInside() method.
Attached file in the first post is updated.

Thanks Gilles, I've used it once, very useful
I'm pretty sure you working on Rectangle 2d/3d as well :)

Oleg
\\\"Always drink upstream from the herd."\\\ - Will Rogers, was died in 1935 plane crash

--> Donate to TheSwamp <--

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #9 on: August 23, 2010, 05:48:04 am »
Thanks both, you're welcome.

Quote
I'm pretty sure you working on Rectangle 2d/3d as well
I'm not so sure, IMO, in geometry (almost 3d geometry) rectangles are'nt as useful as triangles which are not deformable, define planes and so on...
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #10 on: February 03, 2011, 05:03:03 am »
Hi,

Added some extension methods:

void Point2dCollection.RemoveDuplicate()
void Point2dCollection.RemoveDuplicate(Tolerance tol)
bool Point2dCollection.Contains(Point2d pt, Tolerance tol)

void Point3dCollection.RemoveDuplicate()
void Point3dCollection.RemoveDuplicate(Tolerance tol)
bool Point3dCollection.Contains(Point3d pt, Tolerance tol)

And edit the Triangle2d and Triangle3d classes:
both inherits from a 'generic' abstract class: Triangle<T> and have two new properties : CircumscribedCircle and InscribedCircle
« Last Edit: February 03, 2011, 05:11:58 am by gile »
Speaking English as a French Frog

jgr = &jgr

  • Newt
  • Posts: 194
Re: .NET GEOMETRY Routines
« Reply #11 on: March 03, 2011, 10:37:26 am »
« Last Edit: March 03, 2011, 12:47:02 pm by jgr »

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #12 on: April 14, 2011, 05:16:55 pm »
Hi

Here's a F# convex hull (Graham's scan)

EDIT: new code see here

EDIT: a tolerance in comparisons was needed in some cases with colinear points

Code: [Select]
module ConvexHull

open System
open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime

type AcAp = Autodesk.AutoCAD.ApplicationServices.Application

let clockwise (p1:Point2d) (p2:Point2d) (p3:Point2d) =
    (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X) < 1e-8
   
let convexHull (pts : Point2d seq) =
    let rec fill acc pt =
        match acc with
        | a :: b :: _ when clockwise b a pt -> fill acc.Tail pt
        | _ -> pt :: acc
    let p0 = pts
             |> Seq.reduce (fun p1 p2 ->
                if p2.Y < p1.Y || (p1.Y = p2.Y && p2.X < p1.X) then p2 else p1)
    pts
    |> List.ofSeq
    |> List.sortBy (fun p ->
        let d = p0.GetDistanceTo(p)
        (Math.Round((p0.X - p.X) / d, 8), d))
    |> List.fold fill []
    |> List.rev

[<CommandMethod("ch")>]
let Test() =
    let doc = AcAp.DocumentManager.MdiActiveDocument
    let db = doc.Database
    let ed = doc.Editor
    let psr = ed.GetSelection(new SelectionFilter([| new TypedValue(0, "POINT") |]))
    if psr.Status = PromptStatus.OK then
        use tr = db.TransactionManager.StartTransaction()
        use pl = new Polyline()
        psr.Value
        |> Seq.cast<_>
        |> Seq.map (fun (so : SelectedObject) ->
            let pt = tr.GetObject(so.ObjectId, OpenMode.ForRead) :?> DBPoint
            new Point2d(pt.Position.X, pt.Position.Y))
        |> convexHull
        |> List.fold(fun i p ->  pl.AddVertexAt(i, p, 0.0, 0.0, 0.0); i + 1) 0
        |> ignore
        pl.Closed <- true
        pl.SetDatabaseDefaults()
        let btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) :?> BlockTableRecord
        btr.AppendEntity(pl) |> ignore
        tr.AddNewlyCreatedDBObject(pl, true)
        tr.Commit()
« Last Edit: April 25, 2011, 04:09:17 pm by gile »
Speaking English as a French Frog

gile

  • Water Moccasin
  • Posts: 1728
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #13 on: April 15, 2011, 06:09:33 am »
And the new C# implementation:

EDIT: I repalced the lambda function with a delegate (ComparePoints) so that it can be used with NET Framework 2.0 (default for A2007 -> A2009)

Code: [Select]
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace ConvexHull
{
    public class Commands
    {
        private Point2d _p0;

        private bool Clockwise(Point2d p1, Point2d p2, Point2d p3)
        {
            return ((p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X)) < 1e-8;
        }

        private int ComparePoints(Point2d p1, Point2d p2)
        {
            if (p1.IsEqualTo(p2)) return 0;
            double d1 = _p0.GetDistanceTo(p1);
            double d2 = _p0.GetDistanceTo(p2);
            if (d1 == 0.0) return -1;
            if (d2 == 0.0) return 1;
            double cos = (p2.X - _p0.X) / d2 - (p1.X - _p0.X) / d1;
            if (cos < -1e-8) return -1;
            if (cos > 1e-8) return 1;
            return d1.CompareTo(d2);
        }

        private List<Point2d> ConvexHull(List<Point2d> pts)
        {
            _p0 = pts[0];
            for (int i = 1; i < pts.Count; i++)
            {
                Point2d pt = pts[i];
                if (pt.Y < _p0.Y || (pt.Y == _p0.Y && pt.X < _p0.X))
                    _p0 = pt;
            }
            pts.Sort(ComparePoints);
            for (int i = 1; i < pts.Count - 1; i++)
            {
                while (i > 0 && Clockwise(pts[i - 1], pts[i], pts[i + 1]))
                {
                    pts.RemoveAt(i);
                    i--;
                }
            }
            return pts;
        }

        [CommandMethod("ch")]
        public void testCh()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            TypedValue[] filter = new TypedValue[1] { new TypedValue(0, "POINT") };
            PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
            if (psr.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (Polyline pline = new Polyline())
            {
                List<Point2d> pts = new List<Point2d>();
                foreach (SelectedObject so in psr.Value)
                {
                    DBPoint dbPt = (DBPoint)tr.GetObject(so.ObjectId, OpenMode.ForRead);
                    pts.Add(new Point2d(dbPt.Position.X, dbPt.Position.Y));
                }
                for (int i = 0; i < ConvexHull(pts).Count; i++)
                {
                    pline.AddVertexAt(i, pts[i], 0.0, 0.0, 0.0);
                }
                pline.Closed = true;
                pline.SetDatabaseDefaults();
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                btr.AppendEntity(pline);
                tr.AddNewlyCreatedDBObject(pline, true);
                tr.Commit();
            }
        }
    }
}
« Last Edit: April 18, 2011, 05:58:06 am by gile »
Speaking English as a French Frog

fixo

  • Swamp Rat
  • Posts: 856
  • My location is not in the Hitleropa
Re: .NET GEOMETRY Routines
« Reply #14 on: April 18, 2011, 04:18:27 pm »
Nice as always, thanks :)
Regards,

Oleg
\\\"Always drink upstream from the herd."\\\ - Will Rogers, was died in 1935 plane crash

--> Donate to TheSwamp <--