Author Topic: Geometry extensions  (Read 3320 times)

0 Members and 1 Guest are viewing this topic.

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Geometry extensions
« on: November 19, 2010, 04:01:42 PM »
Hi,

I already posted this at TheSwamp.
It will be my contribution to give a start to this new website.

These are some geometry extensions methods for Point2d, Point3d, CircularArc2d, Polyline and Polyline2d classes and two little classes: Triangle2d, Triangle3d.
I hope someones find them usefull and expect it shows a little basic OOP concepts as the creation of new types and the extension of already existing ones.

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) and are available for these objects as native methods while GeometryExtensions.dll is referenced:
Code: [Select]
using GeometryExtensions;

Point3d p1 = new Point3d(10.0, 20.0, 0.0);
Point3d p2 = p1.Polar(Math.PI / 4.0, 10.0);
p2 coordinates are: (17.0710678118655,27.0710678118655,0)

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(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)
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 updated documentation.

GeometryExtensions(1.5).zip contains the C# source code files and the GeometryExtensions_18.dll (AutoCAD 2010-2012) and GeometryExtensions_19.dll (AutoCAD 2013)

<EDIT: version 1.5>


target audience:{intermediate}
« Last Edit: January 21, 2013, 08:12:34 PM by (gile) »

Offline Patriiick

  • Administrator
  • *****
  • Posts: 130
  • Karma: +1/-0
  • Gender: Male
    • prefered language: VB
    • Prog expertise: Good
    • View Profile
  • Twitter: @Patriiick
Re: Geometry extensions
« Reply #1 on: November 20, 2010, 04:01:08 PM »
Thanks (gile) for that, it's certainly the main purpose of this site to "not reinvent the wheel", and to find good libraries like yours.

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Geometry extensions
« Reply #2 on: February 03, 2011, 11:11:16 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

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Geometry extensions
« Reply #3 on: July 10, 2011, 03:55:06 PM »
Hi,

Here's a 'msdn like' documentation for the GeometryExtension namespace.
I builded it with Sandcastle Help File Builder from the comments within the code.

[attach=1]

Doc.zip contains the GeomExtDoc.chm.

I Updated the attachement in the first post.
« Last Edit: October 16, 2011, 04:07:48 PM by (gile) »

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Geometry extensions
« Reply #4 on: September 11, 2011, 01:48:59 PM »
Hi,

I expanded a little the GeometryExtensions library.
There're two more classes: PolylineSegment and PolylineSegmentCollection (which inherits from List<PolylineSegment>) and a new extension method: Ellipse.ToPolyline().
I hope these classes make easier some work with polylines or to create polylines from other entities.

Here's a quick and dirty example (will give unexpected result with entities which don't lies on the WCS XY plane).
The MJOIN command joins the selected entities: line, arc, polyline, ellipse and spline (A2010 or later for spline) into one or more polyline(s).



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

namespace GeometryExtensionsTestCommands
{
    public class MjoinCommand
    {
        [CommandMethod("mjoin")]
        public void PolyJoin()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            TypedValue[] filter = {   
                new TypedValue(-4,"<OR"),
                new TypedValue(0, "ARC,ELLIPSE,LINE,LWPOLYLINE"),
                new TypedValue(-4, "<AND"),
                new TypedValue(0, "SPLINE"),
                new TypedValue(-4, "&"),
                new TypedValue(70, 8),
                new TypedValue(-4, "AND>"),
                new TypedValue(-4, "OR>")};
            PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
            if (psr.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord btr =
                    (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                PolylineSegmentCollection psc = new PolylineSegmentCollection();
                Plane plane = new Plane(Point3d.Origin, Vector3d.ZAxis);
                foreach (ObjectId id in psr.Value.GetObjectIds())
                {
                    Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead);
                    switch (ent.GetType().Name)
                    {
                        case "Arc":
                            Arc arc = (Arc)ent;
                            psc.Add(new PolylineSegment(
                                new CircularArc2d(
                                    arc.Center.Convert2d(plane),
                                    arc.Radius,
                                    arc.StartAngle,
                                    arc.EndAngle,
                                    Vector2d.XAxis,
                                    false)));
                            break;
                        case "Ellipse":
                            Ellipse el = (Ellipse)ent;
                            psc.AddRange(new PolylineSegmentCollection(el));
                            break;
                        case "Line":
                            Line l = (Line)ent;
                            psc.Add(new PolylineSegment(
                                new LineSegment2d(
                                    l.StartPoint.Convert2d(plane),
                                    l.EndPoint.Convert2d(plane))));
                            break;
                        case "Polyline":
                            Polyline pl = (Polyline)ent;
                            psc.AddRange(new PolylineSegmentCollection(pl));
                            break;
                        case "Spline":
                            try
                            {
                                Spline spl = (Spline)ent;
                                psc.AddRange(new PolylineSegmentCollection((Polyline)spl.ToPolyline()));
                            }
                            catch { }
                            break;
                        default:
                            break;
                    }
                }
                foreach (PolylineSegmentCollection segs in psc.Join())
                {
                    Polyline pline = segs.ToPolyline();
                    btr.AppendEntity(pline);
                    tr.AddNewlyCreatedDBObject(pline, true);
                }
                tr.Commit();
            }
        }
    }
}

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Geometry extensions
« Reply #5 on: October 16, 2011, 04:12:18 PM »
Hi,

