SEANT
26th Jun 2010, 12:32 pm
Here is a prototype C# routine to create a point at the center of gravity of a selection set of lines and/or polylines (without bulges).
This example code is in response to the query made in this thread:
http://www.cadtutor.net/forum/showthread.php?t=48143
Limited testing. Use sensible precaution!
To run:
unzip lcog.zip
In AutoCAD:
Command: netload
(navigate to, and load file LCOG.dll)
Command: LCOG
Select linear elements:
// Written by Sean Tessier June 25 2010
// Rev1 - Bug fix June 27 2010
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
[assembly: CommandClass(typeof(LinesCOG.CTCommands))]
namespace LinesCOG
{
public class CTCommands
{
public CTCommands()
{
}
[CommandMethod("LCOG")]
static public void LCOGinit()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Edit or;
Database db = HostApplicationServices.WorkingDatabase;
ObjectIdCollection oidColl = new ObjectIdCollection();
WeightedMidCollection wmc = new WeightedMidCollection();
PromptSelectionOptions pso = new PromptSelectionOptions();
pso.MessageForAdding = "\nSelect linear elements: ";
pso.SinglePickInSpace = true;
pso.SingleOnly = true;
Vector3d v3d = new Vector3d(0.0, 0.0, 1.0);
//Only process lines and polylines with an elevation of 0
TypedValue[] filter = { new TypedValue(-4, "<or"),
new TypedValue(0, "LINE"),
new TypedValue(-4, "<and"),
new TypedValue(0, "LWPOLYLINE"),
new TypedValue(38, 0),
new TypedValue(-4, "and>"),
new TypedValue(-4, "or>")
};
SelectionFilter selFilter = new SelectionFilter(filter);
bool Canceled = false;
using (Transaction trans = db.TransactionManager.StartTransaction())
{
do
{
PromptSelectionResult result = ed.GetSelection(pso, selFilter);
if (result.Status == PromptStatus.OK)
{
ObjectId[] oids = result.Value.GetObjectIds();
foreach (ObjectId oid in oids)
{
if (!oidColl.Contains(oid))
{
oidColl.Add(oid);
Line ln = trans.GetObject(oid, OpenMode.ForRead) as Line;
if (ln != null)
{
Point3d stpt = ln.StartPoint;
Point3d ndpt = ln.EndPoint;
if (stpt.Z == 0.0 && ndpt.Z == 0.0)//only process lines on the WCS XY
{
ln.Highlight();
WeightedMid wm = new WeightedMid(new Point2d(ln.StartPoint.X, ln.StartPoint.Y),
new Point2d(ln.EndPoint.X, ln.EndPoint.Y));
wmc.Add(wm);
}
}
else
{
Polyline pln = trans.GetObject(oid, OpenMode.ForRead) as Polyline;
if (pln != null && !pln.HasBulges)//exclude polylines with bulges
{
for (int i = 0; i < pln.NumberOfVertices - 1; i++)
{
WeightedMid wm = new WeightedMid(pln.GetPoint2dAt(i), pln.GetPoint2dAt(i + 1));
wmc.Add(wm);
}
pln.Highlight();
if (!oidColl.Contains(oid)) oidColl.Add(oid);
}
}
}
}
ed.WriteMessage("\nPocessing " + oidColl.Count.ToString() + " linear elements");
}
else Canceled = true;
} while (!Canceled);
if (oidColl.Count == 0) return;
wmc.ProccessMids();
if (wmc.IsValid)
{
try
{
DBPoint COGpt = new DBPoint(wmc.COG);
BlockTableRecord btr = (BlockTableRecord)(trans.GetObject(db.CurrentSpace Id, OpenMode.ForWrite));
btr.AppendEntity(COGpt);
trans.AddNewlyCreatedDBObject(COGpt, true);
}
catch
{
ed.WriteMessage("\nExecution Error: Operation cancelled!");
}
finally
{
foreach (ObjectId oid in oidColl)//remove highlighting
{
Entity ent = trans.GetObject(oid, OpenMode.ForRead) as Entity;
ent.Unhighlight();
}
}
}
else ed.WriteMessage("\nOperation aborted!");
trans.Commit();
}
}
}
struct WeightedMid //Process individual lines
{
//fields
public double X;
public double Y;
public double MomentX;
public double MomentY;
public double length;
//Constructor
public WeightedMid(Point2d StartPoint, Point2d EndPoint)
{
X = (StartPoint.X + EndPoint.X) / 2.0;
Y = (StartPoint.Y + EndPoint.Y) / 2.0;
length = StartPoint.GetDistanceTo(EndPoint);
MomentX = length * X;
MomentY = length * Y;
}
}
class WeightedMidCollection : List<WeightedMid> //Process lines as a collection
{
//Fields
private double m_totLength;
private Point3d m_cog;
private double m_combinedXMoments;
private double m_combinedYMoments;
private bool m_isValid = false;
//Constructor
public WeightedMidCollection()
{
}
//Properties
public Point3d COG
{
get { return m_cog; }
}
public bool IsValid
{
get { return m_isValid; }
}
//Methods
public void ProccessMids()
{
foreach (WeightedMid wm in this)
{
m_totLength += wm.length;
m_combinedXMoments += wm.MomentX;
m_combinedYMoments += wm.MomentY;
}
try
{
m_cog = new Point3d(m_combinedXMoments / m_totLength, m_combinedYMoments / m_totLength, 0.0);
m_isValid = true;
}
catch
{
m_isValid = false;
}
}
}
}
This example code is in response to the query made in this thread:
http://www.cadtutor.net/forum/showthread.php?t=48143
Limited testing. Use sensible precaution!
To run:
unzip lcog.zip
In AutoCAD:
Command: netload
(navigate to, and load file LCOG.dll)
Command: LCOG
Select linear elements:
// Written by Sean Tessier June 25 2010
// Rev1 - Bug fix June 27 2010
using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
[assembly: CommandClass(typeof(LinesCOG.CTCommands))]
namespace LinesCOG
{
public class CTCommands
{
public CTCommands()
{
}
[CommandMethod("LCOG")]
static public void LCOGinit()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Edit or;
Database db = HostApplicationServices.WorkingDatabase;
ObjectIdCollection oidColl = new ObjectIdCollection();
WeightedMidCollection wmc = new WeightedMidCollection();
PromptSelectionOptions pso = new PromptSelectionOptions();
pso.MessageForAdding = "\nSelect linear elements: ";
pso.SinglePickInSpace = true;
pso.SingleOnly = true;
Vector3d v3d = new Vector3d(0.0, 0.0, 1.0);
//Only process lines and polylines with an elevation of 0
TypedValue[] filter = { new TypedValue(-4, "<or"),
new TypedValue(0, "LINE"),
new TypedValue(-4, "<and"),
new TypedValue(0, "LWPOLYLINE"),
new TypedValue(38, 0),
new TypedValue(-4, "and>"),
new TypedValue(-4, "or>")
};
SelectionFilter selFilter = new SelectionFilter(filter);
bool Canceled = false;
using (Transaction trans = db.TransactionManager.StartTransaction())
{
do
{
PromptSelectionResult result = ed.GetSelection(pso, selFilter);
if (result.Status == PromptStatus.OK)
{
ObjectId[] oids = result.Value.GetObjectIds();
foreach (ObjectId oid in oids)
{
if (!oidColl.Contains(oid))
{
oidColl.Add(oid);
Line ln = trans.GetObject(oid, OpenMode.ForRead) as Line;
if (ln != null)
{
Point3d stpt = ln.StartPoint;
Point3d ndpt = ln.EndPoint;
if (stpt.Z == 0.0 && ndpt.Z == 0.0)//only process lines on the WCS XY
{
ln.Highlight();
WeightedMid wm = new WeightedMid(new Point2d(ln.StartPoint.X, ln.StartPoint.Y),
new Point2d(ln.EndPoint.X, ln.EndPoint.Y));
wmc.Add(wm);
}
}
else
{
Polyline pln = trans.GetObject(oid, OpenMode.ForRead) as Polyline;
if (pln != null && !pln.HasBulges)//exclude polylines with bulges
{
for (int i = 0; i < pln.NumberOfVertices - 1; i++)
{
WeightedMid wm = new WeightedMid(pln.GetPoint2dAt(i), pln.GetPoint2dAt(i + 1));
wmc.Add(wm);
}
pln.Highlight();
if (!oidColl.Contains(oid)) oidColl.Add(oid);
}
}
}
}
ed.WriteMessage("\nPocessing " + oidColl.Count.ToString() + " linear elements");
}
else Canceled = true;
} while (!Canceled);
if (oidColl.Count == 0) return;
wmc.ProccessMids();
if (wmc.IsValid)
{
try
{
DBPoint COGpt = new DBPoint(wmc.COG);
BlockTableRecord btr = (BlockTableRecord)(trans.GetObject(db.CurrentSpace Id, OpenMode.ForWrite));
btr.AppendEntity(COGpt);
trans.AddNewlyCreatedDBObject(COGpt, true);
}
catch
{
ed.WriteMessage("\nExecution Error: Operation cancelled!");
}
finally
{
foreach (ObjectId oid in oidColl)//remove highlighting
{
Entity ent = trans.GetObject(oid, OpenMode.ForRead) as Entity;
ent.Unhighlight();
}
}
}
else ed.WriteMessage("\nOperation aborted!");
trans.Commit();
}
}
}
struct WeightedMid //Process individual lines
{
//fields
public double X;
public double Y;
public double MomentX;
public double MomentY;
public double length;
//Constructor
public WeightedMid(Point2d StartPoint, Point2d EndPoint)
{
X = (StartPoint.X + EndPoint.X) / 2.0;
Y = (StartPoint.Y + EndPoint.Y) / 2.0;
length = StartPoint.GetDistanceTo(EndPoint);
MomentX = length * X;
MomentY = length * Y;
}
}
class WeightedMidCollection : List<WeightedMid> //Process lines as a collection
{
//Fields
private double m_totLength;
private Point3d m_cog;
private double m_combinedXMoments;
private double m_combinedYMoments;
private bool m_isValid = false;
//Constructor
public WeightedMidCollection()
{
}
//Properties
public Point3d COG
{
get { return m_cog; }
}
public bool IsValid
{
get { return m_isValid; }
}
//Methods
public void ProccessMids()
{
foreach (WeightedMid wm in this)
{
m_totLength += wm.length;
m_combinedXMoments += wm.MomentX;
m_combinedYMoments += wm.MomentY;
}
try
{
m_cog = new Point3d(m_combinedXMoments / m_totLength, m_combinedYMoments / m_totLength, 0.0);
m_isValid = true;
}
catch
{
m_isValid = false;
}
}
}
}