/// <summary> /// Reads a poly line from the DXF file and construct a boundary from the geometry and extended attributes /// defining the boundary type and name /// </summary> /// <param name="closedPolyLinesOnly"></param> /// <param name="atEof"></param> /// <param name="boundary"></param> /// <returns></returns> public bool GetBoundaryFromPolyLineEntity(bool closedPolyLinesOnly, out bool atEof, out PolyLineBoundary boundary) { var loadError = false; var polyLineIsClosed = false; atEof = GetStartOfNextEntity(out var DXFRec); boundary = null; if (atEof) { return(false); } boundary = new PolyLineBoundary(); var testString = DXFRec.s.ToUpper(CultureInfo.InvariantCulture); switch (testString) { // ReSharper disable once StringLiteralTypo case "POLYLINE": ReadPolyLine(out loadError, false, boundary, out polyLineIsClosed); break; // ReSharper disable once StringLiteralTypo case "LWPOLYLINE": ReadPolyLine(out loadError, true, boundary, out polyLineIsClosed); break; } return(!loadError && (polyLineIsClosed || !closedPolyLinesOnly)); }
/* Todo: Extrusion not supported * private bool CheckExtrusionRecord(DXFRecord rec) * { * // Returns True if the record is a non default extrusion record * * return ((rec.recType == 210) && (rec.r != 0.0)) || * ((rec.recType == 220) && (rec.r != 0.0)) || * ((rec.recType == 230) && (rec.r != 1.0)); * } */ /// <summary> /// Reads the entirety of a polyline from the DXF file /// </summary> /// <param name="loadError"></param> /// <param name="lwPolyLine"></param> /// <param name="entity"></param> /// <param name="polyLineIsClosed"></param> public void ReadPolyLine(out bool loadError, bool lwPolyLine, PolyLineBoundary entity, out bool polyLineIsClosed) { const double EPSILON = 0.000001; int FetchIndex; int NumArrayEntries; DXFRecord rec; XYZ lastPt = XYZ.Null, pt; bool PaperSpace; // Todo: Extrusion is not taken into account // bool extruded; long PolyLineFlags; // double bulge; long NVertices; long VertexNum; long CurveSmoothing; // Todo extrusion not supported XYZ Extrusion; bool PolyLineIs3D; double DefaultPolyLineHeight; var ExtendedAttrName = ""; var PolyLineRecords = new List <DXFRecord>(); // This function allows us to reread the first few record in the poly line. bool GetDXFRecord(out DXFRecord record) { if (FetchIndex < NumArrayEntries) { record = PolyLineRecords[FetchIndex]; FetchIndex++; return(true); } return(ReadDXFRecord(out record)); } void LoadSimplePolyLine() { // Load all vertices in the poly line var FirstPoint = true; while ((rec.s == "VERTEX") || (lwPolyLine && (VertexNum < NVertices))) { // double nextBulge = 0; var VertexFlags = 0; var Rec10Count = 0; pt.Z = Consts.NullDouble; do { if (!GetDXFRecord(out rec)) { return; } switch (rec.recType) { case 10: Rec10Count++; if (Rec10Count == 1) { pt.X = rec.r * DXFImportConvFactor; } break; case 20: pt.Y = rec.r * DXFImportConvFactor; break; case 30: if (PolyLineIs3D) { pt.Z = rec.r * DXFImportConvFactor; } break; // case 42: // nextBulge = rec.r; // break; // case 62 : ; //SetPen (pen,rec.i); // break; case 70: VertexFlags = (ushort)rec.i; break; } } while (!(rec.recType == 0 || (lwPolyLine && Rec10Count == 2))); // If we are reading in a 2D poly line, then the heights of all the // vertices in the poly line should be set to the elevation read in from // the 38 field in the POLY LINE entity (ie: any elevation read in for // the vertex is discarded. This also applies to LW POLY LINE entities. // Note: This could have been achieved by initializing // the value of pt.z before the repeat loop, but this explicit // behaviour is more evident as to its purpose. if (!PolyLineIs3D) { pt.Z = DefaultPolyLineHeight; } // Todo: Extrusion is not taken into account //if (extruded && !PolyLineIs3D) // AdjustForExtrusion(pt.x, pt.y, pt.z, Extrusion); if (lwPolyLine) { FetchIndex--; // Reprocess the last record VertexNum++; } if ((VertexFlags & kSplineFrameControlPointFlag) != kSplineFrameControlPointFlag) { bool IsDuplicateVertex; if (FirstPoint) { IsDuplicateVertex = false; } else { IsDuplicateVertex = (Math.Abs(pt.X - lastPt.X) < EPSILON) && (Math.Abs(pt.Y - lastPt.Y) < EPSILON) && (!PolyLineIs3D || (Math.Abs(pt.Z - lastPt.Z) < EPSILON)); } // Determine if the vertex we have just read in is the same as the previous vertex. // If it is, then don't create entities for it if (!IsDuplicateVertex) { // Add the vertex to the fence entity.Boundary.Points.Add(new FencePoint(pt.X, pt.Y)); } // bulge = nextBulge; if (!IsDuplicateVertex) { FirstPoint = false; lastPt = pt; } } } } void ProcessNonVertexRecord() { switch (rec.recType) { case 8: //load := SetCurrentLayer (rec.s,pen); break; // 30 record is height for all vertices in a 2D poly line case 30: DefaultPolyLineHeight = rec.r * DXFImportConvFactor; break; // 38 record is height for all vertices in a lightweight poly line case 38: DefaultPolyLineHeight = rec.r * DXFImportConvFactor; break; case 62: //SetPen (pen,rec.i); break; case 67: PaperSpace = rec.i != 0; break; case 70: PolyLineFlags = rec.i; break; case 75: /*Curves and smooth surface type (optional; default = 0); integer codes, not bit-coded: * 0 = No smooth surface fitted * 5 = Quadratic B-spline surface * 6 = Cubic B-spline surface * 8 = Bezier surface */ CurveSmoothing = rec.i; break; case 90: NVertices = rec.i; break; /* Todo: Extrusion not supported * case 210: * Extrusion.X = rec.r; * break; * case 220: * Extrusion.Y = rec.r; * break; * case 230: * Extrusion.Z = rec.r; * break; */ case 1001: ExtendedAttrName = rec.s.ToUpper(CultureInfo.InvariantCulture); // Registered application name (up to 31 bytes) in extended data break; case 1000: // ASCII string in extended attrs (up to 255 bytes) case 1070: if (ExtendedAttrName == "TRIMBLEBNDYTYPE") { entity.Type = (DXFLineWorkBoundaryType)rec.i; } else if (ExtendedAttrName == "TRIMBLENAME") { entity.Name = rec.s; } break; } } bool IsPolyLineClosed() { XYZ pt_start, pt_end; var SavedFetchIndex = FetchIndex; // Start vertex... pt_start.X = PolyLineRecords[FetchIndex].r * DXFImportConvFactor; pt_start.Y = PolyLineRecords[FetchIndex + 1].r * DXFImportConvFactor; if (PolyLineIs3D) { pt_start.Z = PolyLineRecords[FetchIndex + 2].r * DXFImportConvFactor; } else { pt_start.Z = Consts.NullDouble; } do { if (!GetDXFRecord(out rec)) { return(false); } } while (rec.recType != 0); // End vertex... if (PolyLineIs3D) { pt_end.Z = PolyLineRecords[FetchIndex - 2].r * DXFImportConvFactor; pt_end.Y = PolyLineRecords[FetchIndex - 3].r * DXFImportConvFactor; pt_end.X = PolyLineRecords[FetchIndex - 4].r * DXFImportConvFactor; } else { pt_end.Y = PolyLineRecords[FetchIndex - 2].r * DXFImportConvFactor; pt_end.X = PolyLineRecords[FetchIndex - 3].r * DXFImportConvFactor; pt_end.Z = Consts.NullDouble; } FetchIndex = SavedFetchIndex; return((Math.Abs(pt_start.X - pt_end.X) < EPSILON) && (Math.Abs(pt_start.Y - pt_end.Y) < EPSILON) && (!PolyLineIs3D || (Math.Abs(pt_start.Z - pt_end.Z) < EPSILON))); } loadError = true; PaperSpace = false; // Todo extruded = false; // bulge = 0; NVertices = 0; VertexNum = 0; PolyLineFlags = 0; DefaultPolyLineHeight = Consts.NullDouble; CurveSmoothing = 0; // Todo Extrusion = DefaultExtrusion; pt = XYZ.Null; polyLineIsClosed = false; //-------------------------------------------- // This is a bit grubby, but in my defense we had to handle extrusions for // LW POLY LINE entities. In this case we have to read the entire entity looking // for extrusion records before we use the point. FetchIndex = 0; do { if (!ReadDXFRecord(out rec)) { return; } ProcessNonVertexRecord(); PolyLineRecords.Add(rec); FetchIndex++; } while (rec.recType != 0); // Start of next entity polyLineIsClosed = (PolyLineFlags & kPolylineIsClosed) == kPolylineIsClosed; PolyLineIs3D = !lwPolyLine && (((PolyLineFlags & kPolylineIs3D) == kPolylineIs3D) || ((PolyLineFlags & kPolylineIsPolyfaceMesh) == kPolylineIsPolyfaceMesh)); // Todo: extruded = CheckExtrusionRecord(Extrusion); NumArrayEntries = FetchIndex; if (lwPolyLine) { _reuseRecord = true; // load_entities needs to read this record } //-------------------------------------------- // Read poly line header values FetchIndex = 0; // Reprocess the records that have already been read. do { if (!GetDXFRecord(out rec)) { return; } ProcessNonVertexRecord(); } while (!((rec.recType == 0) || (lwPolyLine && (rec.recType == 10)))); // Start of first vertex //-------------------------------------------- if (lwPolyLine) { FetchIndex--; // Reprocess the last record } // Check whether the poly line is closed if the internal flag indicates it is not... polyLineIsClosed = polyLineIsClosed || (lwPolyLine && IsPolyLineClosed()); if (!PaperSpace) { if ((PolyLineFlags & kPolylineIsPolyfaceMesh) == kPolylineIsPolyfaceMesh) { // We no longer load poly face meshes as background line work... } else // It's a poly line of some form { if (!lwPolyLine && (CurveSmoothing == kQuadraticBSplineSmoothing) || (CurveSmoothing == kCubicBSplineSmoothing)) { // Spline fit poly lines are not supported here } else { LoadSimplePolyLine(); } } } else { // ReSharper disable once StringLiteralTypo // Scan past SEQ END for standard 3D poly lines if (!lwPolyLine) { while ((rec.recType != 0) || (rec.s != "SEQEND")) { if (!ReadDXFRecord(out rec)) { return; } } } } loadError = false; }