ObjectARX
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Precision of getSplitCurves

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
khunstad
1121 Views, 8 Replies

Precision of getSplitCurves

Hi!

 

I am using getSplitCurves on a small arc (0.00021807) with a splitpoint very close to the start point (distance is 0.0000084). It returns Acad::eOK, but the length of the returned array is only 1, so the arc isn't really split.

 

If I run mapclean from Autocad Map on this, it is able to split the arc properly.

 

Is there some global presicision setting in ObjectArx? Or does Autodesk have their own internal routines with more precision, which are not exposed through ObjectArx?

 

I hate the idea of rewriting getSplitCurves...

 

Thanks for any help!

 

8 REPLIES 8
Message 2 of 9
kubitTilo
in reply to: khunstad

You may try setting AcGeContext::gTol.setEqualPoint(...) to a higher than the default value, which is 1e-10 I think.

Don't forget to save and restore the original value before and after your operations 😉

 

 




Tilo Pfliegner
Message 3 of 9
khunstad
in reply to: kubitTilo

Excellent! This value was 5E-05 as default, that's why it considered a line of a little less than that as uninteresting.

 

After setting it to 1E-10 it worked like a charm.

 

Thank you very much, this was an extremely quick and precise answer and something that wasn't easy to find when you don't know where to look!

 

Best regards,

 

Knut

Message 4 of 9
LE3
Advocate
in reply to: khunstad

I recall getting something similar with small length entities, what i did was to use the boundingbox or extents of the entities and then do a crossing selection, get the intersection points, sort these points, on polylines i always checked the type if not were AcDb::k2dSimplePoly, i converted to a temp light weight poly in order (in my case as far i remember) to make my SplitCurves command to work.

 