The GeometryExtension librairy keeps on growing.

The main new things are Polyline, Polyline2d and Polyline3d extensions methods : GetProjectedPolyline and GetOrthoProjectedPolyline.

These methods create a new Polyline object and may replace the GetProjectedCurve and GetOrthoProjectedCurve methods which do not give expected results with Polyline and Polyline2d entities.
The elliptical arcs resulting of the polyline arcs projection are approximated using the PolylineSegmentCollection(Ellipse ellipse) constructor. This constructor uses the same geometric method as the 'old' AutoCAD native approximation of ellipses (i.e. PELLIPSE = 1).

Attachment in the first post and documentation have been updated.
« Last Edit: October 16, 2011, 05:18:47 PM by (gile) »

Offline frits432

  • Newbie
  • *
  • Posts: 15
  • Karma: +1/-0
  • Gender: Male
    • prefered language: C
    • Prog expertise: Beginner
    • View Profile
Geometry extensions/Moments of Inerita
« Reply #6 on: November 01, 2011, 04:06:50 PM »
Hi Gile,
If anyone can help you're the one.
I few years ago i wrote a VBA program for AutoCAD doing Geometric calculations on Boundaries -- Polylines including Polylines.
Part of the program involved the creation of the closed polylines, which you have elegantly solved in c#.
Another Part is the calculation of the Moments of Inertia and the the Centroids also solved in the Geometry Extensions class.
I've tried to include the Moments of Inertia calculation but because of too little experience in c# not succeeded yet.

The problem is that to my knowledge the Moments of Inertia can exactly be determined for (rotated) arc shaped contours using a Cone(Segment+Triangle), not a Segment. (see GeoCalcArc)

I like the way you calculate the area dividing everything in triangles and Arc Segment, it's far more elegant than my way of dividing everything in cones and trapezoid.

Have you any experience with the Inertia calculations, and if so can you help me out here.

Thanks,
Frits

Frits

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Geometry extensions
« Reply #7 on: November 03, 2011, 07:28:23 AM »
Hi frits432,

You're welcome.
I'm glad you like it.
Unfortunately, I do not have any experience in inertia calculation.
Maybe the use of a region or solid MassProperties is the easier route.

Offline frits432

  • Newbie
  • *
  • Posts: 15
  • Karma: +1/-0
  • Gender: Male
    • prefered language: C
    • Prog expertise: Beginner
    • View Profile
Re: Geometry extensions
« Reply #8 on: November 03, 2011, 09:18:45 AM »
Hi Gile,
Thanks for the response.
This is the region implementation and it works well for relatively simple profiles like profile2.

