20/03/2018
Как получить пересечение прямой и твердого тела в NET?
По аналогии с тем, как это делается в ObjectARX, это можно сделать при помощи B-Rep API и в AutoCAD .NET API. Следующий код иллюстрирует как получить пересечение линейного примитива (ОТРЕЗОК, ЛУЧ, ПРЯМАЯ) с примитивом, который представляется в виде ACIS (т.е. твердое тело - SOLID, область - REGION, или тело BODY).
Код - C#: [Выделить]
- using System;
- using Autodesk.AutoCAD.Runtime;
- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.DatabaseServices;
- using Autodesk.AutoCAD.Geometry;
- using Autodesk.AutoCAD.EditorInput;
- using Autodesk.AutoCAD.BoundaryRepresentation;
- using AcRx = Autodesk.AutoCAD.Runtime;
- using AcAp = Autodesk.AutoCAD.ApplicationServices;
- using AcDb = Autodesk.AutoCAD.DatabaseServices;
- using AcGe = Autodesk.AutoCAD.Geometry;
- using AcEd = Autodesk.AutoCAD.EditorInput;
- using AcBr = Autodesk.AutoCAD.BoundaryRepresentation;
- // This line is not mandatory, but improves loading performances
- [assembly: CommandClass(typeof(IntSolidNet.MyCommands))]
- namespace IntSolidNet
- {
- public class MyCommands
- {
- [CommandMethod("IntSolid", CommandFlags.Modal)]
- public void MyCommand()
- {
- Document doc = Application.DocumentManager.MdiActiveDocument;
- if (doc == null) return;
- Editor ed = doc.Editor;
- // Запрашиваем линию
- PromptEntityOptions prLine = new PromptEntityOptions("\nВыберите линию: ");
- prLine.SetRejectMessage("Это не линия - допустимы Отрезок, Луч, Прямая");
- prLine.AddAllowedClass(typeof(Line), false);
- prLine.AddAllowedClass(typeof(Ray), false);
- prLine.AddAllowedClass(typeof(Xline), false);
- PromptEntityResult rsLine = ed.GetEntity(prLine);
- if (rsLine.Status != PromptStatus.OK) return;
- // Запрашиваем 3DSolid
- PromptEntityOptions prSolid = new PromptEntityOptions("\nВыберите твердое тело: ");
- prSolid.SetRejectMessage("Это не твердое тело");
- prSolid.AddAllowedClass(typeof(Solid3d), false);
- prSolid.AddAllowedClass(typeof(Region), false);
- prSolid.AddAllowedClass(typeof(Body), false);
- PromptEntityResult rsSolid = ed.GetEntity(prSolid);
- if (rsSolid.Status != PromptStatus.OK) return;
- // Запрашиваем количество пересечений
- PromptIntegerOptions prNumInt =
- new PromptIntegerOptions("\nКоличество пересечений (0 - все): ");
- prNumInt.AllowNegative = false;
- prNumInt.AllowZero = true;
- prNumInt.AllowNone = false;
- PromptIntegerResult rsNumInt = ed.GetInteger(prNumInt);
- if (rsNumInt.Status != PromptStatus.OK) return;
- Point3dCollection hitPoints = new Point3dCollection();
- #pragma warning disable 0618
- using (Entity line = rsLine.ObjectId.Open(OpenMode.ForRead) as Entity)
- using (Entity solid = rsSolid.ObjectId.Open(OpenMode.ForRead) as Entity)
- #pragma warning restore 0618
- {
- if (getHits(line, solid, rsNumInt.Value, hitPoints) == AcRx.ErrorStatus.InvalidInput)
- {
- ed.WriteMessage("\nЧто-то пошло не так!");
- }
- else
- {
- if (hitPoints.Count == 0)
- {
- ed.WriteMessage("\nПересечения не найдены!");
- }
- else
- {
- ed.WriteMessage("\nНайдено {0} пересечений", hitPoints.Count);
- for (int i = 0; i < hitPoints.Count; i++)
- {
- ed.WriteMessage("\nПересечение {0}: {1}", i + 1, hitPoints[i]);
- }
- }
- }
- }
- }
- /// <summary>
- /// Функция для получения точек пересечения твердого тела и прямой
- /// </summary>
- static AcRx.ErrorStatus getHits(Entity line, Entity solid, int nHitsWanted, Point3dCollection hitPoints)
- {
- Document doc = Application.DocumentManager.MdiActiveDocument;
- Editor ed = doc.Editor;
- // Проверяем, что примитив правильного типа
- if (!(solid is Solid3d || solid is Region || solid is Body))
- {
- ed.WriteMessage("\nВторой аргумент должен быть твердым телом, а не %0",
- solid.GetRXClass().Name);
- return AcRx.ErrorStatus.InvalidInput;
- }
- LinearEntity3d pGeLine = null;
- if (line is Line)
- {
- Line ln = line as Line;
- pGeLine = new LineSegment3d(ln.StartPoint, ln.EndPoint);
- }
- else if (line is Ray)
- {
- Ray ln = line as Ray;
- pGeLine = new Ray3d(ln.BasePoint, ln.UnitDir);
- }
- else if (line is Xline)
- {
- Xline ln = line as Xline;
- pGeLine = new Line3d(ln.BasePoint, ln.UnitDir);
- }
- else
- {
- ed.WriteMessage("\nПервый аргумент должен быть линией, а не %0",
- line.GetRXClass().Name);
- return AcRx.ErrorStatus.InvalidInput;
- }
- // Находим количество пересечений при помощи B-Rep API
- ObjectId solidId = solid.ObjectId;
- FullSubentityPath subs = new FullSubentityPath(new ObjectId[] { solidId }, new SubentityId());
- Brep pBrep = new Brep(subs);
- Hit[] pHits = pBrep.GetLineContainment(pGeLine, nHitsWanted);
- if (pHits != null)
- {
- int nHitsFound = pHits.Length;
- for (int i = 0; i < nHitsFound; i++)
- {
- BrepEntity pHitEntity = pHits[i].EntityHit as BrepEntity;
- if (pHitEntity == null)
- continue;
- if (pHitEntity is Brep)
- continue;
- Point3d hitPt = pHits[i].Point;
- hitPoints.Add(hitPt);
- }
- // Конвертируем точки из МСК в ПСК
- int nPts = hitPoints.Count;
- Matrix3d mat = ed.CurrentUserCoordinateSystem.Inverse();
- for (int i = 0; i < nPts; i++)
- {
- hitPoints[i] = hitPoints[i].TransformBy(mat);
- }
- }
- return AcRx.ErrorStatus.OK;
- }
- }
- }
Автор: Александр Ривилис
Обсуждение: http://adn-cis.org/forum/index.php?topic=
Опубликовано 20.03.2018