<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Create close polyline from Region in ObjectARX Forum</title>
    <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12668749#M948</link>
    <description>&lt;P&gt;The algorithm was designed for an &lt;FONT face="courier new,courier"&gt;AcDbRegion&lt;/FONT&gt; that has exactly one face and no holes. It expects exactly one "outer loop". When you explode() an&amp;nbsp;&lt;FONT face="courier new,courier"&gt;AcDbRegion&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;that has N faces, the results are N &lt;FONT face="courier new,courier"&gt;AcDbRegion&lt;/FONT&gt;s that must be processed each.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I stated that I'm not 100% sure whether it is guaranteed, that the explosion fragments appear in the right order.&lt;/P&gt;
&lt;P&gt;I'm also not sure whether the fragments of a region with holes or multiple faces will appear in a defined order.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If you want to analyze these regions I would recommend to use the BREP API. It allows to iterate over outer and inner loops in a region.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The following code is not optimized but it works. Basically it implements&lt;/P&gt;
&lt;LI-CODE lang="cpp"&gt;void BuildLoops(
    std::vector&amp;lt;PlineSegment&amp;gt; &amp;amp;segments, 
    std::vector&amp;lt; std::vector&amp;lt;int&amp;gt; &amp;gt;&amp;amp; loops, 
    double minGap
);&lt;/LI-CODE&gt;
&lt;P&gt;It calculates "loops" which are arrays of indices of connected &lt;FONT face="courier new,courier"&gt;PlineSegment&lt;/FONT&gt;s.&lt;/P&gt;
&lt;P&gt;It would be more effective to explode a multi-face loop to multiple&amp;nbsp;&lt;FONT face="courier new,courier"&gt;vector&amp;lt;PlineSegment&amp;gt;&lt;/FONT&gt; arrays.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-CODE lang="cpp"&gt;struct PlineSegment {
	AcGePoint2d p1, p2;
	double bulge=0.0;
	int   reversed=0; // 0 unknown, -1 reversed, 1 not reversed
	bool  inserted=false;
};

// MyRegion2Pline, R2P
void BuildLoops(std::vector&amp;lt;PlineSegment&amp;gt; &amp;amp;segments, std::vector&amp;lt; std::vector&amp;lt;int&amp;gt; &amp;gt;&amp;amp; loops, double minGap)
{
	int i, N = (int)segments.size();	
	std::vector&amp;lt;int&amp;gt; loop;
	bool bInserted = false;
	do 
	{
		bInserted = false;
		for (i = 0; i &amp;lt; N; ++i)
		{
			if (segments[i].inserted)
				continue;
			if (loop.empty())
			{
				loop.push_back(i);
				segments[i].inserted = true;
			}
			else
			{
				PlineSegment&amp;amp; psPrev = segments[loop.back()];
				PlineSegment&amp;amp; ps = segments[i];
				if (ps.inserted)
					continue;
				double d11, d12, d21, d22, *dMin = &amp;amp;d11;
				d11 = psPrev.p1.distanceTo(ps.p1);
				d12 = psPrev.p1.distanceTo(ps.p2);
				if (d12 &amp;lt; *dMin)
					dMin = &amp;amp;d12;
				d21 = psPrev.p2.distanceTo(ps.p1);
				if (d21 &amp;lt; *dMin)
					dMin = &amp;amp;d21;
				d22 = psPrev.p2.distanceTo(ps.p2);
				if (d22 &amp;lt; *dMin)
					dMin = &amp;amp;d22;

				if (*dMin &amp;lt; minGap)
				{
					loop.push_back(i);
					ps.inserted = true;

					if (dMin == &amp;amp;d21)
					{
						psPrev.reversed = ps.reversed = 1;
					}
					else if (dMin == &amp;amp;d11)
					{
						ps.reversed = 1;
						psPrev.reversed = -1;
					}
					else if (dMin == &amp;amp;d22)
					{
						ps.reversed = -1;
						psPrev.reversed = 1;
					}
					else if (dMin == &amp;amp;d12)
					{
						psPrev.reversed = ps.reversed = -1;
					}

					// Is the loop closed now?
					PlineSegment&amp;amp; psStart = segments[loop.front()];
					const AcGePoint2d&amp;amp; ptStart = (psStart.reversed &amp;gt; 0) ? psStart.p1 : psStart.p2;
					const AcGePoint2d&amp;amp; pt = (ps.reversed&amp;gt;0) ? ps.p2 : ps.p1;
					double d = ptStart.distanceTo(pt);
					if (d &amp;lt; minGap)
					{
						// Yes! Start a new loop
						loops.push_back(std::move(loop));
						loop.clear();
					}
					bInserted = true;
					break; // exit for(j..) loop
				}
			}
		}
	}
	while (bInserted);
}