Here is some partial code from my function - hth:

	for (UINT i = 0; i < length1; i++) 
	{
		AcDbObjectId oid;
		ads_name ename;
		acedSSName(ss1, i, ename);
		if (acdbGetObjectId(oid, ename) != Acad::eOk) return;
		AcDbObjectPointer<AcDbCurve> pPoly(oid, AcDb::kForWrite);
		if (pPoly.openStatus() == Acad::eOk) 
		{
			ids.append(oid); // for erase

			AcDbExtents ebox;
			pPoly->getGeomExtents(ebox);

			AcGePoint3d ll, ur;
			ll = ebox.minPoint();
			ur = ebox.maxPoint();

			acdbWcs2Ucs(asDblArray(ll), asDblArray(ll), false);
			acdbWcs2Ucs(asDblArray(ur), asDblArray(ur), false);

			ads_point ptres, a, b;
			AcGePoint3d m;

			double d = (sqrt(2.0) * acutDistance(asDblArray(ll), asDblArray(ur)) / 2.0);

			acutPolar(asDblArray(ll), acutAngle(asDblArray(ll), asDblArray(ur)), acutDistance(asDblArray(ll), asDblArray(ur)), asDblArray(m));

			acutPolar(asDblArray(m), ((3 * kPi) / 4), d, ptres);
			acdbWcs2Ucs(ptres, a, false);
			acutPolar(asDblArray(m), ((7 * kPi) / 4), d, ptres);
			acdbWcs2Ucs(ptres, b, false);

			ads_name ss2;
			resbuf *rbFilter = acutBuildList(RTDXF0, _T("LINE,ARC,LWPOLYLINE,POLYLINE,CIRCLE,SPLINE,ELLIPSE"), RTNONE);
			if (acedSSGet(_T("_C"), asDblArray(ll), asDblArray(ur), rbFilter, ss2) != RTNORM) 
			//if (acedSSGet(_T("_C"), a, b, rbFilter, ss2) != RTNORM) 
			{
				acutRelRb(rbFilter); 
				return; 
			}
			acutRelRb(rbFilter);

			acedSSDel(ename, ss2);

 I tested with a arc of the same length and the same split distance, and works here.

Message 5 of 9
khunstad
in reply to: LE3

Thanks for trying, but I don't really see what you do here. There is nothing created, only a lot of calculation?

 

Anyway, I got a great solution already!

Message 6 of 9
LE3
Advocate
in reply to: khunstad

Glad you got a solution and yes i realize that, here is my old code, in case someone finds it useful.

 

typedef std::vector<AcGePoint3d> PointList;
const double kPi = 3.14159265358979323846;

Acad::ErrorStatus MakeTempLWPoly (AcDb2dPolyline* tmp2dPoly, AcGePoint3dArray &pts, AcDbVoidPtrArray &curveSegments)
{
	Acad::ErrorStatus es;
	AcDbObjectId curSpaceId = acdbCurDwg()->currentSpaceId();
	AcDbBlockTableRecord *pBlkRec = NULL;
	AcDbCurve* tmpCurve;
	AcGePoint3dArray vertices;
	AcGeDoubleArray bulges;
	AcDb2dVertex* vert = NULL;
	AcDbObjectId vId;
	double c = 0;
	AcDbObjectIterator *vIter;
	double parametro;
	vIter = tmp2dPoly->vertexIterator();
	for (; !vIter->done(); vIter->step()) 
	{
		vId = vIter->objectId();
		if (tmp2dPoly->openVertex(vert, vId, AcDb::kForRead) == Acad::eOk)
		{
			if (tmp2dPoly->getParamAtPoint(vert->position(), parametro) == Acad::eOk)
			{
				c = vert->bulge();
				if ((tmp2dPoly->normal()-AcGeVector3d::kZAxis).length() > 1E-6) c *= -1.0;
				vertices.append(tmp2dPoly->vertexPosition(*vert));
				bulges.append(c);
			}
			vert->close();
		}
	}
	if (tmp2dPoly->isClosed()) 
	{
		if (vertices.first() != vertices.last()) 
		{
			vertices.append(vertices.first());
			bulges.append(bulges.first());
		}
	}
	delete vIter;

	Adesk::Boolean closed;
	if (tmp2dPoly->isClosed()) 
	{
		closed = Adesk::kTrue;
	}
	else
	{
		closed = Adesk::kFalse;
	}

	AcCmColor col = tmp2dPoly->color();
	ACHAR* ltype = tmp2dPoly->linetype();

	AcDbPolyline* pBreakLine = new AcDbPolyline(vertices.length());
	for (int i=0; i < vertices.length(); i++)
	{
		AcGePoint2d pt;
		pt.set(vertices.at(i).x,vertices.at(i).y);
		pBreakLine->addVertexAt(i,pt,bulges.at(i));
	}

	pBreakLine->setClosed(closed);
	pBreakLine->setColor(col);
	pBreakLine->setLinetype(ltype);
	acutDelString(ltype);
	vertices.removeAll();
	bulges.removeAll();

	es = pBreakLine->getSplitCurves(pts,curveSegments);
	if (es == Acad::eOk)
	{
		for (int i=0; i < curveSegments.length(); i++) 
		{
			tmpCurve = static_cast<AcDbCurve*>(curveSegments[i]);
			if (tmpCurve) 
			{
				if (acdbOpenObject(pBlkRec,curSpaceId,AcDb::kForWrite) == Acad::eOk) 
				{
					pBlkRec->appendAcDbEntity(tmpCurve);
					pBlkRec->close();
					tmpCurve->close();
				}
			}
		}
		curveSegments.removeAll();
	} 
	else 
	{
		for (int i = 0; i < curveSegments.length(); i++) 
		{
			tmpCurve = static_cast<AcDbCurve*>(curveSegments[i]);
			delete tmpCurve;
		}
		curveSegments.removeAll();
	}
	
	pBreakLine->close();
	delete pBreakLine;

	return es;
}

static void SplitCurves (void) 
{
	AcDbObjectId curSpaceId = acdbCurDwg()->currentSpaceId();
	AcDbBlockTableRecord *pBlkRec = NULL;
	AcDbCurve* tmpCurve;
	AcGePoint3dArray pts;
	AcDbVoidPtrArray curveSegments;
	AcGePoint3dArray ints; 
	AcGePoint3dArray duplicates;
	PointList points;
	Acad::ErrorStatus es;
	ads_name ss1;
	AcDbObjectIdArray ids;

	resbuf *rbFilter = acutBuildList(RTDXF0, _T("LINE,ARC,LWPOLYLINE,POLYLINE,CIRCLE,SPLINE,ELLIPSE"), RTNONE);

	if (acedSSGet(NULL, NULL, NULL, rbFilter, ss1) != RTNORM) 
	{
		acutRelRb(rbFilter); 
		return; 
	}

	acutRelRb(rbFilter);

	long length1 = 0;
	if ((acedSSLength(ss1, &length1) != RTNORM) || (length1 == 0)) 
	{
		acedSSFree(ss1);
		return;
	}

	for (UINT i = 0; i < length1; i++) 
	{
		AcDbObjectId oid;
		ads_name ename;
		acedSSName(ss1, i, ename);
		if (acdbGetObjectId(oid, ename) != Acad::eOk) return;
		AcDbObjectPointer<AcDbCurve> pPoly(oid, AcDb::kForWrite);
		if (pPoly.openStatus() == Acad::eOk) 
		{
			ids.append(oid);

			AcDbExtents ebox;
			pPoly->getGeomExtents(ebox);

			AcGePoint3d ll, ur;
			ll = ebox.minPoint();
			ur = ebox.maxPoint();

			acdbWcs2Ucs(asDblArray(ll), asDblArray(ll), false);
			acdbWcs2Ucs(asDblArray(ur), asDblArray(ur), false);

			ads_point ptres, a, b;
			AcGePoint3d m;

			double d = (sqrt(2.0) * acutDistance(asDblArray(ll), asDblArray(ur)) / 2.0);

			acutPolar(asDblArray(ll), acutAngle(asDblArray(ll), asDblArray(ur)), 
				acutDistance(asDblArray(ll), asDblArray(ur)), asDblArray(m));

			acutPolar(asDblArray(m), ((3 * kPi) / 4), d, ptres);
			acdbWcs2Ucs(ptres, a, false);
			acutPolar(asDblArray(m), ((7 * kPi) / 4), d, ptres);
			acdbWcs2Ucs(ptres, b, false);

			ads_name ss2;
			resbuf *rbFilter = acutBuildList(RTDXF0, _T("LINE,ARC,LWPOLYLINE,POLYLINE,CIRCLE,SPLINE,ELLIPSE"), RTNONE);
			if (acedSSGet(_T("_C"), asDblArray(ll), asDblArray(ur), rbFilter, ss2) != RTNORM) 
			//if (acedSSGet(_T("_C"), a, b, rbFilter, ss2) != RTNORM) 
			{
				acutRelRb(rbFilter); 
				return; 
			}
			acutRelRb(rbFilter);

			acedSSDel(ename, ss2);

			long length2 = 0;
			if ((acedSSLength(ss2, &length2) != RTNORM) || (length2 == 0)) 
			{
				acedSSFree(ss2);
				return;
			}

			for (UINT i = 0; i < length2; i++) 
			{
				AcDbObjectId oid;
				ads_name ename;
				acedSSName(ss2, i, ename);
				if (acdbGetObjectId(oid, ename) != Acad::eOk) return;

				AcDbObjectPointer<AcDbCurve> pEnt(oid, AcDb::kForRead);
				if (pEnt.openStatus() == Acad::eOk) 
				{
					if (pPoly->intersectWith(pEnt.object(), AcDb::kOnBothOperands, ints) == Acad::eOk) 
					{
						if (!ints.isEmpty()) 
						{
							for (UINT i = 0; i < ints.length(); i++) 
							{
								if (!duplicates.contains(ints.at(i))) 
								{
									duplicates.append(ints.at(i));
									points.push_back(ints.at(i));
								} 
								else 
									continue; 
							}
						}
					}
				}
			}
			acedSSFree(ss2);

			if (!points.empty()) 
			{
				vector<double> distances;
				map<double, AcGePoint3d> m;
				double dist;
				for (UINT i = 0; i < points.size(); i++) 
				{
					AcGePoint3d pt = points.at(i);
					if (pPoly->getDistAtPoint(pt, dist) == Acad::eOk) 
					{
						m.insert(make_pair(dist, pt));
						distances.push_back(dist);
					}
				}

				map<double, AcGePoint3d>::const_iterator it;
				int cnt = 0;

				std::sort(distances.begin(), distances.end());
				std::vector<AcGePoint3d> _points;

				for (it = m.begin(); it != m.end(); ++it) 
				{
					AcGePoint3d pt;
					it = m.find(distances.at(cnt));
					pt = (*it).second;
					_points.push_back(pt);
					cnt = (1 + cnt);
				}

				m.clear();
				distances.clear();

				for (UINT i = 0; i < _points.size(); i++) 
				{
					AcGePoint3d pt;
					pt = _points.at(i);
					acdbWcs2Ucs(asDblArray(pt), asDblArray(pt), false);
					pts.append(pt);
				}

				if (pPoly->isKindOf(AcDb2dPolyline::desc()))
				{
					AcDb2dPolyline *tmp2dPoly = AcDb2dPolyline::cast((AcRxObject*)pPoly.object());

					switch (tmp2dPoly->polyType()) 
					{
					case AcDb::k2dSimplePoly:
						if (pPoly->getSplitCurves(pts, curveSegments) == Acad::eOk)
						{
							for (UINT i = 0; i < curveSegments.length(); i++) 
							{
								tmpCurve = static_cast<AcDbCurve*>(curveSegments[i]);
								if (tmpCurve) 
								{
									if (acdbOpenObject(pBlkRec, curSpaceId, AcDb::kForWrite) == Acad::eOk) 
									{
										pBlkRec->appendAcDbEntity(tmpCurve);
										pBlkRec->close();
										tmpCurve->close();
									}
								}
							}
							curveSegments.removeAll();
						} 
						else 
						{
							for (UINT i = 0; i < curveSegments.length(); i++) 
							{
								tmpCurve = static_cast<AcDbCurve*>(curveSegments[i]);
								delete tmpCurve;
							}
							curveSegments.removeAll();
						}

						break;
					case AcDb::k2dFitCurvePoly:
						MakeTempLWPoly(tmp2dPoly, pts, curveSegments);
						break;
					case AcDb::k2dQuadSplinePoly:
						MakeTempLWPoly(tmp2dPoly, pts, curveSegments);
						break;
					case AcDb::k2dCubicSplinePoly:
						MakeTempLWPoly(tmp2dPoly, pts, curveSegments);
						break;
					}
				}
				else
				{					
					if (pPoly->getSplitCurves(pts, curveSegments) == Acad::eOk)
					{
						for (UINT i = 0; i < curveSegments.length(); i++) 
						{
							tmpCurve = static_cast<AcDbCurve*>(curveSegments[i]);
							if (tmpCurve) 
							{
								if (acdbOpenObject(pBlkRec, curSpaceId, AcDb::kForWrite) == Acad::eOk) 
								{
									pBlkRec->appendAcDbEntity(tmpCurve);
									pBlkRec->close();
									tmpCurve->close();
								}
							}
						}
						curveSegments.removeAll();
					} 
					else 
					{
						for (UINT i = 0; i < curveSegments.length(); i++) 
						{
							tmpCurve = static_cast<AcDbCurve*>(curveSegments[i]);
							delete tmpCurve;
						}
						curveSegments.removeAll();
					}
				}

				_points.clear();
				points.clear();
			}
			if (!ints.isEmpty())
				ints.removeAll();

			if (!duplicates.isEmpty())
				duplicates.removeAll();

			if (!curveSegments.isEmpty())
				curveSegments.removeAll();

			if (!pts.isEmpty())
				pts.removeAll();
		}
	}
	acedSSFree(ss1);

	if (!ids.isEmpty())
	{
		for (UINT i = 0; i < ids.length(); i++)
		{
			AcDbObjectPointer<AcDbEntity> pEnt(ids[i], AcDb::kForWrite);
			if (pEnt.openStatus() == Acad::eOk)
			{
				pEnt->erase();
			}
		}
		ids.removeAll();
	}
}

 Also, a simple version in C#:

#region Split Curves
[CommandMethod("SPLITCURVES")]
public void cmd_splitCurves()
{
    var editor = AcadApp.DocumentManager.MdiActiveDocument.Editor;
    var tv = new[] { new TypedValue((int)DxfCode.Start, "LINE,ARC,LWPOLYLINE,POLYLINE,CIRCLE,SPLINE,ELLIPSE") };
    var filter = new SelectionFilter(tv);
    const string curveObjects = "curve objects";
    var options = new PromptSelectionOptions
    {
        MessageForAdding = string.Format("\nAdd {0} to selection", curveObjects),
        MessageForRemoval = string.Format("\nRemove {0} from selection", curveObjects),
        AllowDuplicates = false,
        RejectObjectsFromNonCurrentSpace = true
    };
    var mainSelection = editor.GetSelection(options, filter);
    if (mainSelection.Status != PromptStatus.OK) return;

    using (var transaction = editor.Document.Database.TransactionManager.StartTransaction())
    {
        var blockTableRecord = transaction.GetObject(editor.Document.Database.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
        if (blockTableRecord != null)
        {
            foreach (var mainObjectId in mainSelection.Value.GetObjectIds())
            {
                var points = new Point3dCollection();
                var dictionary = new SortedDictionary<double, Point3d>();

                var mainCurve = transaction.GetObject(mainObjectId, OpenMode.ForWrite) as Curve;
                if (mainCurve == null) continue;

                var extents = mainCurve.GeometricExtents;
                var minPoint = extents.MinPoint;
                var maxPoint = extents.MaxPoint;

                var subSelection = editor.SelectCrossingWindow(minPoint, maxPoint, filter);
                if (subSelection.Status != PromptStatus.OK) continue;

                foreach (var subObjectId in subSelection.Value.GetObjectIds())
                {
                    var subCurve = transaction.GetObject(subObjectId, OpenMode.ForRead) as Curve;
                    if (subCurve == null) continue;
                    var intersections = new Point3dCollection();
                    mainCurve.IntersectWith(subCurve, Intersect.OnBothOperands, intersections, IntPtr.Zero, IntPtr.Zero);
                    if (intersections.Count <= 0) continue;

                    foreach (Point3d intersection in intersections)
                    {
                        if (points.Contains(intersection)) continue;

                        points.Add(intersection);
                    }
                }
                subSelection.Value.Dispose();

                if (points.Count <= 0) continue;

                foreach (Point3d point in points)
                {
                    var distance = mainCurve.GetDistAtPoint(point);
                    if (dictionary.ContainsKey(distance)) continue;

                    dictionary.Add(distance, point);
                }

                if (!dictionary.Any()) continue;

                var splitPoints = new Point3dCollection(dictionary.Values.ToArray());
                var splitCurves = mainCurve.GetSplitCurves(splitPoints);
                foreach (DBObject splitCurve in splitCurves)
                {
                    var curve = splitCurve as Curve;
                    if (curve == null) continue;

                    blockTableRecord.AppendEntity(curve);
                    transaction.AddNewlyCreatedDBObject(curve, true);
                }
            }
        }
        transaction.Commit();
    }
}
#endregion

 HTH.

Message 7 of 9
LE3
Advocate
in reply to: LE3

On any of my possible replies with code on these customization forums, i need to figure out how the insert-code works, so far what i see as a result is not good, is this how it works or displayed on this site?

Message 8 of 9
khunstad
in reply to: LE3

Seems like all your code was included this time. I'll look at it in 4-5 hours.

Message 9 of 9
khunstad
in reply to: LE3

Sorry, but I didnt' really see what you achieve with this code, LE3. And the gtol trick worked for now, so I'll let it be like that.

 

Thank you anyway!

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost