Статьи > Тестирование статей
AutoCAD .NET API: Рассечение штриховки.
alz:
Разобрался, все зависит от типа петли, если использовать default то штриховка корректно отображается только если тип островков стоит нормальный, соответственно не работает свойство площади штриховки и ее невозможно разделить на отдельные.
Для корректного отображения штриховки нужно использовать минимум 3 типа, в зависимости от количества вложений петель, к тому же петли подразделяются на 2 глобальных типа, обычные и HatchLoopTypes.Textbox(визуально убирают штриховку внутри контура но это сокрытие не влияет на площадь).
Протестировав варианты петель обнаружились такие типы
Обычные
1 - Наружный контур HatchLoopTypes.External
2 - Внутренний контур - внутри наружного HatchLoopTypes.Outermost (если он касается наружного имеет двойной тип + HatchLoopTypes.External )
3 - Контура внутри внутреннего контура обозначаются как HatchLoopTypes.Default
Текстбоксы
1 - снаружи или снаружи и касается внешнего контура или пересекает внешний контур HatchLoopTypes.Textbox | HatchLoopTypes.External
2 - внутри относительно внешнего контура, пересекает второй контур или его касается HatchLoopTypes.Textbox | HatchLoopTypes.Outermost
3 - внутри и касается внешнего контура HatchLoopTypes.Textbox | HatchLoopTypes.Outermost | HatchLoopTypes.External
при переходе в глубину вложения контуров уже идет зависимость от номера вложения для глубины больше 2
4 - текст внутри четного контура - HatchLoopTypes.Textbox | HatchLoopTypes.TextIsland
5 - текст внутри нечетного контура или внутри четного контура но его касается или его пересекает - HatchLoopTypes.Textbox
Для реализации всех этих элементов были изменены следующие функции
1 основной код
--- Код - C# [Выбрать] --- public List<ObjectId> CutHatch(ObjectId plId, ObjectId hId) { List<ObjectId> result = new List<ObjectId>(); //работаем сразу в транзокции и таблице так как частенько придется что-то доставать или что-то записывать using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction()) { using (BlockTableRecord ms = tr.GetObject(HostApplicationServices.WorkingDatabase.CurrentSpaceId, OpenMode.ForWrite, false, true) as BlockTableRecord) { using (Hatch hatch = tr.GetObject(hId, OpenMode.ForWrite, false, true) as Hatch) { //получаем план штриховки Plane plane = hatch.GetPlane(); //получаем вектор текущего вида Vector3d vector = GetViewVector(); //проверяем на самопересечение и замкнутость using (Curve pl1 = tr.GetObject(plId, OpenMode.ForRead, false, true) as Curve) using (Curve pl = pl1.GetProjectedCurve(plane, vector)) using (Curve3d pl3d = pl.GetGeCurve()) using (CurveCurveIntersector3d cuin = new CurveCurveIntersector3d(pl3d, pl3d, vector)) { if (cuin.NumberOfIntersectionPoints > 0 | !pl3d.IsClosed()) { tr.Commit(); return new List<ObjectId> { ObjectId.Null }; } } //получаем петли из штриховки //List<HatchLoop> loops = new List<HatchLoop>(); //создаем кривые в чертеже для каждого петли и записываем их в списки //список обычных петель List<ObjectId> loopCurve = new List<ObjectId>(); //список текстбоксовых петель List<List<ObjectId>> textLoopCurve = new List<List<ObjectId>>(); for (int i = hatch.NumberOfLoops - 1; i >= 0; i--) { HatchLoopTypes sdfds = hatch.LoopTypeAt(i); //получаем куски петли List<ObjectId> objectIds = GetCurveFromLoop(hatch.GetLoopAt(i), plane, hatch); if (hatch.LoopTypeAt(i).Equals(HatchLoopTypes.Textbox) | hatch.LoopTypeAt(i).Equals(HatchLoopTypes.TextIsland | HatchLoopTypes.Textbox) | hatch.LoopTypeAt(i).Equals(HatchLoopTypes.Textbox | HatchLoopTypes.Outermost) | hatch.LoopTypeAt(i).Equals(HatchLoopTypes.Textbox | HatchLoopTypes.External) | hatch.LoopTypeAt(i).Equals(HatchLoopTypes.Textbox | HatchLoopTypes.Outermost | HatchLoopTypes.External) ) textLoopCurve.Add(objectIds); else loopCurve.AddRange(objectIds); } //return new List<ObjectId> { ObjectId.Null }; //список секущих точек List<Point3d> sPoints = new List<Point3d>(); //разрезаем все контура в штриховке проекцией контура (которые контур рассекает) //список удаляемых кривых петель List<ObjectId> erList = new List<ObjectId>(); //список добавляемых кривых в петли List<ObjectId> addList = new List<ObjectId>(); foreach (ObjectId id in loopCurve) { //получаем кривую using (Curve cur = tr.GetObject(id, OpenMode.ForWrite, false, true) as Curve) { //получаем точки пересечения List<Point3d> points = IntersectPoints(plId, ObjectId.Null, null, cur.Clone() as Curve, plane, vector, false); //если точки есть то разрезаем кривую, добавляем куски в список и удаляем разрезанную if (points.Count > 0) { sPoints.AddRange(points); using (Point3dCollection collection = new Point3dCollection()) { foreach (Point3d point in points) collection.Add(point); using (DBObjectCollection objects = cur.GetSplitCurves(collection)) { foreach (Object obj in objects) { using (Curve curve = obj as Curve) { if (curve != null) { addList.Add(ms.AppendEntity(curve)); tr.AddNewlyCreatedDBObject(curve, true); } } } } } cur.Erase(); erList.Add(id); } } } //если были то обновляем список кривых в петлих foreach (ObjectId id in erList) loopCurve.Remove(id); loopCurve.AddRange(addList); //создаем списки распределения кривых (других по идее быть не должно) //внутри List<Curve> inner = new List<Curve>(); //снаружи List<Curve> outer = new List<Curve>(); //создаем список с кусками пересекающей кривой, которые будем добавлять в петли List<ObjectId> kontPartLstId = new List<ObjectId>(); List<Curve> kontPartLst = new List<Curve>(); List<Curve> kontPartLstCopy = new List<Curve>(); //получаем контур в виде проекции на плоскость штриховки using (Curve pl1 = tr.GetObject(plId, OpenMode.ForRead, false, true) as Curve) using (Curve pl = pl1.GetProjectedCurve(plane, vector)) { //распределяем куски петель по спискам foreach (ObjectId id in loopCurve) { Curve c = tr.GetObject(id, OpenMode.ForRead, false, true) as Curve; //после всех манипляций тут должны быть только результаты 1 - 5 //если встретится что-то другое то скорее всего произошла какая-то ошибка и просто прекращаем //если все нормально то все кривые распределятся по спискам кроме номера 3 //он просто игнорируется и никуда не идет, его заменят если что части контура int res = PartIn(pl, c, plane, vector); if (res == 0 | res == 6) { DeleteObj(loopCurve); tr.Commit(); return new List<ObjectId> { ObjectId.Null }; } if (res == 1 | res == 4) { inner.Add(c); continue; } if (res == 2 | res == 5) { outer.Add(c); continue; } if (res == 3) continue; } //ищем куски разрезающей кривой //сортируем точки по разрезающей кривой sPoints = SortPoint(sPoints, pl); using (Point3dCollection collection = new Point3dCollection()) { if (sPoints.Count > 0) { foreach (Point3d point in sPoints) collection.Add(point); using (DBObjectCollection objects = pl.GetSplitCurves(collection)) { foreach (Object obj in objects) { using (Curve curve = obj as Curve) { if (curve != null) { //проверяем находится ли кусок контура внутри штриховки int res = CurveInCurves(curve, loopCurve, plane, vector, null); //если ошибка if (res == 0) { DeleteObj(loopCurve); DeleteObj(kontPartLstId); tr.Commit(); return new List<ObjectId> { ObjectId.Null }; } //если внутри то добавляем на модель и в список if (res == 1 | res == 4) { kontPartLstId.Add(ms.AppendEntity(curve)); tr.AddNewlyCreatedDBObject(curve, true); } } } } } } } //получаем куски контура как кривые и создаем 2 списка для тех областей что внутри и для тех что снаружи List<ObjectId> nkontPartLstId = new List<ObjectId>(); foreach (ObjectId objectId in kontPartLstId) { Curve curve = tr.GetObject(objectId, OpenMode.ForRead, false, true) as Curve; kontPartLst.Add(curve); //добавляем копию на модель и в список Curve curveCopy = curve.Clone() as Curve; nkontPartLstId.Add(ms.AppendEntity(curveCopy)); tr.AddNewlyCreatedDBObject(curveCopy, true); kontPartLstCopy.Add(curveCopy); } //добавляем ObjectId копий в общий список для последующего удаления kontPartLstId.AddRange(nkontPartLstId); //анализируем списки и составляем из кусков новые петли inner.AddRange(kontPartLstCopy); List<List<ObjectId>> loopsId = GetNewLoops(inner); List<(List<ObjectId>, HatchLoopTypes)> loopsIdAndType = GetLoopsType(loopsId, plane, vector); for (int i = (hatch.NumberOfLoops - 1); i >= 0; i--) hatch.RemoveLoopAt(i); if (loopsId != null) result.Add(NewHatch(tr, ms, loopsIdAndType, hatch, textLoopCurve)); else { DeleteObj(loopCurve); DeleteObj(kontPartLstId); tr.Commit(); return new List<ObjectId> { ObjectId.Null }; } outer.AddRange(kontPartLst); loopsId = GetNewLoops(outer); loopsIdAndType = GetLoopsType(loopsId, plane, vector); if (loopsId != null) result.Add(NewHatch(tr, ms, loopsIdAndType, hatch, textLoopCurve)); else { DeleteObj(loopCurve); DeleteObj(kontPartLstId); tr.Commit(); return new List<ObjectId> { ObjectId.Null }; } DeleteObj(kontPartLstId); DeleteObj(nkontPartLstId); } foreach (List<ObjectId> ids in textLoopCurve) DeleteObj(ids); DeleteObj(loopCurve); hatch.Erase(); } } tr.Commit(); } return result; }
alz:
2 - функция определения положения точки или кривой относительно группы кривых
--- Код - C# [Выбрать] --- /// <summary> /// используется что бы определить положение объекта относительно элементов петли /// даст точный результат если объекты из списка обзаруют замкнутый контур /// </summary> /// <param name="cur"></param> /// <param name="loopIds"></param> /// <param name="plane"></param> /// <param name="vector"></param> /// <param name="kontur"></param> /// <returns> /// 0 - ошибка исходных данных /// 1 - внутри петли /// 2 - снаружи петли /// 3 - пересекает петлю /// 4 - касается петли и внутри /// 5 - касается петли и снаружи /// 6 - если точка лежит на контуре /// </returns> private int CurveInCurves(Object cur, List<ObjectId> loopIds, Plane plane, Vector3d vector, Curve kontur) { if ((loopIds.Count == 0 & kontur == null) | cur == null ) return 0; //проверяем на пересечение bool kas = false; using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction()) { if (cur is Curve) { Curve curCur = cur as Curve; using (Curve3d cur3d = curCur.GetGeCurve()) { foreach (ObjectId loopId in loopIds) { using (Curve curve = tr.GetObject(loopId, OpenMode.ForRead, false, true) as Curve) { if (curve != null) { using (Curve3d curve3d = curve.GetGeCurve()) using (CurveCurveIntersector3d cuin = new CurveCurveIntersector3d(curve3d, cur3d, vector)) { if (cuin.NumberOfIntersectionPoints > 0) { for (int i = 0; i < cuin.NumberOfIntersectionPoints; i++) { if (cuin.IsTransversal(i)) { if (cuin.GetIntersectionPoint(i).Equals(cur3d.StartPoint) | cuin.GetIntersectionPoint(i).Equals(cur3d.EndPoint)) { kas = true; } else { tr.Commit(); return 3; } } else { kas = true; } } } } } } } } } if (cur is Point3d) { foreach (ObjectId loopId in loopIds) { using (Curve curve = tr.GetObject(loopId, OpenMode.ForRead, false, true) as Curve) { if (curve != null) if (curve.GetClosestPointTo((Point3d)cur, false).DistanceTo((Point3d)cur) == 0) { tr.Commit(); return 5; } } } } tr.Commit(); } //счетчик общего числа пересечений //создаем список точек что бы не задваивать пересечения //если вдруг точка пересечения попадет в стык между двумя кривыми //встречается часто если сечется прямоугольником так как вектор параллелен оси List<Point3d> points = new List<Point3d>(); using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction()) { //строим луч из центра кривой в плане штриховки using (Ray ray = new Ray()) { //создаем луч из центра кривой if (cur is Curve) ray.BasePoint = GetCentr(cur as Curve); if (cur is Point3d) ray.BasePoint = (Point3d)cur; ray.UnitDir = plane.Normal.GetPerpendicularVector(); //проходим по всем кривым и ищем пересечения using (Curve3d ray3d = ray.GetGeCurve()) { List<Curve> curves = new List<Curve>(); foreach (ObjectId id in loopIds) curves.Add(tr.GetObject(id, OpenMode.ForRead, false, true) as Curve); if (kontur != null) curves.Add(kontur); foreach (Curve curve in curves) { using (Curve3d loopCur3d = curve.GetGeCurve()) using (CurveCurveIntersector3d cuin = new CurveCurveIntersector3d(ray3d, loopCur3d, vector)) { if (cuin.NumberOfIntersectionPoints > 0) { //ищем число пересечений не считая касательных for (int i = 0; i < cuin.NumberOfIntersectionPoints; i++) if (cuin.IsTransversal(i)) { if (!points.Contains(cuin.GetIntersectionPoint(i))) { points.Add(cuin.GetIntersectionPoint(i)); } } } } } } } tr.Commit(); } //если число пересечений нечетное то точка изнутри, если четное или ноль то снаружи if (points.Count % 2 != 0) { if (kas) return 4; else return 1; } else { if (kas) return 5; else return 2; } }3 изменена функция отрисовки новой штриховки, теперь учитывает типы петель
--- Код - C# [Выбрать] --- private ObjectId NewHatch(Transaction tr, BlockTableRecord ms, List<(List<ObjectId>, HatchLoopTypes)> loopsIdAndType, Hatch hatch, List<List<ObjectId>> textLoopCurve) { ObjectId result = ObjectId.Null; //переменная для фиксации результата bool del = false; using (Hatch h = hatch.Clone() as Hatch) { using (Transaction tr2 = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction()) { result = ms.AppendEntity(h); tr2.AddNewlyCreatedDBObject(h, true); tr2.Commit(); } //проходим по всем loop в списке for (int i = 0; i < loopsIdAndType.Count; i++) { List<ObjectId> loopId = loopsIdAndType[i].Item1; if (loopId.Count == 0) continue; //если ошибок не было то вставляем петлю if (!del) { //создаем из списка коллекцию using (ObjectIdCollection lId = new ObjectIdCollection()) { //добавляем в коллекцию куски loop foreach (ObjectId curId in loopId) lId.Add(curId); //пробуем добавить коллекцию в штриховку try { h.AppendLoop(loopsIdAndType[i].Item2, lId); } catch { //если не удалось то удаляем штриховку и возвращаем ObjectId.Null del = true; } } } } //теперь требуется определить новую глубину вложения каждого тексбокса //глубина определяется положением текстбокса относительно всех петель // 1 петля - внешний контур External // 2 петля - внутренний контур Outermost // остальные петли идут как Default //в отличии от обычных петель которые друг с другом не пересекаются (еси есть пересечения они объединяются в одну петлю) //типы положения текстбоксов // 1 - текстбокс снаружи или снаружи и касается внешнего контура или пересекает внешний контур +External // 2 - внутри относительно внешнего контура, пересекает второй контур или его касается +Outermost // 3 - внутри и касается внешнего контура +Outermost +External //при переходе в глубину вложения контуров уже идет зависимость от номера вложения для уровней больше 2 // 4 - текст внутри четного контура +TextIsland // 5 - текст внутри четного контура но его касается или его пересекает - ничего for (int i = 0; i < textLoopCurve.Count; i++) { List<ObjectId> loopId = textLoopCurve[i]; if (loopId.Count == 0) continue; //если ошибок не было то вставляем петлю if (!del) { //создаем из списка коллекцию using (ObjectIdCollection lId = new ObjectIdCollection()) { //добавляем в коллекцию куски loop foreach (ObjectId curId in loopId) lId.Add(curId); //определяем место текстовой петли относительно обычных if (loopsIdAndType.Count > 0) { //тип текстбокс штриховки int vType = 1; //полный уровень вложения int into = 100000; //проходим по кускам петли и определяем уровень вложения foreach (ObjectId curLoopId in lId) { bool stop = false; using (Curve c = tr.GetObject(curLoopId, OpenMode.ForRead, false, true) as Curve) { int curinto = 0; //проходим по всем не текстбокс петлям foreach ((List<ObjectId>, HatchLoopTypes) vloopId in loopsIdAndType) { int res = CurveInCurves(c, vloopId.Item1, hatch.GetPlane(), GetViewVector(), null); //определяем уровень вложения if (res == 1) { curinto++; continue; } if (res == 3) { //если пересекает внешний контур if (vloopId.Item2 == HatchLoopTypes.External) { vType = 1; stop = true; break; } //если пересекает внутренний контур if (vloopId.Item2 == HatchLoopTypes.Outermost | vloopId.Item2 == (HatchLoopTypes.Outermost | HatchLoopTypes.External)) { vType = 2; } } if (res == 4) { //если пересекает внешний контур if (vloopId.Item2 == HatchLoopTypes.External) { vType = 3; stop = true; break; } } } if (into > curinto) into = curinto; if (stop) break; } } if (vType == 1 & into > 0) { if (into == 1) vType = 2; if (into % 2 != 0) vType = 4; else vType = 5; } //пробуем добавить коллекцию в штриховку try { //устанаваливаем loop в зависимости от глубины вложения switch (vType) { case 1: h.AppendLoop(HatchLoopTypes.External | HatchLoopTypes.Textbox, lId); break; case 2: h.AppendLoop(HatchLoopTypes.Outermost | HatchLoopTypes.Textbox, lId); break; case 3: h.AppendLoop(HatchLoopTypes.External | HatchLoopTypes.Outermost | HatchLoopTypes.Textbox, lId); break; case 4: h.AppendLoop(HatchLoopTypes.TextIsland | HatchLoopTypes.Textbox, lId); break; case 5: h.AppendLoop(HatchLoopTypes.Textbox, lId); break; } } catch { //если не удалось то удаляем штриховку и возвращаем ObjectId.Null del = true; } } } } } //если произошла какая-то ошибка то удаляем штриховку if (del) { h.Erase(); return ObjectId.Null; } } return result; } 4 добавлена новая функция, определяет тип петли
--- Код - C# [Выбрать] ---private List<(List<ObjectId>, HatchLoopTypes)> GetLoopsType(List<List<ObjectId>> loopsId, Plane plane, Vector3d vector) { List<(List<ObjectId>, HatchLoopTypes)> result = new List<(List<ObjectId>, HatchLoopTypes)>(); if (loopsId == null) return result; using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction()) { for (int i = 0; i < loopsId.Count; i++) { //касание внешнего контура bool exout = false; List<ObjectId> loopId = loopsId[i]; if (loopId.Count == 0) continue; //переменная для определения уровня вложения int into = 0; //если loop больше одного определяем тип этого loop if (loopsId.Count > 1) { //берем за основу один из элементов loop using (Curve c = tr.GetObject(loopId[0], OpenMode.ForRead, false, true) as Curve) { //проходим по всем loop кроме текущего и проверяем где находится элемент относительно них foreach (List<ObjectId> vloopId in loopsId) { if (vloopId.Equals(loopId)) continue; int res = CurveInCurves(c, vloopId, plane, vector, null); //если элемент внутри одного из loop (возврат от проверки - 1) if (res == 1) into++; if (res == 4) { exout = true; into++; } //все вложения больше 1 это default if (into > 1) break; } } } //устанаваливаем loop в зависимости от глубины вложения switch (into) { case 0: result.Add((loopId, HatchLoopTypes.External)); break; case 1: { if (exout) result.Add((loopId, HatchLoopTypes.Outermost | HatchLoopTypes.External)); else result.Add((loopId, HatchLoopTypes.Outermost)); break; } default: result.Add((loopId, HatchLoopTypes.Default)); break; } } tr.Commit(); } return result; }
Навигация
Перейти к полной версии