示例#1
0
        //[CommandMethod("S1NF0_GeologColumnsToExcel2", CommandFlags.Modal)]
        public void GeologColumnsToExcel2()
        {
            Document adoc = Application.DocumentManager.MdiActiveDocument;

            if (adoc == null)
            {
                return;
            }

            Database db = adoc.Database;

            Editor ed = adoc.Editor;

            List <Entity> selectedEntities = new List <Entity>();

            try
            {
                Point3d?pt1 = null;
                Point3d?pt2 = null;
                //Обвести рамкой область таблицы
                if (Utils.SpecifyWindow(out pt1, out pt2, ed))
                {
                    Point3d _pt1 = pt1.Value;
                    Point3d _pt2 = pt2.Value;

                    double minX = 0;
                    double minY = 0;
                    double maxX = 0;
                    double maxY = 0;
                    if (_pt1.X < _pt2.X)
                    {
                        minX = _pt1.X;
                        maxX = _pt2.X;
                    }
                    else
                    {
                        minX = _pt2.X;
                        maxX = _pt1.X;
                    }
                    if (_pt1.Y < _pt2.Y)
                    {
                        minY = _pt1.Y;
                        maxY = _pt2.Y;
                    }
                    else
                    {
                        minY = _pt2.Y;
                        maxY = _pt1.Y;
                    }

                    Point2d minPt1 = new Point2d(minX, minY);
                    Point2d maxPt2 = new Point2d(maxX, maxY);
                    //Зумирование по рамке
                    Utils.ZoomWin(ed, _pt1, _pt2);
                    //Получить все линии и тексты по рамке
                    TypedValue[]          tv  = new TypedValue[] { new TypedValue(0, "LWPOLYLINE,LINE,TEXT,MTEXT") };
                    SelectionFilter       flt = new SelectionFilter(tv);
                    PromptSelectionResult res = ed.SelectCrossingWindow(_pt1, _pt2, flt);
                    if (res.Status == PromptStatus.OK)
                    {
                        SelectionSet acSSet = res.Value;

                        List <Entity>        textEnts        = new List <Entity>();
                        List <LineSegment2d> verticalLines   = new List <LineSegment2d>(); //Точки линии снизу вверх
                        List <LineSegment2d> horizontalLines = new List <LineSegment2d>(); //Точки линии слева направо

                        Line2d bottom      = new Line2d(minPt1, new Vector2d(1, 0));       //по низу
                        Line2d leftBorder  = new Line2d(minPt1, new Vector2d(0, 1));       //по левой стороне
                        Line2d top         = new Line2d(maxPt2, new Vector2d(1, 0));       //по верху
                        Line2d rightBorder = new Line2d(maxPt2, new Vector2d(0, 1));       //по правой стороне

                        using (Transaction tr = db.TransactionManager.StartTransaction())
                        {
                            //Подсветить выбранное. Дать возможность дополнительно выбрать вручную тексты, которые вылезают за рамку
                            HashSet <ObjectId> selectedIds = new HashSet <ObjectId>();
                            foreach (ObjectId id in acSSet.GetObjectIds())
                            {
                                selectedIds.Add(id);
                                Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead);
                                selectedEntities.Add(ent);
                            }
                            Utils.Highlight(selectedEntities, true);
                            tv  = new TypedValue[] { new TypedValue(0, "TEXT,MTEXT") };
                            flt = new SelectionFilter(tv);
                            PromptSelectionOptions pso = new PromptSelectionOptions();
                            pso.MessageForAdding = "\nВыберите дополнительные тексты, вышедшие за рамки таблицы если необходимо (TEXT,MTEXT)";

                            PromptSelectionResult acSSPrompt = adoc.Editor.GetSelection(pso, flt);
                            if (acSSPrompt.Status == PromptStatus.OK)
                            {
                                foreach (SelectedObject acSSObj in acSSet)
                                {
                                    if (acSSObj != null)
                                    {
                                        if (!selectedIds.Contains(acSSObj.ObjectId))
                                        {
                                            selectedIds.Add(acSSObj.ObjectId);
                                            Entity ent = tr.GetObject(acSSObj.ObjectId, OpenMode.ForRead) as Entity;
                                            selectedEntities.Add(ent);
                                        }
                                    }
                                }
                            }

                            //Разобрать все линии на отрезки. Разбить на 2 группы: вертикальные и горизонтальные.
                            //Не брать в расчет линии, проходящие строго по границам указанной рамки
                            //Наклонные линии нигде не учитывать
                            List <Line2d> borderGuidings = new List <Line2d>()
                            {
                                bottom, leftBorder, top, rightBorder
                            };
                            foreach (Entity ent in selectedEntities)
                            {
                                if (ent is MText || ent is DBText)
                                {
                                    textEnts.Add(ent);
                                }
                                else
                                {
                                    if (ent is Polyline)
                                    {
                                        //TODO: Полилиния может иметь дуговые вставки. Учитывать это?
                                        Polyline polyline = ent as Polyline;
                                        for (int i = 0; i < polyline.NumberOfVertices - 1; i++)
                                        {
                                            Point2d segPt1 = polyline.GetPoint2dAt(i);
                                            Point2d segPt2 = polyline.GetPoint2dAt(i + 1);
                                            if (!OverlapBorder(segPt1, segPt2, borderGuidings) &&
                                                InsideBorders(segPt1, segPt2, minX, minY, maxX, maxY))
                                            {
                                                ResolveLineType(segPt1, segPt2, verticalLines, horizontalLines);
                                            }
                                        }
                                    }
                                    else if (ent is Line)
                                    {
                                        Line    line   = ent as Line;
                                        Point2d segPt1 = new Point2d(line.StartPoint.X, line.StartPoint.Y);
                                        Point2d segPt2 = new Point2d(line.EndPoint.X, line.EndPoint.Y);
                                        if (!OverlapBorder(segPt1, segPt2, borderGuidings) &&
                                            InsideBorders(segPt1, segPt2, minX, minY, maxX, maxY))
                                        {
                                            ResolveLineType(segPt1, segPt2, verticalLines, horizontalLines);
                                        }
                                    }
                                }
                            }
                            tr.Commit();
                        }


                        //Определить координаты X по которым проходят сплошные вертикальные линии - это границы столбцов
                        //Разбить вертикальные линии на группы по координате X
                        SortedDictionary <double, SortedSet <LineSegment2d> > columnBorders
                            = new SortedDictionary <double, SortedSet <LineSegment2d> >();
                        foreach (LineSegment2d vertLine in verticalLines)
                        {
                            double x = vertLine.StartPoint.X;
                            SortedSet <LineSegment2d> lines = null;
                            columnBorders.TryGetValue(x, out lines);
                            if (lines == null)
                            {
                                lines = new SortedSet <LineSegment2d>(new VertLineComparer());
                                columnBorders.Add(x, lines);
                            }
                            lines.Add(vertLine);
                        }

                        //Оставить только те вертикальные линии, которые проходят от верха до низа выбранной области
                        List <double> keysToRemove = new List <double>();
                        foreach (KeyValuePair <double, SortedSet <LineSegment2d> > kvp in columnBorders)
                        {
                            //Первый отрезок пересекает нижнюю границу заданной области
                            //Последний отрезок пересекает верхнюю границу заданной области
                            if ((new CurveCurveIntersector2d(kvp.Value.First(), bottom)).NumberOfIntersectionPoints == 0 ||
                                (new CurveCurveIntersector2d(kvp.Value.Last(), top)).NumberOfIntersectionPoints == 0)
                            {
                                keysToRemove.Add(kvp.Key);
                                break;
                            }

                            //Между отрезками нет зазоров
                            LineSegment2d previousSeg = null;
                            foreach (LineSegment2d seg in kvp.Value)
                            {
                                if (previousSeg != null)
                                {
                                    if (!previousSeg.EndPoint.IsEqualTo(seg.StartPoint) && previousSeg.EndPoint.Y < seg.StartPoint.Y)
                                    {
                                        //Между отрезками есть зазор
                                        keysToRemove.Add(kvp.Key);
                                        break;
                                    }
                                }
                                previousSeg = seg;
                            }
                        }

                        foreach (double key in keysToRemove)
                        {
                            columnBorders.Remove(key);
                        }

                        if (columnBorders.Count == 0)
                        {
                            ed.WriteMessage("Таблица не распознана. В заданной области должны быть сплошные вертикальные линии, обозначающие границы столбцов");
                            return;
                        }

                        //Для каждой колонки образуется список точек пересечений с горизонтальными отрезками, обозначающих низ ячейки
                        List <double> colBorders = new List <double>()
                        {
                            minX
                        };
                        colBorders.AddRange(columnBorders.Keys);
                        colBorders.Add(maxX);
                        List <ColumnInfo> columns = new List <ColumnInfo>();
                        for (int i = 0; i < colBorders.Count - 1; i++)
                        {
                            ColumnInfo ci = new ColumnInfo(colBorders[i], colBorders[i + 1]);
                            ci.CalcRowBottomLevels(horizontalLines, minY);
                            columns.Add(ci);
                        }

                        //Каждый текст относится к столбцу, а затем по списку точек столбца относится к конкретной строке
                        //(ближайшая нижележащая точка указывает на номер строки)

                        foreach (Entity textEnt in textEnts)
                        {
                            string contents = (textEnt as MText)?.Text;
                            if (contents == null)
                            {
                                contents = (textEnt as DBText)?.TextString;
                            }

                            Extents3d?ext = textEnt.Bounds;
                            if (ext != null)
                            {
                                Point2d textLocation =
                                    new Point2d((ext.Value.MinPoint.X + ext.Value.MaxPoint.X) / 2,
                                                (ext.Value.MinPoint.Y + ext.Value.MaxPoint.Y) / 2);
                                double colPosition = textLocation.X;
                                if (colPosition < minX)
                                {
                                    columns.First().AddTextToCell(textLocation, contents);
                                }
                                else if (colPosition > maxX)
                                {
                                    columns.Last().AddTextToCell(textLocation, contents);
                                }
                                else
                                {
                                    //Найти колонку, в которую добавляется текст и добавить его
                                    ColumnInfo col = columns.Find(c => c.LeftSide <= colPosition && c.RightSide >= colPosition);
                                    if (col != null)
                                    {
                                        col.AddTextToCell(textLocation, contents);
                                    }
                                }
                            }
                        }


                        //Заполнить таблицу эксель
                        //Получить приложение Excel
                        Excel.Application instance = null;
                        try
                        {
                            instance = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
                        }
                        catch (System.Runtime.InteropServices.COMException)
                        {
                            instance = new Excel.Application();
                        }

                        try
                        {
                            instance.ScreenUpdating = false;
                            //Создать новую книгу Excel и записать в нее таблицу
                            Excel._Workbook workbook = instance.Workbooks.Add(Type.Missing);
                            Excel.Worksheet wSheet   = workbook.Sheets.Item[1];

                            int colNum = 1;
                            foreach (ColumnInfo col in columns)
                            {
                                int rowNum = 1;
                                foreach (SortedDictionary <Point2d, string> cellContent in col.RowBottomLevels.Values.Reverse())
                                {
                                    string val = string.Join(" ", cellContent.Values);

                                    wSheet.Cells[rowNum, colNum] = val;
                                    //if (colNum == 2)
                                    //{
                                    //    wSheet.Cells[rowNum, 1] = boreholeName;
                                    //}
                                    rowNum++;
                                }

                                colNum++;
                            }
                        }
                        finally
                        {
                            instance.ScreenUpdating = true;
                            instance.Visible        = true;
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
                CommonException(ex, "Ошибка при получении таблицы Excel по таблице в AutoCAD");
            }
            finally
            {
                Utils.Highlight(selectedEntities, false);
            }
        }