Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/ACadSharp.Tests/Entities/HatchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,39 @@ namespace ACadSharp.Tests.Entities
{
public class HatchTests : CommonEntityTests<Hatch>
{
[Fact]
public void BoundaryPathToEntityTest()
{
var a = new Hatch.BoundaryPath.Arc
{
Center = new XY(25, 0),
StartAngle = 0,
EndAngle = MathHelper.HalfPI,
Radius = 10,
CounterClockWise = true
};

ACadSharp.Entities.Arc arc = (Arc)a.ToEntity();

Assert.NotNull(arc);
Assert.Equal(a.Center.Convert<XYZ>(), arc.Center);
Assert.Equal(a.StartAngle, arc.StartAngle);
Assert.Equal(a.EndAngle, arc.EndAngle);
Assert.Equal(a.Radius, arc.Radius);

var l = new Hatch.BoundaryPath.Line
{
Start = new XY(25, 0),
End = new XY(25, 0)
};

ACadSharp.Entities.Line line = (Line)l.ToEntity();

Assert.NotNull(line);
Assert.Equal(l.Start.Convert<XYZ>(), line.StartPoint);
Assert.Equal(l.End.Convert<XYZ>(), line.EndPoint);
}

[Fact]
public void CreateHatch()
{
Expand Down
21 changes: 8 additions & 13 deletions src/ACadSharp.Tests/Entities/LineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ namespace ACadSharp.Tests.Entities
{
public class LineTests : CommonEntityTests<Line>
{
private CSMathRandom _random = new CSMathRandom();

[Fact]
public void TranslationTest()
{
Expand All @@ -26,7 +24,6 @@ public void TranslationTest()

AssertUtils.AreEqual(start.Add(move), line.StartPoint);
AssertUtils.AreEqual(end.Add(move), line.EndPoint);
AssertUtils.AreEqual(XYZ.AxisZ, line.Normal);
}

[Fact]
Expand Down Expand Up @@ -69,25 +66,23 @@ public void ScalingTest()
}

[Fact]
public void RandomTranslationTest()
public void ToPolylineTest()
{
XYZ start = this._random.Next<XYZ>();
XYZ end = this._random.Next<XYZ>();
var start = new XYZ(-1, -1, 0);
var end = new XYZ(1, 1, 0);
Line line = new Line
{
StartPoint = start,
EndPoint = end,
};

XYZ move = this._random.Next<XYZ>();
Transform translation = Transform.CreateTranslation(move);
line.ApplyTransform(translation);
var pline = line.ToPolyline();

AssertUtils.AreEqual(start.Add(move), line.StartPoint);
AssertUtils.AreEqual(end.Add(move), line.EndPoint);
Assert.NotNull(pline);
Assert.Equal(pline.Vertices[0].Location, start);
Assert.Equal(pline.Vertices[1].Location, end);
}


[Fact]
public override void GetBoundingBoxTest()
{
Expand All @@ -100,4 +95,4 @@ public override void GetBoundingBoxTest()
Assert.Equal(new XYZ(10, 10, 0), boundingBox.Max);
}
}
}
}
18 changes: 18 additions & 0 deletions src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ static WriterSingleObjectTests()
{
Data = new();
Data.Add(new(nameof(SingleCaseGenerator.Empty)));
Data.Add(new(nameof(SingleCaseGenerator.ArcToPolyline)));
Data.Add(new(nameof(SingleCaseGenerator.ArcSegments)));
Data.Add(new(nameof(SingleCaseGenerator.SingleEllipse)));
Data.Add(new(nameof(SingleCaseGenerator.SingleLine)));
Expand Down Expand Up @@ -319,6 +320,23 @@ public void ArcSegments()
this.Document.Entities.Add(l);
}

public void ArcToPolyline()
{
Arc arc = new Arc()
{
Center = new XYZ(100, 0, 0),
Radius = 50,
StartAngle = MathHelper.HalfPI,
EndAngle = Math.PI,
};

var pline = arc.ToPolyline();

this.Document.Entities.Add(arc);
this.Document.Entities.Add(pline);
}


public void ChangedEncoding()
{
this.Document.Header.CodePage = "gb2312";
Expand Down
75 changes: 74 additions & 1 deletion src/ACadSharp/Entities/Arc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,51 @@ public static Arc CreateFromBulge(XY p1, XY p2, double bulge)
};
}

