private HatchBoundaryPath ReadEdgeBoundaryPath(int numEdges) { // the information of the boundary path data always appear exactly as it is read List<HatchBoundaryPath.Edge> entities = new List<HatchBoundaryPath.Edge>(); this.chunk.Next(); while (entities.Count < numEdges) { // Edge type (only if boundary is not a polyline): 1 = Line; 2 = Circular arc; 3 = Elliptic arc; 4 = Spline HatchBoundaryPath.EdgeType type = (HatchBoundaryPath.EdgeType) this.chunk.ReadShort(); switch (type) { case HatchBoundaryPath.EdgeType.Line: this.chunk.Next(); // line double lX1 = this.chunk.ReadDouble(); // code 10 this.chunk.Next(); double lY1 = this.chunk.ReadDouble(); // code 20 this.chunk.Next(); double lX2 = this.chunk.ReadDouble(); // code 11 this.chunk.Next(); double lY2 = this.chunk.ReadDouble(); // code 21 this.chunk.Next(); HatchBoundaryPath.Line line = new HatchBoundaryPath.Line { Start = new Vector2(lX1, lY1), End = new Vector2(lX2, lY2) }; entities.Add(line); break; case HatchBoundaryPath.EdgeType.Arc: this.chunk.Next(); // circular arc double aX = this.chunk.ReadDouble(); // code 10 this.chunk.Next(); double aY = this.chunk.ReadDouble(); // code 40 this.chunk.Next(); double aR = this.chunk.ReadDouble(); // code 40 this.chunk.Next(); double aStart = this.chunk.ReadDouble(); // code 50 this.chunk.Next(); double aEnd = this.chunk.ReadDouble(); // code 51 this.chunk.Next(); bool aCCW = this.chunk.ReadShort() != 0; // code 73 this.chunk.Next(); HatchBoundaryPath.Arc arc = new HatchBoundaryPath.Arc { Center = new Vector2(aX, aY), Radius = aR, StartAngle = aStart, EndAngle = aEnd, IsCounterclockwise = aCCW }; entities.Add(arc); break; case HatchBoundaryPath.EdgeType.Ellipse: this.chunk.Next(); // elliptic arc double eX = this.chunk.ReadDouble(); // code 10 this.chunk.Next(); double eY = this.chunk.ReadDouble(); // code 20 this.chunk.Next(); double eAxisX = this.chunk.ReadDouble(); // code 11 this.chunk.Next(); double eAxisY = this.chunk.ReadDouble(); // code 21 this.chunk.Next(); double eAxisRatio = this.chunk.ReadDouble(); // code 40 this.chunk.Next(); double eStart = this.chunk.ReadDouble(); // code 50 this.chunk.Next(); double eEnd = this.chunk.ReadDouble(); // code 51 this.chunk.Next(); bool eCCW = this.chunk.ReadShort() != 0; // code 73 this.chunk.Next(); HatchBoundaryPath.Ellipse ellipse = new HatchBoundaryPath.Ellipse { Center = new Vector2(eX, eY), EndMajorAxis = new Vector2(eAxisX, eAxisY), MinorRatio = eAxisRatio, StartAngle = eStart, EndAngle = eEnd, IsCounterclockwise = eCCW }; entities.Add(ellipse); break; case HatchBoundaryPath.EdgeType.Spline: this.chunk.Next(); // spline short degree = (short) this.chunk.ReadInt(); // code 94 this.chunk.Next(); bool isRational = this.chunk.ReadShort() != 0; // code 73 this.chunk.Next(); bool isPeriodic = this.chunk.ReadShort() != 0; // code 74 this.chunk.Next(); int numKnots = this.chunk.ReadInt(); // code 95 double[] knots = new double[numKnots]; this.chunk.Next(); int numControlPoints = this.chunk.ReadInt(); // code 96 Vector3[] controlPoints = new Vector3[numControlPoints]; this.chunk.Next(); for (int i = 0; i < numKnots; i++) { knots[i] = this.chunk.ReadDouble(); // code 40 this.chunk.Next(); } for (int i = 0; i < numControlPoints; i++) { double x = this.chunk.ReadDouble(); // code 10 this.chunk.Next(); double y = this.chunk.ReadDouble(); // code 20 this.chunk.Next(); // control point weight might not be present double w = 1.0; if (this.chunk.Code == 42) { w = this.chunk.ReadDouble(); // code 42 this.chunk.Next(); } controlPoints[i] = new Vector3(x, y, w); } // this information is only required for AutoCAD version 2010 and newer // stores information about spline fit point (the spline entity does not make use of this information) if (this.doc.DrawingVariables.AcadVer >= DxfVersion.AutoCad2010) { int numFitData = this.chunk.ReadInt(); // code 97 this.chunk.Next(); for (int i = 0; i < numFitData; i++) { //double fitX = this.chunk.ReadDouble(); // code 11 this.chunk.Next(); //double fitY = this.chunk.ReadDouble(); // code 21 this.chunk.Next(); } // the info on start tangent might not appear if (this.chunk.Code == 12) { //double startTanX = this.chunk.ReadDouble(); // code 12 this.chunk.Next(); //double startTanY = this.chunk.ReadDouble(); // code 22 this.chunk.Next(); } // the info on end tangent might not appear if (this.chunk.Code == 13) { //double endTanX = this.chunk.ReadDouble(); // code 13 this.chunk.Next(); //double endTanY = this.chunk.ReadDouble(); // code 23 this.chunk.Next(); } } HatchBoundaryPath.Spline spline = new HatchBoundaryPath.Spline { Degree = degree, IsPeriodic = isPeriodic, IsRational = isRational, ControlPoints = controlPoints, Knots = knots }; entities.Add(spline); break; } } HatchBoundaryPath path = new HatchBoundaryPath(entities); // read all referenced entities Debug.Assert(this.chunk.Code == 97, "The reference count code 97 was expected."); int numBoundaryObjects = this.chunk.ReadInt(); this.hatchContourns.Add(path, new List<string>(numBoundaryObjects)); this.chunk.Next(); for (int i = 0; i < numBoundaryObjects; i++) { Debug.Assert(this.chunk.Code == 330, "The reference handle code 330 was expected."); this.hatchContourns[path].Add(this.chunk.ReadString()); this.chunk.Next(); } return path; }
// TODO: apply the transformation directly to edges public void TransformBy2(Matrix3 transformation, Vector3 translation) { if (this.associative) { this.UnLinkBoundary(); } Vector3 newNormal = transformation * this.Normal; if (Vector3.Equals(Vector3.Zero, newNormal)) { newNormal = this.Normal; } Matrix3 transOW = MathHelper.ArbitraryAxis(this.Normal); Matrix3 transWO = MathHelper.ArbitraryAxis(newNormal).Transpose(); Vector3 position = transOW * new Vector3(0.0, 0.0, this.Elevation); foreach (HatchBoundaryPath path in this.BoundaryPaths) { foreach (HatchBoundaryPath.Edge edge in path.Edges) { switch (edge.Type) { case HatchBoundaryPath.EdgeType.Arc: break; case HatchBoundaryPath.EdgeType.Ellipse: break; case HatchBoundaryPath.EdgeType.Line: HatchBoundaryPath.Line line = (HatchBoundaryPath.Line)edge; Vector3 start = new Vector3(line.Start.X, line.Start.Y, 0.0); Vector3 end = new Vector3(line.End.X, line.End.Y, 0.0); // to world coordinates start = transOW * start + position; end = transOW * end + position; // transformation start = transformation * start + translation; end = transformation * end + translation; Vector3 point; point = transWO * start; line.Start = new Vector2(point.X, point.Y); point = transWO * end; line.End = new Vector2(point.X, point.Y); break; case HatchBoundaryPath.EdgeType.Polyline: break; case HatchBoundaryPath.EdgeType.Spline: break; } } } position = transformation * position + translation; position = transWO * position; Vector2 refAxis = Vector2.Rotate(Vector2.UnitX, this.Pattern.Angle * MathHelper.DegToRad); refAxis = this.Pattern.Scale * refAxis; Vector3 v = transOW * new Vector3(refAxis.X, refAxis.Y, 0.0); v = transformation * v; v = transWO * v; Vector2 axis = new Vector2(v.X, v.Y); double newAngle = Vector2.Angle(axis) * MathHelper.RadToDeg; double newScale = axis.Modulus(); newScale = MathHelper.IsZero(newScale) ? MathHelper.Epsilon : newScale; this.Pattern.Scale = newScale; this.Pattern.Angle = newAngle; this.Elevation = position.Z; this.Normal = newNormal; }