...
                var plines = new List<Polyline>();
                foreach (PolylineSegmentCollection segs in psc.Join())
                {
                    Polyline pline = segs.ToPolyline();
                    plines.Add(pline);
                }
                ed.WriteMessage("\n{0} boundaries", plines.Count);
                plines.OrderByDescending(p => p.Area);
                Polyline plineContour = plines.First();
                    DBObjectCollection outerCurves = new DBObjectCollection { plineContour };
                    DBObjectCollection outerRegion = Region.CreateFromCurves(outerCurves);
                    Solid3d solidPart = new Solid3d();
                    solidPart.Extrude((Region)outerRegion[0], 1.0, 0.0);
                plines.Remove(plineContour);

               foreach (Polyline plineHoles in plines)
                {
                    DBObjectCollection holeCurves = new DBObjectCollection { plineHoles };
                    DBObjectCollection holeRegions = Region.CreateFromCurves(holeCurves);
                    Solid3d solidHole = new Solid3d();
                    solidHole.Extrude((Region)holeRegions[0], 1.0, 0.0);
                    solidPart.BooleanOperation(BooleanOperationType.BoolSubtract, solidHole);
                }
                Point3d centroid = solidPart.MassProperties.Centroid;
                ed.WriteMessage("\nCentroid={0}", centroid);
                Vector3d moI = solidPart.MassProperties.MomentsOfIntertia;
                ed.WriteMessage("\nMomentsOfIntertia={0}", moI);
...

But for  the more advanced contours like profile3 the conversion to regions often fails. That's why i implemented that VBA solution a few years ago.

Currently i try  to implement any of the following solutions:
1. conversion of the VBA  program Circle Cone + trapezoid calculations;
2. circle segments + triangles calculations following you're code in PlineAlgebraicArea(...);
3. circle segments + "cross section defined as polygon" 
     from http://en.wikipedia.org/wiki/Second_moment_of_area

The second one is my favorite because of the simplicity(== elegance) of your code, however the implementation of the Inertia calculation for rotated non symmetrical triangles is a bit  tricky. It requires additional Ixy calculations.

Again thanks.
Frits

Frits

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Geometry extensions
« Reply #9 on: November 14, 2011, 09:17:21 PM »
New version of GeometryExtensions (1.3).
Download updated in the first message.
Corrected some bugs with the GetProjectedPolyline and GetOrthoProjectedPolyline methods.

Offline frits432

  • Newbie
  • *
  • Posts: 15
  • Karma: +1/-0
  • Gender: Male
    • prefered language: C
    • Prog expertise: Beginner
    • View Profile
Re: Geometry extensions
« Reply #10 on: November 15, 2011, 10:13:09 AM »
Hi Gile,
Thank you for posting this new version. Currently i am working on the Paperspace to Modelspace transformation and testing code for these calculations. But i can't get it right.
This is the scenario:
Simple Viewport rotated and zoomed to a rectangle in modelspace, see attachment.
When executing the command MSPVP1 an exact matching rectangle presenting the Paperspace Viewport border will be created in Modelspace.
When executing the command msPVPByGile there is a small displacement.
I suppose there is a problem with the order of the Matrix transformation in
Matrix3d ps2wcs = pvp2.PSDCS2DCS() * pvp2.DCS2WCS();

Any suggestions?
Greetings,
Frits



Frits

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Geometry extensions
« Reply #11 on: November 15, 2011, 09:15:45 PM »
Hi,

As you say the matrix multiplication is not comutative.
When multiplying two matrices, the resulting matrix can be considered as the combination of the right hand matrix transformation first and then, the left hand one.
This is the way the * operator works (as in maths).

So to transform from paper space coordinates to model space coordinates, you have to write:
Code: [Select]
Matrix3d ps2wcs = pvp2.DCS2WCS() * pvp2.PSDCS2DCS();The Matrix3d class provides a method which (perhaps) allows more 'readable' code: PreMultiplyBy.
Code: [Select]
Matrix3d ps2wcs = pvp2.PSDCS2DCS().PreMultiplyBy(pvp2.DCS2WCS());
You can see this message.
« Last Edit: November 15, 2011, 09:23:22 PM by (gile) »

Offline frits432

  • Newbie
  • *
  • Posts: 15
  • Karma: +1/-0
  • Gender: Male
    • prefered language: C
    • Prog expertise: Beginner
    • View Profile
Re: Geometry extensions
« Reply #12 on: November 16, 2011, 09:14:36 AM »
Gile,
You're right, this "pvp2.DCS2WCS() * pvp2.PSDCS2DCS()" was the transformation what i am looking for.
Thanks Gile, you're the expert!
Frits

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Re: Geometry extensions
« Reply #13 on: January 21, 2013, 08:13:21 PM »
I updated the attachment and documentation in the first message.