/// <summary>
/// Calculates the bulge factor for an arc defined by its center, start point, end point, and direction.
/// </summary>
/// <remarks>The bulge factor is commonly used in geometric and CAD applications to represent arcs in polyline
/// definitions.</remarks>
/// <param name="center">The center point of the arc.</param>
/// <param name="start">The starting point of the arc.</param>
/// <param name="end">The ending point of the arc.</param>
/// <param name="clockWise">A value indicating whether the arc is drawn in a clockwise direction. <see langword="true"/> if the arc is
/// clockwise; otherwise, <see langword="false"/>.</param>
/// <returns>The bulge factor of the arc, which represents the tangent of one-fourth of the included angle. A positive value
/// indicates a counterclockwise arc, while a negative value indicates a clockwise arc.</returns>
public static double GetBulge(XY center, XY start, XY end, bool clockWise)
{
//TODO: add normal

XY u = start - center;
XY u2 = new XY(0.0 - u.Y, u.X);
XY v = end - center;
double angle = Math.Atan2(x: u.Dot(v), y: u2.Dot(v));
if (clockWise)
{
if (angle > 0.0)
{
angle -= MathHelper.PI * 2.0;
}
}
else if (angle < 0.0)
{
angle += MathHelper.PI * 2.0;
}

return Math.Tan(angle / 4.0);
}

/// <summary>
/// Calculates the bulge value corresponding to a given angle.
/// </summary>
/// <param name="angle">The angle, in radians, for which to calculate the bulge. The angle must be a finite value.</param>
/// <returns>The bulge value, which is the tangent of half the angle.</returns>
public static double GetBulgeFromAngle(double angle)
{
return Math.Tan(angle / 4);
}

/// <summary>
/// Get the center coordinate from a start, end an a bulge value.
/// </summary>
Expand Down Expand Up @@ -185,7 +230,7 @@ public static XY GetCenter(XY start, XY end, double bulge, out double radius)

double gamma = (Math.PI - theta) / 2;
double phi = (end - start).GetAngle() + Math.Sign(bulge) * gamma;
return new XY(start.X + radius * CSMath.MathHelper.Cos(phi), start.Y + radius * CSMath.MathHelper.Sin(phi));
return new XY(start.X + radius * MathHelper.Cos(phi), start.Y + radius * MathHelper.Sin(phi));
}

/// <inheritdoc/>
Expand Down Expand Up @@ -276,5 +321,33 @@ public override List<XYZ> PolygonalVertexes(int precision)
this.Normal.Normalize()
);
}

/// <inheritdoc/>
public override Polyline3D ToPolyline(int precision = byte.MaxValue)
{
var pline = new Polyline3D();
pline.Flags = PolylineFlags.Polyline3D;
pline.Thickness = this.Thickness;
pline.Normal = this.Normal;

this.GetEndVertices(out XYZ start, out XYZ end);

double bulge = Arc.GetBulge(
this.Center.Convert<XY>(),
start.Convert<XY>(),
end.Convert<XY>(),
false);

pline.Vertices.Add(new Vertex3D(start));
pline.Vertices.Add(new Vertex3D()
{
Location = end,
Bulge = bulge,
});

this.MatchProperties(pline);

return pline;
}
}
}
31 changes: 30 additions & 1 deletion src/ACadSharp/Entities/Circle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace ACadSharp.Entities
/// </remarks>
[DxfName(DxfFileToken.EntityCircle)]
[DxfSubClass(DxfSubclassMarker.Circle)]
public class Circle : Entity, ICurve
public class Circle : Entity, ICurve, IPolylineEquivalent
{
/// <summary>
/// Specifies the center of an arc, circle, ellipse, view, or viewport.
Expand Down Expand Up @@ -129,5 +129,34 @@ public virtual List<XYZ> PolygonalVertexes(int precision)
this.Normal.Normalize()
);
}

