using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.Civil.DatabaseServices;
using Autodesk.Civil.DatabaseServices.Styles;
using System;
using System.Collections.Generic;
namespace C3dTest
{
public class CreateCurvePipeTest
{
[CommandMethod("CreatePipeFromArc")]
public void CreatePipeFromArc()
{
Document adoc = Application.DocumentManager.MdiActiveDocument;
Editor ed = adoc.Editor;
Database db = adoc.Database;
PromptEntityOptions partOps
= new PromptEntityOptions("\nSelect network part: ");
partOps.SetRejectMessage("It's not part!");
partOps.AddAllowedClass(typeof(Part), false);
PromptEntityResult partRes = ed.GetEntity(partOps);
if (partRes.Status != PromptStatus.OK) return;
PromptEntityOptions arcOpts
= new PromptEntityOptions("\nSelect arc: ");
arcOpts.SetRejectMessage("It's not arc!");
arcOpts.AddAllowedClass(typeof(Arc), true);
PromptEntityResult arcRes = ed.GetEntity(arcOpts);
if (arcRes.Status != PromptStatus.OK) return;
ObjectId
netId,
famId = default,
sizeId = default;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Part part = tr.GetObject
(partRes.ObjectId, OpenMode.ForRead) as Part;
netId = part.NetworkId;
Network net = tr.GetObject
(netId, OpenMode.ForRead) as Network;
ObjectId partsListId = net.PartsListId;
PartsList partsList
= tr.GetObject(partsListId, OpenMode.ForRead) as PartsList;
using (ObjectIdCollection pipeFamsIds
= partsList.GetPartFamilyIdsByDomain(DomainType.Pipe))
{
if (pipeFamsIds.Count > 0)
{
famId = pipeFamsIds[0];
}
}
if (famId.IsValid)
{
PartFamily partFamily
= tr.GetObject(famId, OpenMode.ForRead) as PartFamily;
if (partFamily.PartSizeCount > 0)
{
sizeId = partFamily[0];
}
}
tr.Commit();
}
if (!famId.IsValid || !sizeId.IsValid)
{
return;
}
ObjectId newPipeId = default;
Point3d? endPoint = null;
List<Point3d> tmp = new List<Point3d>();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Arc arc = tr.GetObject(arcRes.ObjectId, OpenMode.ForRead) as Arc;
CircularArc3d arc3dForCreate;
bool isClockWise;
using (CircularArc3d arc3dForSupport = arc.GetGeCurve() as CircularArc3d)
{
// Если дуга больше полукруга
if ((arc3dForSupport.EndAngle - arc3dForSupport.StartAngle) > Math.PI)
{
// Идея такая. Сперва создаём трубу полукругом, а затем конечную точку
// тащим к тому месту, где она должна быть. При этом, капризное API не
// даёт сразу перетащить эту точку. Поэтому, перетаскивание делается
// через череду промежуточных точек. Причём, чем больше получается итоговый
// центральный угол дуги, тем меньше нужно делать шаг между точками.
// Сохраняем конечную точку. Одновременно это будет флагом того, что
// полученную изначально трубу надо будет дотягивать до этой точки
endPoint = arc3dForSupport.EndPoint;
double
// Почему-то иногда метод отказывается строить полный полукруг.
// Поэтому чуть-чуть его уменьшаем
tmpTotalAngle = 0.99 * Math.PI,
tmpEndAngle = arc3dForSupport.StartAngle + tmpTotalAngle;
arc3dForCreate = new CircularArc3d
(arc3dForSupport.Center,
arc3dForSupport.Normal,
arc3dForSupport.ReferenceVector,
arc3dForSupport.Radius,
arc3dForSupport.StartAngle,
tmpEndAngle);
// Начальный угловой шаг для вычисления точек на дуге
double
step = Math.PI / 6.0,
// Пороговое значение центрального угла дуги
// для первого уменьшения шага
stage1 = Math.PI * 1.5,
// Пороговое значение центрального угла дуги
// для второго уменьшения шага
stage2 = Math.PI * 11.0 / 6.0;
while ((arc3dForSupport.EndAngle - tmpEndAngle) > step)
{
tmpTotalAngle += step;
tmpEndAngle += step;
tmp.Add(arc3dForSupport.EvaluatePoint(tmpEndAngle));
// Чем больше итоговая дуга - тем меньше шаг
if (tmpTotalAngle > stage2)
{
step = Math.PI / 36.0;
}
else if (tmpTotalAngle > stage1)
{
step = Math.PI / 9;
}
}
}
else
{
arc3dForCreate = arc3dForSupport.Clone() as CircularArc3d;
}
Plane xy = new Plane(Point3d.Origin, Vector3d.ZAxis);
Point3d mid = arc3dForSupport.EvaluatePoint
((arc3dForSupport.EndAngle + arc3dForSupport.StartAngle) / 2.0);
using (CircularArc2d arc2d = new CircularArc2d
(arc3dForSupport.StartPoint.Convert2d(xy),
mid.Convert2d(xy),
arc3dForSupport.EndPoint.Convert2d(xy)))
{
isClockWise = arc2d.IsClockWise;
}
}
Network net = tr.GetObject(netId, OpenMode.ForWrite) as Network;
using (arc3dForCreate)
{
net.AddCurvePipe
(famId,
sizeId,
arc3dForCreate,
isClockWise,
ref newPipeId,
false);
}
tr.Commit();
}
if (newPipeId.IsValid && endPoint.HasValue)
{
foreach (Point3d tmpPt in tmp)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Pipe pipe = tr.GetObject(newPipeId, OpenMode.ForWrite) as Pipe;
pipe.EndPoint = tmpPt;
tr.Commit();
}
}
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Pipe pipe = tr.GetObject(newPipeId, OpenMode.ForWrite) as Pipe;
pipe.EndPoint = endPoint.Value;
tr.Commit();
}
}
}
}
}