Thư viện TryCombine
1 Thêm class TryCombineExts.cs
Lưu mã sau dưới dạng tệp tin TryCombineExts.cs
Code:
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AJS_TryCombine
{
static class TryCombineExts
{
public static DBObjectCollection TryCombine(this DBObjectCollection cvs, bool samelayer = false, double tol = 1e-5)
{
DBObjectCollection res = new DBObjectCollection();
if (cvs.Count < 2) return cvs;
// Explode Region -> collection of Curves / Regions
// Create a plane to convert 3D coords
// into Region coord system
bool finished = false;
while (!finished && cvs.Count > 0)
{
// Count the Curves and the non-Curves, and find
// the index of the first Curve in the collection
int cvCnt = 0, nonCvCnt = 0, fstCvIdx = -1;
for (int i = 0; i < cvs.Count; i++)
{
Curve tmpCv = cvs[i] as Curve;
if (tmpCv == null)
nonCvCnt++;
else
{
if (tmpCv.Closed || tmpCv.StartPoint.DistanceTo(tmpCv.EndPoint) < tol)
{
res.Add(tmpCv);
cvs.Remove(tmpCv);
// Decrement, so we don't miss an item
i--;
}
else
{
cvCnt++;
if (fstCvIdx == -1) fstCvIdx = i;
}
}
}
if (fstCvIdx >= 0)
{
// For the initial segment take the first
// Curve in the collection
Curve fstCv = (Curve)cvs[fstCvIdx];
// The resulting Polyline
Polyline p = new Polyline();
p.XData = fstCv.XData;
//fstCv.CopyPropertiesTo(p);
// Set common entity properties from the Region
// Add the first two vertices, but only set the
// bulge on the first (the second will be set
// retroactively from the second segment)
// We also assume the first segment is counter-
// clockwise (the default for arcs), as we're
// not swapping the order of the vertices to
// make them fit the Polyline's order
//EDs.Princ(fstCv.StartPoint.ToString() + " d2=" + fstCv.StartPoint.To2d());
p.AddVertexAt(p.NumberOfVertices, fstCv.StartPoint.To2d(), BulgeFromCurve(fstCv, false), 0, 0);
p.AddVertexAt(p.NumberOfVertices, fstCv.EndPoint.To2d(), 0, 0, 0);
cvs.Remove(fstCv);
// The next point to look for
Point3d nextPt = fstCv.EndPoint;
// We no longer need the curve
//try
{
if (fstCv.Layer != "" && fstCv.LayerId != ObjectId.Null) p.LayerId = fstCv.LayerId;
if (fstCv.ColorIndex >= 0 && fstCv.ColorIndex <= 256) p.ColorIndex = fstCv.ColorIndex;
p.LineWeight = fstCv.LineWeight;
}
//catch { }
//fstCv.Dispose();
// Find the line that is connected to
// the next point
// If for some reason the lines returned were not
// connected, we could loop endlessly.
// So we store the previous curve count and assume
// that if this count has not been decreased by
// looping completely through the segments once,
// then we should not continue to loop.
// Hopefully this will never happen, as the curves
// should form a closed loop, but anyway...
// Set the previous count as artificially high,
// so that we loop once, at least.
int prevCnt = cvs.Count + 1;
while (cvs.Count > nonCvCnt && cvs.Count < prevCnt)
{
prevCnt = cvs.Count;
foreach (DBObject obj in cvs)
{
Curve cv = obj as Curve;
if (cv != null && (!samelayer || cv.Layer == p.Layer))
{
// If one end of the curve connects with the
// point we're looking for...
if (cv.StartPoint.Equal(nextPt, tol) || cv.EndPoint.Equal(nextPt, tol))
{
// Calculate the bulge for the curve and
// set it on the previous vertex
double bulge = BulgeFromCurve(cv, cv.EndPoint.Equal(nextPt, tol));
if (bulge != 0.0) p.SetBulgeAt(p.NumberOfVertices - 1, bulge);
// Reverse the points, if needed
if (cv.StartPoint.Equal(nextPt, tol))
nextPt = cv.EndPoint;
else
// cv.EndPoint == nextPt
nextPt = cv.StartPoint;
// Add out new vertex (bulge will be set next
// time through, as needed)
p.AddVertexAt(p.NumberOfVertices, nextPt.To2d(), 0, 0, 0);
// Remove our curve from the list, which
// decrements the count, of course
cvs.Remove(cv);
//cv.Dispose();
break;
}
}
}
}
p.ReverseCurve();
nextPt = p.EndPoint;
// We no longer need the curve
// Find the line that is connected to
// the next point
// If for some reason the lines returned were not
// connected, we could loop endlessly.
// So we store the previous curve count and assume
// that if this count has not been decreased by
// looping completely through the segments once,
// then we should not continue to loop.
// Hopefully this will never happen, as the curves
// should form a closed loop, but anyway...
// Set the previous count as artificially high,
// so that we loop once, at least.
prevCnt = cvs.Count + 1;
while (cvs.Count > nonCvCnt && cvs.Count < prevCnt)
{
prevCnt = cvs.Count;
foreach (DBObject obj in cvs)
{
Curve cv = obj as Curve;
if (cv != null && (!samelayer || cv.Layer == p.Layer))
{
// If one end of the curve connects with the
// point we're looking for...
if (cv.StartPoint.Equal(nextPt, tol) || cv.EndPoint.Equal(nextPt, tol))
{
// Calculate the bulge for the curve and
// set it on the previous vertex
double bulge = BulgeFromCurve(cv, cv.EndPoint.Equal(nextPt, tol));
if (bulge != 0.0) p.SetBulgeAt(p.NumberOfVertices - 1, bulge);
// Reverse the points, if needed
if (cv.StartPoint.Equal(nextPt, tol))
nextPt = cv.EndPoint;
else
// cv.EndPoint == nextPt
nextPt = cv.StartPoint;
// Add out new vertex (bulge will be set next
// time through, as needed)
p.AddVertexAt(p.NumberOfVertices, nextPt.To2d(), 0, 0, 0);
// Remove our curve from the list, which
// decrements the count, of course
cvs.Remove(cv);
//cv.Dispose();
break;
}
}
}
}
// Once we have added all the Polyline's vertices,
// transform it to the original region's plane
//p.TransformBy(Matrix3d.PlaneToWorld(pl));
p.ReverseCurve();
res.Add(p);
if (cvs.Count == nonCvCnt) finished = true;
}
// If there are any Regions in the collection,
// recurse to explode and add their geometry
if (nonCvCnt > 0 && cvs.Count > 0)
{
foreach (DBObject obj in cvs)
{
Region subReg = obj as Region;
if (subReg != null)
{
foreach (Entity e in subReg.ToPolylines())
res.Add(e);
cvs.Remove(subReg);
//subReg.Dispose();
}
}
}
if (cvs.Count == 0) finished = true;
}
return res;
}
public static Point2d To2d(this Point3d p)
{
return new Point2d(p.X, p.Y);
}
public static bool Equal(this Point3d pt, Point3d thatpt, double tol = 0.000001)
=> pt.DistanceTo(thatpt) < tol;
public static double BulgeFromCurve(this Curve cv, bool clockwise)
{
double bulge = 0.0;
Arc a = cv as Arc;
if (a != null)
{
double newStart;
// The start angle is usually greater than the end,
// as arcs are all counter-clockwise.
// (If it isn't it's because the arc crosses the
// 0-degree line, and we can subtract 2PI from the
// start angle.)
if (a.StartAngle > a.EndAngle)
newStart = a.StartAngle - 8 * Math.Atan(1);
else
newStart = a.StartAngle;
// Bulge is defined as the tan of
// one fourth of the included angle
bulge = Math.Tan((a.EndAngle - newStart) / 4);
// If the curve is clockwise, we negate the bulge
if (clockwise) bulge = -bulge;
}
return bulge;
}
}
}
Cách dùng
1 Thêm class cmdTryCombine.cs
Lưu mã sau dưới dạng tệp tin cmdTryCombine.cs
Code:
// (C) Copyright 2024 by
//
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.Linq;
// This line is not mandatory, but improves loading performances
[assembly: CommandClass(typeof(AJS_TryCombine.MyCommands))]
namespace AJS_TryCombine
{
// This class is instantiated by AutoCAD for each document when
// a command is called by the user the first time in the context
// of a given document. In other words, non static data in this class
// is implicitly per-document!
public class MyCommands
{
// Modal Command with localized name
[CommandMethod("TryCombine", CommandFlags.Modal)]
public void MyCommand_TryCombine() // This method can have any name
{
// Put your command code here
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc != null)
{
var ed = doc.Editor;
ed.WriteMessage("Hello, this is your first command. Create by www.lisp.vn");
var psr = ed.GetSelection(new SelectionFilter(new TypedValue[] { new TypedValue(0, "*line,arc") }));
if (psr.Status != PromptStatus.OK) return;
var ids = psr.Value.GetObjectIds().ToList();
using (var tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
{
var ents = ids.Select(x => tr.GetObject(x, OpenMode.ForWrite, false, true) as Entity).ToList();
var cvs = new DBObjectCollection();
foreach (var ent in ents)
{
if (ent is Arc || ent is Line)
cvs.Add(ent.Clone() as Curve);
else
{
var dbs = new DBObjectCollection();
ent.Explode(dbs);
foreach (Entity e in dbs)
if (e is Arc || e is Line)
cvs.Add(e as Curve);
}
}
var btr = tr.GetObject(HostApplicationServices.WorkingDatabase.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
var pls = cvs.TryCombine();
foreach (Curve pl in pls)
{
btr.AppendEntity(pl);
tr.AddNewlyCreatedDBObject(pl, true);
}
tr.Commit();
}
}
}
}
}Link tải Solution
Nhóm AutoCAD dotNet
Link tham gia nhóm Zalo: http://dnz.lisp.vn
---------------------------------------------------------------------------------------------
Mọi thông tin xin liên hệ Fanpage AutoLISP Thật là đơn giản!
Cảm ơn bạn đã theo dõi!
Không có nhận xét nào:
Đăng nhận xét