void cmdRegion2Pline()
{
	ads_point    pt;
	ads_name     ent;
	AcDbObjectId idRegion;

	if (acedEntSel(_T("\nSelect region"), ent, pt) != RTNORM)
		return;

	if (acdbGetObjectId(idRegion, ent) != Acad::eOk)
		return;

	Acad::ErrorStatus es;
	AcDbVoidPtrArray curves;
	AcDbRegion* region;
	AcGePlane regionPlane;
	if ((es = acdbOpenObject(region, idRegion, AcDb::kForRead)) == Acad::eOk)
	{
		region-&amp;gt;getPlane(regionPlane);
		region-&amp;gt;explode(curves);
		region-&amp;gt;close();

		// AcDbRegions with multiple faces will create single-face regions upon explode
		AcDbVoidPtrArray curvesFromSubregions;
		int i, N = curves.length();
		for (i = 0; i &amp;lt; N; ++i)
		{
			AcDbObject *obj = (AcDbObject*)curves[i];
			AcDbRegion *rg;
			if (rg = AcDbRegion::cast(obj))
			{
				AcDbVoidPtrArray curves2;
				rg-&amp;gt;explode(curves2);
				curvesFromSubregions.append(curves2);
				delete obj;
				curves.removeAt(i--);
				--N;
			}
		}
		curves.append(curvesFromSubregions);
	}

	AcGePoint3d origin;
	AcGeVector3d axis1, axis2, norm(regionPlane.normal());
	regionPlane.getCoordSystem(origin, axis1, axis2);
	// Recalculate origin to be the closest point on the plane
	double dp = origin.asVector().dotProduct(norm);
	origin = AcGePoint3d::kOrigin + dp * norm;

	AcGeMatrix3d mat_WCS_ECS, mat_ECS_WCS;
	mat_WCS_ECS.setCoordSystem(origin, axis1, axis2, norm);
	mat_ECS_WCS = mat_WCS_ECS.inverse();

	int i, j, N = curves.length();
	AcDbObject* obj;
	AcDbCurve* crv;
	AcDbArc* arc;
	AcGePoint3d ps, pe;
	double angle = 0.0;
	std::vector&amp;lt;PlineSegment&amp;gt; segments;
	PlineSegment segment;
	// Collect segment data:
	for (i = 0; i &amp;lt; N; ++i)
	{
		obj = (AcDbObject*)curves[i];
		if (crv = AcDbCurve::cast(obj))
		{
			crv-&amp;gt;getStartPoint(ps);
			crv-&amp;gt;getEndPoint(pe);
			// Transform to ECS. After this z-components should be 0
			ps.transformBy(mat_ECS_WCS);
			pe.transformBy(mat_ECS_WCS);
			segment.p1 = AcGePoint2d(ps.x, ps.y);
			segment.p2 = AcGePoint2d(pe.x, pe.y);
			if (segment.p1 != segment.p2) // don't add coincident points.
			{
				if (arc = AcDbArc::cast(obj))
					segment.bulge = tan(0.25 * arc-&amp;gt;totalAngle());
				else
					segment.bulge = 0.0;
			}
			segments.push_back(segment);
		}
		delete obj;
	}

	AcDbDatabase* pDB = acdbHostApplicationServices()-&amp;gt;workingDatabase();
	double minGap = 1000 * AcGeContext::gTol.equalPoint();
	std::vector&amp;lt; std::vector&amp;lt;int&amp;gt; &amp;gt; loops;
	BuildLoops(segments, loops, minGap);
	for (const std::vector&amp;lt;int&amp;gt; &amp;amp;loop : loops)
	{
		AcDbPolyline* pline = new AcDbPolyline();
		pline-&amp;gt;setDatabaseDefaults(pDB);
		unsigned int ix = 0;
		for (int i : loop)
		{
			const PlineSegment&amp;amp; ps = segments[i];
			pline-&amp;gt;addVertexAt(ix++, ps.reversed ? ps.p2:ps.p1, ps.reversed * ps.bulge);
		}
		pline-&amp;gt;setClosed(true);
		pline-&amp;gt;transformBy(mat_WCS_ECS);
		PostToDb(pDB, pline);
	}
}
&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Wed, 27 Mar 2024 10:15:54 GMT</pubDate>
    <dc:creator>tbrammer</dc:creator>
    <dc:date>2024-03-27T10:15:54Z</dc:date>
    <item>
      <title>Create close polyline from Region</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12665549#M942</link>
      <description>&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;SPAN&gt;i want to make completly closed polyline from acdbregion&amp;nbsp;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;i tried but not getting accurate result&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;</description>
      <pubDate>Tue, 26 Mar 2024 05:48:24 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12665549#M942</guid>
      <dc:creator>jignesh.rana</dc:creator>
      <dc:date>2024-03-26T05:48:24Z</dc:date>
    </item>
    <item>
      <title>Re: Create close polyline from Region</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12666014#M943</link>
      <description>&lt;P&gt;It's a bit tricky indeed. You have to deal with ECS coordinats of the polyline's vertices and take into account that some of the lines and arcs you get from &lt;FONT face="courier new,courier"&gt;region-&amp;gt;explode()&lt;/FONT&gt; could be reverted. Try the code below.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This code assumes that the explosion fragments are in the same order as the segments of the region. I'm not 100% sure whether this is guaranteed.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;A completely different approach would be to use the BREP API (&amp;lt;ARX&amp;gt;\utils\brep) instead of &lt;FONT face="courier new,courier"&gt;explode()&lt;/FONT&gt;. It allows to analyze an &lt;FONT face="courier new,courier"&gt;AcDbRegion&lt;/FONT&gt; directly.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-CODE lang="cpp"&gt;struct PlineSegment {
	AcGePoint2d p1, p2;
	double bulge=0.0;
	int   reversed=0; // 0 unknown, -1 reversed, 1 not reversed
};

