The following Polyline3d.ToPolyline() extension method returns a new instance of Polyline if the Polyline3d is planar.
public static class ExtensionMethods
{
/// <summary>
/// Gets the vertices of a polyline 3d.
/// </summary>
/// <param name="pline3d">The instance this method applies to.</param>
/// <returns>The collection of vertices positions (SimpleVertex or FitVertex).</returns>
public static Point3dCollection GetVertices(this Polyline3d pline3d)
{
if (pline3d == null)
throw new ArgumentNullException(nameof(pline3d));
var points = new Point3dCollection();
using (var tr = pline3d.Database.TransactionManager.StartOpenCloseTransaction())
{
foreach (ObjectId id in pline3d)
{
var vx = (PolylineVertex3d)tr.GetObject(id, OpenMode.ForRead);
if (vx.VertexType != Vertex3dType.ControlVertex)
points.Add(vx.Position);
}
tr.Commit();
}
return points;
}
/// <summary>
/// Evaluates if the points lies on a single plane.
/// </summary>
/// <param name="points">The instance this method applies to.</param>
/// <param name="normal">Normal of the plane.</param>
/// <returns></returns>
public static bool IsPlanar(this Point3dCollection points, out Vector3d normal)
{
if (points == null)
throw new ArgumentNullException(nameof(points));
normal = new Vector3d();
if (points.Count < 3)
return false;
var v = points[0].GetVectorTo(points[1]);
var u = new Vector3d();
bool found = false;
for (int i = 2; i < points.Count; i++)
{
u = points[0].GetVectorTo(points[i]);
if (!u.IsParallelTo(v))
{
found = true;
break;
}
}
if (!found)
return false;
normal = v.CrossProduct(u).GetNormal();
var plane = new Plane(points[0], normal);
double d = Tolerance.Global.EqualPoint;
return points.Cast<Point3d>().All(p => Math.Abs(plane.GetSignedDistanceTo(p)) <= d);
}
/// <summary>
/// Gets a Polyline from the Polyline3d.
/// An exception is thrown if the Polyline3d vertices do not define a single plane.
/// </summary>
/// <param name="pline3d">The instance this method applies to.</param>
/// <returns>A new Polyline instance.</returns>
public static Polyline ToPolyline(this Polyline3d pline3d)
{
if (pline3d == null)
throw new ArgumentNullException(nameof(pline3d));
Vector3d normal;
var points = pline3d.GetVertices();
if (!points.IsPlanar(out normal))
throw new InvalidOperationException("The Polyline3d does not define a single plane.");
var plane = new Plane(Point3d.Origin, normal);
var pline = new Polyline(points.Count);
for (int i = 0; i < points.Count; i++)
{
pline.AddVertexAt(i, points[i].Convert2d(plane), 0.0, 0.0, 0.0);
}
pline.Normal = normal;
pline.Elevation = points[0].TransformBy(Matrix3d.WorldToPlane(plane)).Z;
pline.Closed = pline3d.Closed;
return pline;
}
}
Testing example:
[CommandMethod("TEST")]
public void Polyline3dToPolyline()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var peo = new PromptEntityOptions("\nSelect a 3D polyline: ");
peo.SetRejectMessage("\nSelected object is not a 3D polyline.");
peo.AddAllowedClass(typeof(Polyline3d), true);
var per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
using (var tr = db.TransactionManager.StartTransaction())
{
var pl3d = (Polyline3d)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
var space = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
try
{
var pline = pl3d.ToPolyline();
pline.SetDatabaseDefaults();
space.AppendEntity(pline);
tr.AddNewlyCreatedDBObject(pline, true);
pl3d.Erase();
}
catch (System.Exception ex)
{
Application.ShowAlertDialog(ex.Message);
}
tr.Commit();
}
}