ixmilia / dxf

MIT License
218 stars 67 forks source link

Hatch creation issue #167

Closed AFriendlyGuy closed 2 years ago

AFriendlyGuy commented 2 years ago

The creation of a hatch yielded an dxf file, which AutoCAD 2022 could not read.

The hatch was created like this (inspired by #136):

var file = new DxfFile();
var header = file.Header;
header.SetDefaults();
header.Version = DxfAcadVersion.R2018;
var boundaryPath = new DxfHatch.NonPolylineBoundaryPath(DxfHatch.BoundaryPathType.Polyline);
for(var i=0; i < v.Length-1; ++i)
  boundaryPath.Edges.Add(new DxfHatch.LineBoundaryPathEdge() { StartPoint =v[i], EndPoint =v[i+1] });
boundaryPath.Edges.Add(new DxfHatch.LineBoundaryPathEdge() { StartPoint = v[^1], EndPoint = v[0] });            
var hatch = new DxfHatch { PatternName = "SOLID" };
hatch.BoundaryPaths.Add(boundaryPath);
file.Entities.Add(hatch);
file.Normalize();
file.Save("Test.dxf", true);

The error message in AutoCAD was the following (translated from German):

The following error was detected while reading
in HATCH starting at line 1930:
Error: Group code 71 expected.
Invalid or incomplete DXF input -- drawing aborted.

Here is the relevant part from the dxf file starting at line 1930, it contains the code 71:

HATCH
  5
1D
100
AcDbEntity
  8
0
370
     0
430

440
        0
284
     0
100
AcDbHatch
 10
0.0
 20
0.0
 30
0.0
210
0.0
220
0.0
230
1.0
  2
SOLID
 70
     0
 63
   256
 71
     0
 91
        1
 92
        2
 93
        4
 72
     1
 10
860116.930352756
 20
5794971.436
 11
860116.930352756
 21
5794999.004
 72
     1
 10
860116.930352756
 20
5794999.004
 11
860112.9501
 21
5794999.004
 72
     1
 10
860112.9501
 20
5794999.004
 11
860112.9501
 21
5794971.436
 72
     1
 10
860112.9501
 20
5794971.436
 11
860116.930352756
 21
5794971.436
 97
        0
 75
     0
 76
     0
 52
0.0
 41
1.0
 77
     0
 78
     0
 47
1.0
 98
        0
450
        0
451
        0
452
        0
453
        0
460
0.0
461
0.0
462
0.0
463
0.0
470
LINEAR

A hatch generated from within AutoCAD looks slightly different:

HATCH
  5
2BC
330
1F
100
AcDbEntity
  8
0
100
AcDbHatch
 10
0.0
 20
0.0
 30
0.0
210
0.0
220
0.0
230
1.0
  2
SOLID
 70
     1
 71
     1
...
brettfo commented 2 years ago

Can you check something for me? It looks like the difference is that AutoCAD generated codes 2, 70, 71, but this library generated 2, 70, 63, 71. Can you manually swap the 63 and 71 codes and try to open that? You can use Notepad or any basic text editor to make the relevant portion of the file read:

...
  2
SOLID
 70
     0
 71
     0
 63
   256
...
AFriendlyGuy commented 2 years ago

The swap changes the error message to "code 91 expected". Swapping this code also changes the error message. It looks like the order of the code should be exactly the same as in the case generated by AutoCAD. I adjusted the order until I got the error message "code 73 expected". According to the specs this is the code for the "Is closed"-flag for the polyline boundary data. It is missing in the output of the library.

Maybe the problem is

92
2

which indicates that the boundary is a polyline despite the fact that I used NonPolylineBoundaryPath.

AFriendlyGuy commented 2 years ago

I changed the c# code to generate a polyline boundary path:

var boundaryPath = new DxfHatch.PolylineBoundaryPath { IsClosed = true };
for(var i=0; i < v.Length; ++i)
  boundaryPath.Vertices.Add(new DxfVertex(v[i]));                       
var hatch = new DxfHatch {
  FillMode = DxfHatchPatternFillMode.SolidFill,
  FillColor = DxfColor.FromIndex(color),
  PatternName = "SOLID",
};
hatch.BoundaryPaths.Add(boundaryPath);

Then I had to do the following adjustments (left side version accepted by AutoCAD, right side library output): grafik

brettfo commented 2 years ago

Thank you for figuring out the correct order of the codes, this is hugely valuable. Ultimately the fix is going to need to exist in EntitiesSpec.xml and I'd like it if the changes somewhat matched what the 2018 spec says about HATCH.

  1. For code 63 that apparently needs to be removed, the spec says "For MPolygon, pattern fill color as the ACI". There are several properties with the predicate "For MPolygon", but I don't see what would classify a hatch as an MPolygon. Admittedly I'm not terribly familiar with the intricacies of AutoCAD, do you know what "MPolygon" could refer to? If we can figure out when this value should be written or suppressed, a WriteCondition="" could be added here.
  2. Code 78 is written here, I'm guessing a write condition should be added along the lines of PatternDefinitionLines.Count != 0.
  3. Code 47 for pixel size. The spec mentions "for associative hatches and hatches created with the Flood method of hatching" and code 71 specifies if the hatch is associative, so perhaps a write condition of IsAssociative would suffice? I'm not sure what "Flood" means in this context, though.
  4. Codes 452 and 453. It looks like these just need to be moved down a bit?
  5. Code 463. The spec says it's reserved, so perhaps writing this value should be disabled?

What are your thoughts on the above? I can work on some changes to address items 2-5, but I don't know what to do about item 1, code 63 and "MPolygon".

AFriendlyGuy commented 2 years ago

I am not an expert on AutoCAD or DXF files. I am just trying to write an DXF-export for my tool. Having said this, here are my guesses: Concerning MPolygon the specs says in the very beginning:

The following group codes apply to hatch and MPolygon entities.

I would conclude that MPolygon is a different kind of entity which happens to be very similar to a hatch and shares most of the group codes. But I have no idea how to create a MPolygon in AutoCAD.

Concering 3.: Maybe it is better to related it to code 70 == 0 (pattern fill)? The specs says

... in hatch pattern computation for associative hatches ...

I agree with you on the other points.

brettfo commented 2 years ago

I've added a branch write-hatch with some changes, can you see if it helps your scenario?

It includes the following changes from above:

  1. I simply omit writing code 63. I have no idea what "MPolygon" could mean; I'll have to revisit this.
  2. Added the appropriate write condition for code 78.
  3. I combined both of our suggestions and made the write condition FillMode == DxfHatchPatternFillMode.SolidFill || IsAssociative. That way the "for associative hatches" condition is met as well as "hatches created with [] Flood" (I'm equating SolidFill with Flood.)
  4. Codes 452 and 453 have been moved.
  5. Code 463 has been removed.
AFriendlyGuy commented 2 years ago

Everything is fine now except the condition FillMode == DxfHatchPatternFillMode.SolidFill || IsAssociative did not work for me. One can have solid fill and still AutoCAD does not expect the group code 47. After changing it to IsAssociative as you proposed in the beginning it worked for me.

brettfo commented 2 years ago

Can you clarify some points for me?

  1. You mention that code 42 was unexpected. HATCH doesn't use this code, presumably this was a typo for 47?
  2. What exactly is the condition that worked for you? FillMode is an enum with values of PatternFill (0) and SolidFill (1), while IsAssociative is a bool.
AFriendlyGuy commented 2 years ago

Sorry for the confusion. It was already late yesterday when I wrote the comment and I got disturbed several times. I corrected it. What I meant was:

I played around with AutoCAD to generate a hatch containing group code 47, but I was not successful. Instead AutoCAD just froze quite frequently.

brettfo commented 2 years ago

I've force-pushed to the write-hatch branch with your condition change. If you could give it a quick check to make sure I set the condition appropriately, I'll merge this back to main.

AFriendlyGuy commented 2 years ago

The current version of write-hatch works for me.

brettfo commented 2 years ago

Thanks for checking, I've merged these changed back to main via commit 38ecfd51d3222dab5dd5ef7198327823133ef997.