haplokuon / netDxf

.net dxf Reader-Writer
MIT License
990 stars 401 forks source link

Incorrect settings of insertion of the block attributes #245

Closed iborzenkov closed 3 years ago

iborzenkov commented 3 years ago

I have a block placed in a DXF file. I load it into my program using NetDXF, visualize it in some way, also I initialize some of the block attributes. Then I upload it back to DXF, again using NetDXF. In fact, I perform actions in my program similar to the usual block insertion in AutoCAD. However, the result is different.

I brought them in the picture 24-12-2020 13-32-09

On the left is a block inserted using AutoCAD, on the right is a block inserted using NetDXF. I will pay attention to the block attributes, the ObliqueAngle, WidthFactor and Height parameters are incorrect.

To make it easier to reproduce the error, debug and fix the problem, I created an unit test. The original DXF file that is mentioned in the unit test can be found here.

I see problems in the Attribute.TransformBy(Matrix3 transformation, Vector3 translation); method.

I solved my problems by adding the logic of rounding instead newObliqueAngle = 90 + (newRotation - newObliqueAngle); I using newObliqueAngle = Math.Round(90 + (newRotation - newObliqueAngle), 0, MidpointRounding.AwayFromZero); for my tasks, angles accurate to whole degrees are enough. But this solution may not be suitable for other users.

haplokuon commented 3 years ago

Your issue is the typical rounding error when working with sines and cosines. A similar issue as yours may affect transformations of attribute definitions and texts. If you need a quick fix for it go to the MathHelper.NormalizeAngle and where is says:

if (IsZero(normalized))

write

if (IsZero(normalized) || IsEqual(Math.Abs(normalized), 360.0))

As a side note, I've seen in your example you are calling the Sync() method of the Insert where the TransformAttributes() method is all you need. While the Sync() will also modify the attributes properties to accommodate the transformation state of the insertion, it will also add and delete attributes in the list to synchronize it to the attribute definitions list defined in the block. The TransformAttributes() only transform them, making changes to the insert position, rotation, normal, and/or scale; when changing the block origin and/or units; or even the document insertion units will require this method to be called manually. In your case you are only modifying the insert rotation property therefore a call to TransformAttributes() is all you need.