Author Topic: Ascertaining Relative Location To Curve  (Read 6096 times)

0 Members and 1 Guest are viewing this topic.

wannabe

  • Guest
Ascertaining Relative Location To Curve
« on: June 26, 2009, 07:04:39 AM »
Does anyone have any suggestions about how I can ascertain which side of a curve an object is on.

I originally though that querying the X and Y of the object's centre and the point perpendicular on the curve would work. However, if there are extreme meanders, a line going south East for example could be on the left or the right depending how far a long the curve its perpendicular point is.

My current thought is to align the ucs with the perpendicular point and a point a small distance along the line. I'm not sure even this would be fullt accurate or if there is an ideal I haven't come across yet.

Any suggestions?

Nick

sinc

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #1 on: June 26, 2009, 08:10:36 AM »
This is what I do.  I believe this code is in the CurveUtil class in the source code I have posted on my website.

Code: [Select]
        /// <summary>
        /// Returns +1 if p3 is on right side of line formed by p1-p2, or
        /// returns -1 if p3 is on lefts side of line formed by p1-p2.  Points
        /// are flattend to XY plane.
        /// </summary>
        public static int DeflectionDirection(Point3d p1, Point3d p2, Point3d p3)
        {
            return DeflectionDirection(
                new Point2d(p1.X, p1.Y),
                new Point2d(p2.X, p2.Y),
                new Point2d(p3.X, p3.Y)
                );
        }

        /// <summary>
        /// Returns +1 if p3 is on right side of line formed by p1-p2, or
        /// returns -1 if p3 is on lefts side of line formed by p1-p2.
        /// </summary>
        public static int DeflectionDirection(Point2d p1, Point2d p2, Point2d p3)
        {
            double crossProduct = ((p2.X - p1.X) * (p3.Y - p1.Y)) - ((p2.Y - p1.Y) * (p3.X - p1.X));
            return (crossProduct > 0) ? -1 : 1;
        }

        public static int DeflectionDirection(Curve curve, Point3d point)
        {
            Point3d pointOnCurve = curve.GetClosestPointTo(point, Vector3d.ZAxis, false);
            return DeflectionDirection(curve, point, pointOnCurve);
        }

        public static int DeflectionDirection(Curve curve, Point3d point, Point3d pointOnCurve)
        {
            double dist = curve.GetDistAtPoint(pointOnCurve);
            Point3d pol2;
            if ((dist + .01) > curve.GetDistanceAtParameter(curve.EndParam))
            {
                pol2 = pointOnCurve;
                pointOnCurve = curve.GetPointAtDist(dist - .01);
            }
            else
            {
                pol2 = curve.GetPointAtDist(dist + .01);
            }
            return CurveUtil.DeflectionDirection(pointOnCurve, pol2, point);
        }

wannabe

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #2 on: June 26, 2009, 09:35:42 AM »
I can't acces the link from sinc on the work's machine so I'll try it at home. In the meantime, I'm having a slight difficulty getting an offset version of my curve. Here's the code which crashes in the first line of my transaction whilst trying to cast the object to a curve (the object returned as a DBObjectcollection returned from the Curve.GetOffsetCurves() method.

Here's the offending code:

Code: [Select]
private static string getOffsetSide(BlockReference block)
        {
            double distToL;
            double distToR;

            //1. Offset curve a small amount in both directions
            DBObjectCollection curveLCollection = SelectedCurve.GetOffsetCurves(1.0);
            DBObjectCollection curveRCollection = SelectedCurve.GetOffsetCurves(-1.0);

            //2. Add to current space
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                Curve curveL = (Curve)trans.GetObject(curveLCollection[0].ObjectId, OpenMode.ForWrite);
                Curve curveR = (Curve)trans.GetObject(curveRCollection[0].ObjectId, OpenMode.ForWrite);

                BlockTableRecord currentSpace = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                currentSpace.AppendEntity(curveL);
                currentSpace.AppendEntity(curveR);


                //3. Measure distance to both curves
                Point3d blockCentre = new Point3d(block.Position.X, block.Position.Y, 0);

                Point3d curveLPoint = curveL.GetClosestPointTo(blockCentre, false);
                Line lineToL = new Line(blockCentre, new Point3d(curveLPoint.X, curveLPoint.Y, 0));
                distToL = lineToL.Length;

                Point3d curveRPoint = curveR.GetClosestPointTo(blockCentre, false);
                Line lineToR = new Line(blockCentre, new Point3d(curveRPoint.X, curveRPoint.Y, 0));
                distToR = lineToR.Length;

                //4 dispose of curves
                curveL.Erase();
                curveR.Erase();

                trans.Abort();
            }

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Ascertaining Relative Location To Curve
« Reply #3 on: June 26, 2009, 10:02:15 AM »
The way you posed the question
Quote
which side of a curve an object is on.
you need to start with bounding boxes as unless you know the size of the object you don't know what point to use on the object. There is a possibility that the object is touching/ intersecting the curve.