void cmdRegion2Pline()
{
	ads_point    pt;
	ads_name     ent;
	AcDbObjectId idRegion;

	if (acedEntSel(_T("\nSelect region"), ent, pt) != RTNORM)
		return;

	if (acdbGetObjectId(idRegion, ent) != Acad::eOk)
		return;

	Acad::ErrorStatus es;
	AcDbVoidPtrArray curves;
	AcDbRegion *region;
	AcGePlane regionPlane;
	if ((es = acdbOpenObject(region, idRegion, AcDb::kForRead)) == Acad::eOk)
	{
		region-&amp;gt;getPlane(regionPlane);
		region-&amp;gt;explode(curves);
		region-&amp;gt;close();
	}

	AcGePoint3d origin;
	AcGeVector3d axis1, axis2, norm(regionPlane.normal());
	regionPlane.getCoordSystem(origin, axis1, axis2);
	// Recalculate origin to be the closest point on the plane
	double dp = origin.asVector().dotProduct(norm);
	origin = AcGePoint3d::kOrigin + dp * norm;

	AcGeMatrix3d mat_WCS_ECS, mat_ECS_WCS;
	mat_WCS_ECS.setCoordSystem(origin, axis1, axis2, norm);
	mat_ECS_WCS = mat_WCS_ECS.inverse();

	int i, j, N=curves.length();
	AcDbObject *obj;
	AcDbCurve *crv;
	AcDbArc *arc;
	AcGePoint3d ps, pe;
	double angle=0.0;
	std::vector&amp;lt;PlineSegment&amp;gt; segments;
	PlineSegment segment;
	// Collect segment data:
	for (i=0; i&amp;lt;N; ++i)
	{
		obj = (AcDbObject*)curves[i];
		if (crv = AcDbCurve::cast(obj))
		{			
			crv-&amp;gt;getStartPoint(ps);
			crv-&amp;gt;getEndPoint(pe);
			// Transform to ECS. After this z-components should be 0
			ps.transformBy(mat_ECS_WCS);
			pe.transformBy(mat_ECS_WCS);
			segment.p1 = AcGePoint2d(ps.x, ps.y);
			segment.p2 = AcGePoint2d(pe.x, pe.y);
			if (arc = AcDbArc::cast(obj))
				segment.bulge = tan(0.25 * arc-&amp;gt;totalAngle());
			else
				segment.bulge = 0.0;
			segments.push_back(segment);
		}
		delete obj;
	}
	// When we stitch the polyline together we must make sure that start- and endpoints match.
	AcDbDatabase *pDB = acdbHostApplicationServices()-&amp;gt;workingDatabase();
	AcDbPolyline* pline = new AcDbPolyline();
	pline-&amp;gt;setDatabaseDefaults(pDB);
	unsigned int ix = 0;

	for (i = 0; i &amp;lt; N; ++i)	{
		j = (i&amp;gt;0)? i-1 : N-1;
		PlineSegment &amp;amp;ps = segments[i];
		PlineSegment&amp;amp; psPrev = segments[j];
		if (psPrev.p2 == ps.p1)	{
			psPrev.reversed = ps.reversed = 1;
			pline-&amp;gt;addVertexAt(ix++, ps.p1, ps.reversed * ps.bulge);
		} else if (psPrev.p1 == ps.p1){
			ps.reversed     = 1;
			psPrev.reversed = -1;
			pline-&amp;gt;addVertexAt(ix++, ps.p1, ps.reversed * ps.bulge);
		} else if (psPrev.p2 == ps.p2) {
			ps.reversed     = -1;
			psPrev.reversed = 1;
			pline-&amp;gt;addVertexAt(ix++, ps.p2, ps.reversed * ps.bulge);
		} else if (psPrev.p1 == ps.p2) {
			psPrev.reversed = ps.reversed = -1;
			pline-&amp;gt;addVertexAt(ix++, ps.p2, ps.reversed * ps.bulge);
		}
	}
	pline-&amp;gt;setClosed(true);
	pline-&amp;gt;transformBy(mat_WCS_ECS);
	PostToDb(pDB, pline);
}
&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 26 Mar 2024 10:25:37 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12666014#M943</guid>
      <dc:creator>tbrammer</dc:creator>
      <dc:date>2024-03-26T10:25:37Z</dc:date>
    </item>
    <item>
      <title>Re: Create close polyline from Region</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12666252#M944</link>
      <description>&lt;P&gt;how to deal with PlineSegment ?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;it is giving compile error&lt;/P&gt;</description>
      <pubDate>Tue, 26 Mar 2024 12:16:14 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12666252#M944</guid>
      <dc:creator>jignesh.rana</dc:creator>
      <dc:date>2024-03-26T12:16:14Z</dc:date>
    </item>
    <item>
      <title>Re: Create close polyline from Region</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12666363#M945</link>
      <description>&lt;P&gt;sir i tried your logic and its working but at some points it not match and cze of it&amp;nbsp; polyline created different&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;i attached screenshot for reference and also attach dwg&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="img_20240326.png" style="width: 513px;"&gt;&lt;img src="https://forums.autodesk.com/t5/image/serverpage/image-id/1341956iEB94F0C352906B19/image-size/large?v=v2&amp;amp;px=999" role="button" title="img_20240326.png" alt="img_20240326.png" /&gt;&lt;/span&gt;&lt;/P&gt;</description>
      <pubDate>Tue, 26 Mar 2024 12:59:56 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12666363#M945</guid>
      <dc:creator>jignesh.rana</dc:creator>
      <dc:date>2024-03-26T12:59:56Z</dc:date>
    </item>
    <item>
      <title>Re: Create close polyline from Region</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12666512#M946</link>
      <description>&lt;P&gt;I see. This is an accuracy problem. I didn't expect this.&lt;/P&gt;
