Статьи > Тестирование статей

AutoCAD .NET API: Рассечение штриховки.

<< < (2/2)

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;        } 

Навигация

[0] Главная страница сообщений

[*] Предыдущая страница

Перейти к полной версии