wannabe

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #4 on: June 26, 2009, 10:08:45 AM »
I've made some progress:

Code: [Select]
foreach (Object id in curveLCollection)
                {
                    Curve segment = (Curve)id;
                  
                }

EDIT: The above works  :lol: :lol: :lol:



Thanks.

The way you posed the question
Quote
which side of a curve an object is on.
you need to start with bounding boxes as unless you know the size of the object you don't know what point to use on the object. There is a possibility that the object is touching/ intersecting the curve.
« Last Edit: June 26, 2009, 10:16:57 AM by wannabe »

Spike Wilbury

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #5 on: June 26, 2009, 10:27:30 AM »
This is how I would do, to use the GetOffsetCurves method, on a quick code that offset a curve to both sides:

Code: [Select]
[CommandMethod("MYOFFSET")]
public void myoffset()
{
    Document doc = acadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    PromptEntityResult res = ed.GetEntity("\nSelect curve to offset both sides: ");
    if (res.Status != PromptStatus.OK) return;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        Curve curve = tr.GetObject(res.ObjectId, OpenMode.ForRead, false) as Curve;
        if (curve != null)
        {
            double offsetDist = 2.0;
            DBObjectCollection curvesPositiveSide = curve.GetOffsetCurves(offsetDist);
            DBObjectCollection curvesNegativeSide = curve.GetOffsetCurves(-offsetDist);
            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
            foreach (DBObject obj in curvesPositiveSide)
            {
                btr.AppendEntity((Entity)obj);
                tr.AddNewlyCreatedDBObject(obj, true);
            }
            foreach (DBObject obj in curvesNegativeSide)
            {
                btr.AppendEntity((Entity)obj);
                tr.AddNewlyCreatedDBObject(obj, true);
            }
        }
        tr.Commit();
    }
}

might help... maybe.

wannabe

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #6 on: June 26, 2009, 10:33:06 AM »
This is how I would do, to use the GetOffsetCurves method, on a quick code that offset a curve to both sides:

Code: [Select]
[CommandMethod("MYOFFSET")]
public void myoffset()
{
    Document doc = acadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    PromptEntityResult res = ed.GetEntity("\nSelect curve to offset both sides: ");
    if (res.Status != PromptStatus.OK) return;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        Curve curve = tr.GetObject(res.ObjectId, OpenMode.ForRead, false) as Curve;
        if (curve != null)
        {
            double offsetDist = 2.0;
            DBObjectCollection curvesPositiveSide = curve.GetOffsetCurves(offsetDist);
            DBObjectCollection curvesNegativeSide = curve.GetOffsetCurves(-offsetDist);
            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
            foreach (DBObject obj in curvesPositiveSide)
            {
                btr.AppendEntity((Entity)obj);
                tr.AddNewlyCreatedDBObject(obj, true);
            }
            foreach (DBObject obj in curvesNegativeSide)
            {
                btr.AppendEntity((Entity)obj);
                tr.AddNewlyCreatedDBObject(obj, true);
            }
        }
        tr.Commit();
    }
}

might help... maybe.

Yeah, thats an interesting way to do things and I definitely appreciate the contribution.

I don't really want to keep the curves at the moment. They are just used to work out two distances and then they are not needed.

Cheers again.

Spike Wilbury

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #7 on: June 26, 2009, 11:16:32 AM »
Quote
I don't really want to keep the curves at the moment. They are just used to work out two distances and then they are not needed.

I was providing a way to implement the GetOffsetCurves method.

If you want to work on the offset curves, you do not need to call the AppendEntity();

Here is a way to do it:

Code: [Select]
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
PromptEntityResult res = ed.GetEntity("\nSelect curve to offset both sides: ");
if (res.Status != PromptStatus.OK) return;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
    Curve curve = tr.GetObject(res.ObjectId, OpenMode.ForRead, false) as Curve;
    if (curve != null)
    {
        double offsetDist = 2.0;
        DBObjectCollection curvesPositiveSide = curve.GetOffsetCurves(offsetDist);
        DBObjectCollection curvesNegativeSide = curve.GetOffsetCurves(-offsetDist);
        Curve curvePos = (Curve)curvesPositiveSide[0];
        Curve curveNeg = (Curve)curvesNegativeSide[0];

        Point3d sp = new Point3d();
        Point3d ep = new Point3d();
        double d = 0.0;
        if (curvePos != null)
            sp = curvePos.StartPoint;
        if (curveNeg != null)
            ep = curveNeg.StartPoint;

        d = sp.DistanceTo(ep); // distance from both points
    }
    tr.Commit();
}