/// <inheritdoc/>
public virtual Polyline3D ToPolyline(int precision = byte.MaxValue)
{
var pline = new Polyline3D();
pline.IsClosed = true;
pline.Thickness = this.Thickness;
pline.Normal = this.Normal;

XYZ start = this.PolarCoordinateRelativeToCenter(0);
XYZ end = this.PolarCoordinateRelativeToCenter(MathHelper.PI);

double bulge = Arc.GetBulge(
this.Center.Convert<XY>(),
start.Convert<XY>(),
end.Convert<XY>(),
false);

pline.Vertices.Add(new Vertex3D(start));
pline.Vertices.Add(new Vertex3D()
{
Location = end,
Bulge = bulge,
});

this.MatchProperties(pline);

return pline;
}
}
}
2 changes: 2 additions & 0 deletions src/ACadSharp/Entities/Hatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ public double PatternScale
//varies
//Pattern line data.Repeats number of times specified by code 78. See Pattern Data
//11 For MPolygon, offset vector

//99 For MPolygon, number of degenerate boundary paths(loops), where a degenerate boundary path is a border that is ignored by the hatch
//99 For MPolygon, number of degenerate boundary paths(loops), where a degenerate boundary path is a border that is ignored by the hatch
/// <inheritdoc/>
public Hatch() : base() { }
Expand Down
4 changes: 2 additions & 2 deletions src/ACadSharp/Entities/IEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ public interface IEntity : IHandledCadObject, IGeometricEntity
LineWeightType GetActiveLineWeightType();

/// <summary>
/// Match the properties of this entity with another entity.
/// Matches the properties of the current entity to a specified entity.
/// </summary>
/// <param name="entity"></param>
/// <param name="entity">The entity whose properties will be matched. Cannot be <see langword="null"/>.</param>
void MatchProperties(IEntity entity);
}
}
19 changes: 19 additions & 0 deletions src/ACadSharp/Entities/IPolylineEquivalent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace ACadSharp.Entities
{
/// <summary>
/// Represents an object that can be converted to a 3D polyline representation.
/// </summary>
/// <remarks>This interface defines a contract for objects that can produce a <see cref="Polyline3D"/> instance,
/// which is a 3D representation of the object's geometry. Implementers of this interface should ensure that the
/// returned polyline accurately represents the object's shape.</remarks>
public interface IPolylineEquivalent
{
/// <summary>
/// Converts the current object to a 3D polyline representation.
/// </summary>
/// <param name="precision">The level of precision used for the conversion. Higher values result in a more detailed polyline. The value must be
/// between 0 and 255, inclusive. The default is <see cref="byte.MaxValue"/>.</param>
/// <returns>A <see cref="Polyline3D"/> representing the 3D polyline approximation of the current object.</returns>
Polyline3D ToPolyline(int precision = byte.MaxValue);
}
}
14 changes: 13 additions & 1 deletion src/ACadSharp/Entities/Line.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace ACadSharp.Entities
/// </remarks>
[DxfName(DxfFileToken.EntityLine)]
[DxfSubClass(DxfSubclassMarker.Line)]
public class Line : Entity
public class Line : Entity, IPolylineEquivalent
{
/// <summary>
/// A 3D coordinate representing the end point of the object.
Expand Down Expand Up @@ -90,5 +90,17 @@ public override BoundingBox GetBoundingBox()

return new BoundingBox(min, max);
}

/// <inheritdoc/>
public Polyline3D ToPolyline(int precision = 255)
{
var pline = new Polyline3D(this.StartPoint, this.EndPoint);
pline.Thickness = this.Thickness;
pline.Normal = this.Normal;

this.MatchProperties(pline);

return pline;
}
}
}
2 changes: 1 addition & 1 deletion src/ACadSharp/Entities/LwPolyLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public partial class LwPolyline : Entity, IPolyline
/// Polyline flags.
/// </summary>
[DxfCodeValue(70)]
public LwPolylineFlags Flags { get => _flags; set => _flags = value; }
public LwPolylineFlags Flags { get => this._flags; set => this._flags = value; }

/// <inheritdoc/>
public bool IsClosed
Expand Down
Loading
Loading