TheSwamp
Code Red => .NET => Topic started by: wannabe 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
-
This is what I do. I believe this code is in the CurveUtil class in the source code I have posted on my website (http://"http://www.quuxsoft.com/SincpacC3D_source.aspx").
/// <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);
}
-
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:
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();
}
-
The way you posed the question
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.
-
I've made some progress:
foreach (Object id in curveLCollection)
{
Curve segment = (Curve)id;
}
EDIT: The above works :lol: :lol: :lol:
Thanks.
The way you posed the question 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.
-
This is how I would do, to use the GetOffsetCurves method, on a quick code that offset a curve to both sides:
[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.
-
This is how I would do, to use the GetOffsetCurves method, on a quick code that offset a curve to both sides:
[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.
-
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:
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
-
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 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...
-
Hmm don't they go away on the tr.Commit();
Ah yes, are those objects transatcion residient?... good point :laugh:
-
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.
-
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 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.
-
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?
//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();
-
you need to check if the objects are valid first, before doing anything, and I never had use the call to trans.Abort();
-
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.
-
Have alook at AcDbCurve::getOffsetCurves in the ARX docs. Aslo have you tried what sinc posted?