1

I am implementing a DXF importer, for now I am taking into consideration the HEADER section and only one variable from it INSUNITS, TABLES section only one table BLOCK_RECORD table, BLOCKS section, ENTITIES section (INSERT, LINE, LWPOLYLINE, ARC, CIRCLE).

When importing I don't know if I need to take into consideration units, and if I need to, I don't know how exactly to take this into consideration. My file is not imported in the correct way now, it is most likely due to these units as I think I am doing my INSERT transformations correctly:

EXTRUSIONDIRECTIONTRANSFORMATION * 
     INSERTIONPOINTTRANSLATION * 
     ROTATION * SCALING * BASEPOINTTRANSLATION

A file I am importing is imported in the correct way when I remove the BASEPOINTTRANSLATION, but some other files are not imported in the right way and some parts of the drawing get imported very far away from rest.

It looks to me like the base point of a block is in inches and when I convert it to meters it becomes a bit better. So if someone knows in which order I should do the transformations and how to handle units in DXF files I would be really grateful as I am stuck now.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
SMpersonal
  • 35
  • 5
  • I could try to locate my old code base to see how I did this, or, you could do what I did: create lots of tiny examples, first with no transformations, then we one component, then two, and so on, to figure out how to get results identical to AutoCAD. – 500 - Internal Server Error Dec 09 '21 at 23:17
  • I did that already, so basically I looked at a program that seems to do it right, made some samples and made transformations according to that, but then when I use something made in Autocad I get the problem that the base point translation shifts everything really far away, so I suspected that it has something to do with units, and in the DXF reference the units have not been explained in a very intuitive way, if you could pls send me the codebase. I actually looked at quite a few codebases and everyone does it differently. And the program that I know does it right is not open source. – SMpersonal Dec 09 '21 at 23:45

1 Answers1

1

In the Python ezdxf package, I do it that way:

  1. Start matrix M0 = OCS transformation matrix including the scaling of the x-, y- and z-axis; same as OCS transformation matrix * scaling matrix
  2. rotation matrix M1 about the extrusion vector
  3. transformation matrix M= M0 * M1
  4. adding the translation to the insert point
    • transform the insert point from the OCS to WCS
    • transform the block_base_point by the current matrix M without translation, the current state of M doesn't have a translation yet, so a full transformation wouldn't be a problem but a "direction only" transformation is faster in my code
    • subtract the block_base_point from the insert point
    • set last row of M to (insert.x, insert.y, insert.z, 1) if row major order, last column if column major order, which is basically M * translation matrix

the Python code at github

The unit scaling can be ignored, the CAD application has to set the correct scaling values to match parent layout units and block reference units in the INSERT scaling attributes. E.g. if you insert a block with mm-units into a modelspace with m-units, the scaling values of the INSERT entity have to be 0.001 to convert the millimeters into meters (1mm = 0.001m).

mozman
  • 2,001
  • 8
  • 23
  • Thank you, it seems like I already had the right order of transformations I just did it in a different way. When I import the file it is still not imported in the right way. I am importing this into a 3D viewer which can accept multiple DXF files and OBJ files and have them in the same world, this viewer expects coordinates in meters. Each block definition has an associated block record, and each insert has an associated block record, do I just do conversions from units inside of blocks block record to units inside of inserts block record and then keep doing this? Then convert to meters? – SMpersonal Dec 10 '21 at 19:26
  • 1
    As I said in the last paragraph in my answer, the correct scaling has to be set in the INSERT entity by the CAD application which created the DXF file. The associated BLOCK_RECORD in the BLOCK and the INSERT entity (tag 330) is the owner of the entity and a central DXF structure. Each layout (model space, paper space, block layout) requires and has such a BLOCK_RECORD, this BLOCK_RECORD is the owner of all entities in the layout. If you really have to convert units, its from units of the BLOCK_RECORD of the BLOCK to the units of the BLOCK_RECORD of the INSERT. – mozman Dec 11 '21 at 03:55
  • And what if I am converting from unitless to inches or inches to unitless, in that case what should my scaling factor do? I have a sample in which every BLOCK_RECORD has units unitless and the INSUNITS header variable has units inches. Also should I not touch the transformation you stated when doing this unit conversion just add to the scaling part the conversion factor or should I also do something else with the conversion factor, right now I am multiplying it with the xfactor, yfactor and zfactor of the INSERT entity. Sorry for the questions, but the DXF reference is really bad. – SMpersonal Dec 11 '21 at 14:56
  • You cannot convert from unitless to any unit without knowing the source unit. Use Autodesk's Trueview application as a DXF viewer to compare the result with your rendering. It uses the AutoCAD rendering engine which defines and displays the correct interpretation of the DXF "standard" used by Autodesk. And to repeat it again: For DXF files from reliable CAD applications such as AutoCAD, BricsCAD, GstarCAD or ZWCAD, you do not have to perform any scaling for the unit conversion yourself. – mozman Dec 11 '21 at 19:00