might help... maybe

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Ascertaining Relative Location To Curve
« Reply #8 on: June 26, 2009, 11:26:40 AM »
Hi Luis,

in this case, would you need to iterate through the DBObjectCollections'
disposing of each object that was not added the to DB?


Spike Wilbury

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #9 on: June 26, 2009, 11:29:49 AM »
Hi Luis,

in this case, would you need to iterate through the DBObjectCollections'
disposing of each object that was not added the to DB?



Hi Daniel,

I say yes... but
Hmm don't they go away on the tr.Commit(); ... I was trying to demostrate on a quicky code - how to use those objects without added to the database... :)
Let me check...

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Ascertaining Relative Location To Curve
« Reply #10 on: June 26, 2009, 11:35:21 AM »
Hmm don't they go away on the tr.Commit();

Ah yes, are those objects transatcion residient?... good point  :laugh:

sinc

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #11 on: June 26, 2009, 11:49:42 AM »
If you create a DBObject and do not add it to a Transaction, you must dispose of it yourself.  Autocad will get wobbly and probably crash otherwise.

Spike Wilbury

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #12 on: June 26, 2009, 12:16:06 PM »
have been out of the C# coding... but I think they are disposed inside of the using { ... }... but I'm not a C# expert  :-(


I have tried several times to crash autocad with that code, and no luck....

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Ascertaining Relative Location To Curve
« Reply #13 on: June 26, 2009, 12:29:01 PM »
It's not a big deal since those objects have finalizers that should do the cleanup,
I think there was an issue when the collection was disposed before the object(s) it contained were disposed. 

wannabe

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #14 on: June 29, 2009, 03:32:00 AM »
Back on the subject of 'my curves' , I'm having a small issue with the following code snippet. In one of my drawings, it was giving me a null reference exception. Having stepped throught the code I've found it to be the curveRCollection: there was no object being stored in it, yet the curveLCollection was holding the offset curve as intended.

I've tested the code on a few other drawings and it works fine on those (the curveRCollection is being populated as expected).

Any ideas?

Code: [Select]
   //1. Offset curve a small amount in both directions

            DBObjectCollection curveLCollection = SelectedCurve.GetOffsetCurves(0.001);
            DBObjectCollection curveRCollection = SelectedCurve.GetOffsetCurves(-0.001);
           

            //2. Add to current space
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
               
                foreach(object id in curveLCollection)
                curveL = (Curve)id;

                foreach (object id in curveRCollection)
                 curveR = (Curve)id;

                BlockTableRecord currentSpace = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                currentSpace.AppendEntity(curveL);
                currentSpace.AppendEntity(curveR);


                //3. Measure distance to both curves
                Point3d blockCentre = new Point3d(block.Position.X, block.Position.Y, 0);

                Point3d curveLPoint = curveL.GetClosestPointTo(blockCentre, false);
                Line lineToL = new Line(blockCentre, new Point3d(curveLPoint.X, curveLPoint.Y, 0));
                distToL = lineToL.Length;

                Point3d curveRPoint = curveR.GetClosestPointTo(blockCentre, false);
                Line lineToR = new Line(blockCentre, new Point3d(curveRPoint.X, curveRPoint.Y, 0));
                distToR = lineToR.Length;

                //4 dispose of curves
                curveL.Erase();
                curveR.Erase();

                trans.Abort();

Spike Wilbury

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #15 on: June 29, 2009, 10:24:20 AM »
you need to check if the objects are valid first, before doing anything, and I never had use the call to trans.Abort();

wannabe

  • Guest
Re: Ascertaining Relative Location To Curve
« Reply #16 on: June 29, 2009, 10:41:58 AM »
you need to check if the objects are valid first, before doing anything, and I never had use the call to trans.Abort();

The curve is being offset, hence the curveLCollection being populate with the single curve offset on the one side. However, the offset to the other is failing.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Ascertaining Relative Location To Curve
« Reply #17 on: June 29, 2009, 06:22:27 PM »
Have alook at AcDbCurve::getOffsetCurves in the ARX docs. Aslo have you tried what sinc posted?