&lt;P&gt;If you look at the content of&amp;nbsp;&lt;FONT face="courier new,courier"&gt;std::vector&amp;lt;PlineSegment&amp;gt; segments&lt;/FONT&gt; you will see these values at index 0 and 1:&lt;/P&gt;
&lt;LI-CODE lang="general"&gt;[0]	{p1={x=-30.203451326888171 y=30.376315339599387 } p2={x=-12.919102255473263 y=30.376311689869908 } bulge=...}
[1]	{p1={x=-31.203567541422672 y=30.376309680192207 } p2={x=-30.203451326887865 y=30.376309734909317 } bulge=...}&lt;/LI-CODE&gt;
&lt;P&gt;As you can see&amp;nbsp;&lt;FONT face="courier new,courier"&gt;segments[0].p1&lt;/FONT&gt; and&amp;nbsp;&lt;FONT face="courier new,courier"&gt;segments[1].p2&lt;/FONT&gt;&amp;nbsp;are slightly differnt. The difference is only 0.00001 but seems to be greater than the tolerance specifed in &lt;FONT face="courier new,courier"&gt;AcGeContext::gTol&lt;/FONT&gt;.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You can either raise the tolerance or modify the code so that it looks for the pair of points with the smallest distance, which is the safer way. For example you can add this else-block after &lt;FONT face="courier new,courier"&gt;else if (psPrev.p1 == ps.p2){...}&lt;/FONT&gt;:&lt;/P&gt;
&lt;LI-CODE lang="cpp"&gt;		else
		{
			double d11, d12, d21, d22, *dMin = &amp;amp;d11;
			d11 = psPrev.p1.distanceTo(ps.p1);
			d12 = psPrev.p1.distanceTo(ps.p2);
			if (d12 &amp;lt; *dMin)
				dMin = &amp;amp;d12;
			d21 = psPrev.p2.distanceTo(ps.p1);
			if (d21 &amp;lt; *dMin)
				dMin = &amp;amp;d21;
			d22 = psPrev.p2.distanceTo(ps.p2);
			if (d22 &amp;lt; *dMin)
				dMin = &amp;amp;d22;

			if (dMin == &amp;amp;d21)
			{
				psPrev.reversed = ps.reversed = 1;
				pline-&amp;gt;addVertexAt(ix++, ps.p1, ps.reversed * ps.bulge);
			}
			else if (dMin == &amp;amp;d11)
			{
				ps.reversed = 1;
				psPrev.reversed = -1;
				pline-&amp;gt;addVertexAt(ix++, ps.p1, ps.reversed * ps.bulge);
			}
			else if (dMin == &amp;amp;d22)
			{
				ps.reversed = -1;
				psPrev.reversed = 1;
				pline-&amp;gt;addVertexAt(ix++, ps.p2, ps.reversed * ps.bulge);
			}
			else if (dMin == &amp;amp;d12)
			{
				psPrev.reversed = ps.reversed = -1;
				pline-&amp;gt;addVertexAt(ix++, ps.p2, ps.reversed * ps.bulge);
			}&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 26 Mar 2024 13:51:04 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12666512#M946</guid>
      <dc:creator>tbrammer</dc:creator>
      <dc:date>2024-03-26T13:51:04Z</dc:date>
    </item>
    <item>
      <title>Re: Create close polyline from Region</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12668444#M947</link>
      <description>&lt;P&gt;thanx a lot sir but for single region it is working fine&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;but subtracted or union region is not work with this logic&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;i have attached dwg for sample cases&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;and i got some logic and modified in it i putted epsilon(tolerance) but i don't know for how much put tolerance so from your logic last else block is good thing but its not work with my logic&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;here i wrote that logic&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;DIV&gt;&lt;DIV&gt;AcDbVoidPtrArray PolylineFromRegion(AcDbRegion *reg)&lt;/DIV&gt;&lt;DIV&gt;{&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// We will return a collection of entities&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// (should include closed Polylines and other&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// closed curves, such as Circles)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbVoidPtrArray res;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Explode Region -&amp;gt; collection of Curves / Regions&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;Acad::ErrorStatus es = Acad::eOk;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbVoidPtrArray cvs;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (reg == NULL)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;return res;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;es = reg-&amp;gt;explode(cvs);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Create a plane to convert 3D coords&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// into Region coord system&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGeVector3d vec;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;es = reg-&amp;gt;getNormal(vec);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGePlane *pl = new AcGePlane(AcGePoint3d(0,0,0),vec);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//es = reg-&amp;gt;getPlane(pl);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if(pl != NULL)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;bool finished = false;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;while (!finished &amp;amp;&amp;amp; cvs.length() &amp;gt; 0)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Count the Curves and the non-Curves, and find&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// the index of the first Curve in the collection&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;int cvCnt = 0, nonCvCnt = 0, fstCvIdx = -1;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;for (int i = 0; i &amp;lt; cvs.length(); i++)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbCurve *tmpCv = (AcDbCurve *)cvs.at(i);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//AcGePoint3d stPnt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//tmpCv-&amp;gt;getStartPoint(stPnt);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//pl = new AcGePlane(stPnt,vec);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//if (tmpCv == NULL || tmpCv-&amp;gt;isKindOf(AcDbRegion::desc()) == true)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if(tmpCv == NULL || tmpCv-&amp;gt;isA() == AcDbRegion::desc())&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;nonCvCnt++;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;else&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Closed curves can go straight into the&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// results collection, and aren't added&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// to the Curve count&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (tmpCv-&amp;gt;isClosed())&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;res.append(tmpCv);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;cvs.remove(tmpCv);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Decrement, so we don't miss an item&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;i--;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;else&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;cvCnt++;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (fstCvIdx == -1)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;fstCvIdx = i;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (fstCvIdx &amp;gt;= 0)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// For the initial segment take the first&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Curve in the collection&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbCurve *fstCv = (AcDbCurve *)cvs.at(fstCvIdx);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// The resulting Polyline&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbPolyline *p = new AcDbPolyline();&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Set common entity properties from the Region&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;es = p-&amp;gt;setPropertiesFrom(reg);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Add the first two vertices, but only set the&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// bulge on the first (the second will be set&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// retroactively from the second segment)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// We also assume the first segment is counter-&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// clockwise (the default for arcs), as we're&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// not swapping the order of the vertices to&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// make them fit the Polyline's order&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGePoint3d pntStartPoint;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;fstCv-&amp;gt;getStartPoint(pntStartPoint);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGePoint2d pntStart, pntEnd;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;pntStart.set(pntStartPoint.x, pntStartPoint.y);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;p-&amp;gt;addVertexAt(p-&amp;gt;numVerts(),pntStart,BulgeFromCurve(fstCv, false), 0, 0);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGePoint3d pntEndPoint;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;fstCv-&amp;gt;getEndPoint(pntEndPoint);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;pntEnd.set(pntEndPoint.x, pntEndPoint.y);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;p-&amp;gt;addVertexAt(p-&amp;gt;numVerts(),pntEnd,0, 0, 0);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;cvs.remove(fstCv);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// The next point to look for&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGePoint3d nextPt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;fstCv-&amp;gt;getEndPoint(nextPt);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// We no longer need the curve&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;DeleteEntity(fstCv);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Find the line that is connected to&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// the next point&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// If for some reason the lines returned were not&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// connected, we could loop endlessly.&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// So we store the previous curve count and assume&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// that if this count has not been decreased by&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// looping completely through the segments once,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// then we should not continue to loop.&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Hopefully this will never happen, as the curves&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// should form a closed loop, but anyway...&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Set the previous count as artificially high,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// so that we loop once, at least.&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;int prevCnt = cvs.length() + 1;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;while (cvs.length() &amp;gt; nonCvCnt &amp;amp;&amp;amp; cvs.length() &amp;lt; prevCnt)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;prevCnt = cvs.length();&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//for(INT_PTR i(0);i&amp;lt;prevCnt;++i) //commented on 26-05-2023: as we remove points from cvs so don't take variable(prevCnt) for loop&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;for (INT_PTR i(0); i&amp;lt;cvs.length(); ++i)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbCurve *cv = (AcDbCurve *)cvs.at(i);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (cv != NULL)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// If one end of the curve connects with the&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// point we're looking for...&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGePoint3d StartPt, EndPt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;cv-&amp;gt;getStartPoint(StartPt);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;cv-&amp;gt;getEndPoint(EndPt);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//if (StartPt == nextPt ||EndPt == nextPt)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;double epsilon = 0.00001;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;double dist1 = StartPt.distanceTo(nextPt);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;double dist2 = EndPt.distanceTo(nextPt);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (dist1 &amp;lt;= epsilon || dist2 &amp;lt;= epsilon)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Calculate the bulge for the curve and&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// set it on the previous vertex&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;double bulge = BulgeFromCurve(cv, EndPt == nextPt);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (bulge != 0.0)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;p-&amp;gt;setBulgeAt(p-&amp;gt;numVerts()-1, bulge);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Reverse the points, if needed&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//if (StartPt == nextPt)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if(dist1 &amp;lt;= epsilon)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;nextPt = EndPt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;else&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// cv.EndPoint == nextPt&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;nextPt = StartPt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Add out new vertex (bulge will be set next&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// time through, as needed)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGePoint2d nextTempPt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;nextTempPt.set(nextPt.x,nextPt.y);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;p-&amp;gt;addVertexAt(p-&amp;gt;numVerts(),nextTempPt,0, 0, 0);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Remove our curve from the list, which&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// decrements the count, of course&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;cvs.remove(cv);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;DeleteEntity(cv);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//break;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;i--;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Once we have added all the Polyline's vertices,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// transform it to the original region's plane&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcGeMatrix3d mat = AcGeMatrix3d::planeToWorld(pl-&amp;gt;normal());&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;p-&amp;gt;transformBy(mat);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//RemoveSameVertex(p);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;res.append(p);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (cvs.length() == nonCvCnt)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;finished = true;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// If there are any Regions in the collection,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// recurse to explode and add their geometry&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (nonCvCnt &amp;gt; 0 &amp;amp;&amp;amp; cvs.length() &amp;gt; 0)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;INT_PTR iLen = cvs.length();&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;for(INT_PTR j(0);j&amp;lt;cvs.length();++j)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbRegion *subReg = (AcDbRegion *)cvs.at(j);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbVoidPtrArray cvs1;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;//es = subReg-&amp;gt;explode(cvs1);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (subReg != NULL)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbVoidPtrArray subRes = PolylineFromRegion(subReg);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;for(INT_PTR k(0);k&amp;lt;subRes.length();++k)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;res.append(subRes.at(k));&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;cvs.remove(subReg);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;DeleteEntity(subReg); &lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (cvs.length() == 0)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;finished = true;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;return res;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;}&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;DIV&gt;double BulgeFromCurve(AcDbCurve *cv,bool clockwise)&lt;/DIV&gt;&lt;DIV&gt;{&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;double bulge = 0.0;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;AcDbArc *a = (AcDbArc *)cv;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (a != NULL)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;{&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;double newStart;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// The start angle is usually greater than the end,&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// as arcs are all counter-clockwise.&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// (If it isn't it's because the arc crosses the&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// 0-degree line, and we can subtract 2PI from the&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// start angle.)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (a-&amp;gt;startAngle() &amp;gt; a-&amp;gt;endAngle())&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;newStart = a-&amp;gt;startAngle() - 8 * atan(double(1));// * Math::Atan(1);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;else&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;newStart = a-&amp;gt;startAngle();&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// Bulge is defined as the tan of&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// one fourth of the included angle&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;bulge = tan((a-&amp;gt;endAngle() - newStart) / 4);&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;// If the curve is clockwise, we negate the bulge&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;if (clockwise)&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;bulge = -bulge;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;}&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;&lt;SPAN&gt;return bulge;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;DIV&gt;}&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;</description>
      <pubDate>Wed, 27 Mar 2024 07:38:29 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12668444#M947</guid>
      <dc:creator>jignesh.rana</dc:creator>
      <dc:date>2024-03-27T07:38:29Z</dc:date>
    </item>
    <item>
      <title>Re: Create close polyline from Region</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12668749#M948</link>
      <description>&lt;P&gt;The algorithm was designed for an &lt;FONT face="courier new,courier"&gt;AcDbRegion&lt;/FONT&gt; that has exactly one face and no holes. It expects exactly one "outer loop". When you explode() an&amp;nbsp;&lt;FONT face="courier new,courier"&gt;AcDbRegion&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;that has N faces, the results are N &lt;FONT face="courier new,courier"&gt;AcDbRegion&lt;/FONT&gt;s that must be processed each.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I stated that I'm not 100% sure whether it is guaranteed, that the explosion fragments appear in the right order.&lt;/P&gt;
&lt;P&gt;I'm also not sure whether the fragments of a region with holes or multiple faces will appear in a defined order.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If you want to analyze these regions I would recommend to use the BREP API. It allows to iterate over outer and inner loops in a region.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The following code is not optimized but it works. Basically it implements&lt;/P&gt;
&lt;LI-CODE lang="cpp"&gt;void BuildLoops(
    std::vector&amp;lt;PlineSegment&amp;gt; &amp;amp;segments, 
    std::vector&amp;lt; std::vector&amp;lt;int&amp;gt; &amp;gt;&amp;amp; loops, 
    double minGap
);&lt;/LI-CODE&gt;
&lt;P&gt;It calculates "loops" which are arrays of indices of connected &lt;FONT face="courier new,courier"&gt;PlineSegment&lt;/FONT&gt;s.&lt;/P&gt;
&lt;P&gt;It would be more effective to explode a multi-face loop to multiple&amp;nbsp;&lt;FONT face="courier new,courier"&gt;vector&amp;lt;PlineSegment&amp;gt;&lt;/FONT&gt; arrays.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-CODE lang="cpp"&gt;struct PlineSegment {
	AcGePoint2d p1, p2;
	double bulge=0.0;
	int   reversed=0; // 0 unknown, -1 reversed, 1 not reversed
	bool  inserted=false;
};

// MyRegion2Pline, R2P
void BuildLoops(std::vector&amp;lt;PlineSegment&amp;gt; &amp;amp;segments, std::vector&amp;lt; std::vector&amp;lt;int&amp;gt; &amp;gt;&amp;amp; loops, double minGap)
{
	int i, N = (int)segments.size();	
	std::vector&amp;lt;int&amp;gt; loop;
	bool bInserted = false;
	do 
	{
		bInserted = false;
		for (i = 0; i &amp;lt; N; ++i)
		{
			if (segments[i].inserted)
				continue;
			if (loop.empty())
			{
				loop.push_back(i);
				segments[i].inserted = true;
			}
			else
			{
				PlineSegment&amp;amp; psPrev = segments[loop.back()];
				PlineSegment&amp;amp; ps = segments[i];
				if (ps.inserted)
					continue;
				double d11, d12, d21, d22, *dMin = &amp;amp;d11;
				d11 = psPrev.p1.distanceTo(ps.p1);
				d12 = psPrev.p1.distanceTo(ps.p2);
				if (d12 &amp;lt; *dMin)
					dMin = &amp;amp;d12;
				d21 = psPrev.p2.distanceTo(ps.p1);
				if (d21 &amp;lt; *dMin)
					dMin = &amp;amp;d21;
				d22 = psPrev.p2.distanceTo(ps.p2);
				if (d22 &amp;lt; *dMin)
					dMin = &amp;amp;d22;

				if (*dMin &amp;lt; minGap)
				{
					loop.push_back(i);
					ps.inserted = true;

					if (dMin == &amp;amp;d21)
					{
						psPrev.reversed = ps.reversed = 1;
					}
					else if (dMin == &amp;amp;d11)
					{
						ps.reversed = 1;
						psPrev.reversed = -1;
					}
					else if (dMin == &amp;amp;d22)
					{
						ps.reversed = -1;
						psPrev.reversed = 1;
					}
					else if (dMin == &amp;amp;d12)
					{
						psPrev.reversed = ps.reversed = -1;
					}

					// Is the loop closed now?
					PlineSegment&amp;amp; psStart = segments[loop.front()];
					const AcGePoint2d&amp;amp; ptStart = (psStart.reversed &amp;gt; 0) ? psStart.p1 : psStart.p2;
					const AcGePoint2d&amp;amp; pt = (ps.reversed&amp;gt;0) ? ps.p2 : ps.p1;
					double d = ptStart.distanceTo(pt);
					if (d &amp;lt; minGap)
					{
						// Yes! Start a new loop
						loops.push_back(std::move(loop));
						loop.clear();
					}
					bInserted = true;
					break; // exit for(j..) loop
				}
			}
		}
	}
	while (bInserted);
}


void cmdRegion2Pline()
{
	ads_point    pt;
	ads_name     ent;
	AcDbObjectId idRegion;

	if (acedEntSel(_T("\nSelect region"), ent, pt) != RTNORM)
		return;

	if (acdbGetObjectId(idRegion, ent) != Acad::eOk)
		return;

	Acad::ErrorStatus es;
	AcDbVoidPtrArray curves;
	AcDbRegion* region;
	AcGePlane regionPlane;
	if ((es = acdbOpenObject(region, idRegion, AcDb::kForRead)) == Acad::eOk)
	{
		region-&amp;gt;getPlane(regionPlane);
		region-&amp;gt;explode(curves);
		region-&amp;gt;close();

		// AcDbRegions with multiple faces will create single-face regions upon explode
		AcDbVoidPtrArray curvesFromSubregions;
		int i, N = curves.length();
		for (i = 0; i &amp;lt; N; ++i)
		{
			AcDbObject *obj = (AcDbObject*)curves[i];
			AcDbRegion *rg;
			if (rg = AcDbRegion::cast(obj))
			{
				AcDbVoidPtrArray curves2;
				rg-&amp;gt;explode(curves2);
				curvesFromSubregions.append(curves2);
				delete obj;
				curves.removeAt(i--);
				--N;
			}
		}
		curves.append(curvesFromSubregions);
	}

	AcGePoint3d origin;
	AcGeVector3d axis1, axis2, norm(regionPlane.normal());
	regionPlane.getCoordSystem(origin, axis1, axis2);
	// Recalculate origin to be the closest point on the plane
	double dp = origin.asVector().dotProduct(norm);
	origin = AcGePoint3d::kOrigin + dp * norm;

	AcGeMatrix3d mat_WCS_ECS, mat_ECS_WCS;
	mat_WCS_ECS.setCoordSystem(origin, axis1, axis2, norm);
	mat_ECS_WCS = mat_WCS_ECS.inverse();

	int i, j, N = curves.length();
	AcDbObject* obj;
	AcDbCurve* crv;
	AcDbArc* arc;
	AcGePoint3d ps, pe;
	double angle = 0.0;
	std::vector&amp;lt;PlineSegment&amp;gt; segments;
	PlineSegment segment;
	// Collect segment data:
	for (i = 0; i &amp;lt; N; ++i)
	{
		obj = (AcDbObject*)curves[i];
		if (crv = AcDbCurve::cast(obj))
		{
			crv-&amp;gt;getStartPoint(ps);
			crv-&amp;gt;getEndPoint(pe);
			// Transform to ECS. After this z-components should be 0
			ps.transformBy(mat_ECS_WCS);
			pe.transformBy(mat_ECS_WCS);
			segment.p1 = AcGePoint2d(ps.x, ps.y);
			segment.p2 = AcGePoint2d(pe.x, pe.y);
			if (segment.p1 != segment.p2) // don't add coincident points.
			{
				if (arc = AcDbArc::cast(obj))
					segment.bulge = tan(0.25 * arc-&amp;gt;totalAngle());
				else
					segment.bulge = 0.0;
			}
			segments.push_back(segment);
		}
		delete obj;
	}

	AcDbDatabase* pDB = acdbHostApplicationServices()-&amp;gt;workingDatabase();
	double minGap = 1000 * AcGeContext::gTol.equalPoint();
	std::vector&amp;lt; std::vector&amp;lt;int&amp;gt; &amp;gt; loops;
	BuildLoops(segments, loops, minGap);
	for (const std::vector&amp;lt;int&amp;gt; &amp;amp;loop : loops)
	{
		AcDbPolyline* pline = new AcDbPolyline();
		pline-&amp;gt;setDatabaseDefaults(pDB);
		unsigned int ix = 0;
		for (int i : loop)
		{
			const PlineSegment&amp;amp; ps = segments[i];
			pline-&amp;gt;addVertexAt(ix++, ps.reversed ? ps.p2:ps.p1, ps.reversed * ps.bulge);
		}
		pline-&amp;gt;setClosed(true);
		pline-&amp;gt;transformBy(mat_WCS_ECS);
		PostToDb(pDB, pline);
	}
}
&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 27 Mar 2024 10:15:54 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12668749#M948</guid>
      <dc:creator>tbrammer</dc:creator>
      <dc:date>2024-03-27T10:15:54Z</dc:date>
    </item>
    <item>
      <title>Re: Create close polyline from Region</title>
      <link>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12677165#M949</link>
      <description>&lt;P&gt;I have implemented a solution based on the BREP API. It is attached in Region2Pline.zip. This solution also works well for regions with multiple faces and holes.&amp;nbsp; You should be able to build the project out of the box. It is written for ObjectARX 2024. Just adjust the path&amp;nbsp;&lt;FONT face="courier new,courier"&gt;&amp;lt;ArxSdkDir&amp;gt;X:\ObjectARX 2024\&amp;lt;/ArxSdkDir&amp;gt;&amp;nbsp;&lt;/FONT&gt;in&amp;nbsp;Autodesk.arx-2022.props to your own ARX directory.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The ARX implements the command "R2P" =&amp;gt;&amp;nbsp;&lt;FONT face="courier new,courier"&gt;void cmdR2P()&lt;/FONT&gt;.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;It uses the BREP API to fill a &lt;FONT face="courier new,courier"&gt;std::vector&amp;lt;OuterLoopWithHoles&amp;gt;&lt;/FONT&gt;:&lt;/P&gt;
&lt;LI-CODE lang="cpp"&gt;class CurveSegment {
public:
	AcDbFullSubentPath subentPath;
	AcGePoint3d ptStart;
	double bulge = 0.0;
};

class OuterLoopWithHoles {
public:
	std::vector&amp;lt;CurveSegment&amp;gt; OuterLoop;  // 1..N outer shapes of the region
	std::vector &amp;lt; std::vector&amp;lt;CurveSegment&amp;gt; &amp;gt; InnerLoops; // 0..M holes
};
&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;By changing the static variable&amp;nbsp; &lt;FONT face="courier new,courier"&gt;static bool bCreatePline&lt;/FONT&gt;&amp;nbsp; you can choose whether you want to create polylines from &lt;FONT face="courier new,courier"&gt;ptsStart&lt;/FONT&gt; and &lt;FONT face="courier new,courier"&gt;bulge&lt;/FONT&gt; or arcs and lines per segment based on &lt;FONT face="courier new,courier"&gt;subentPath&lt;/FONT&gt;.&lt;/P&gt;</description>
      <pubDate>Sun, 31 Mar 2024 11:25:13 GMT</pubDate>
      <guid>https://forums.autodesk.com/t5/objectarx-forum/create-close-polyline-from-region/m-p/12677165#M949</guid>
      <dc:creator>tbrammer</dc:creator>
      <dc:date>2024-03-31T11:25:13Z</dc:date>
    </item>
  </channel>
</rss>

