This project has moved. For the latest updates, please go here.

Load and display Entities

Sep 11, 2015 at 9:33 AM
Hi everyone,
I am trying to load and display all the content of my .dxf file.
For that I proceed as follows (just a simplification):
 var doc = DxfDocument.Load(Filename);
 foreach(var block in doc.Blocks)
 {
      foreach(var entitiy in block.Entities)
      {
           if(entity.IsVisible)
              //Drawmethod depending on entitytype
      }
 }
If there is an entityobject of type "insert" than I call the draw methods for the objects inside the block of the insert object.
As a result I recieve an image where some elements are dipsplayed twice, but switched.
For instance, my .dxf file contains a vessel than there is the crane of the vessel displayed at two different positions.
Is there a property or method to figure out which block or entity has to be displayed and which are just footing for inserts ?
Coordinator
Sep 11, 2015 at 6:31 PM
First remember, an insert is a block reference, and the block its definition, multiple instances of the same block might appear in a drawing, you might even have blocks not referenced by any insert. A block is not an entity, therefore it is not an object that should be drawn.

You have to read the Insert entities and transform the entities contained in its block definition to know the final position of the entities that make the block. Check the Insert entity class, under the "Explode" region there is some commented code that might help you. You should use that explode code as a guide, it is far from finished and it is not guaranteed to work under all circumstances.

You might like to take a look at the method "ShowDxfDocumentInformation" in the TestDxfDocument, it will show you how to access the information stored in a dxf.

Daniel
Sep 16, 2015 at 8:26 AM
Edited Sep 16, 2015 at 8:26 AM
Thank you very much.
Now I have each object only once and at the correct position.
Sep 22, 2015 at 7:53 AM
Hi,
I have an additonal question concerning the correct position, scale and rotation of an entity.
This time I have a .dxf file where inside my insert entity are additional inserts as well (which may have additional inserts as well). So my file looks like this.
Insert
     Line
     Circle
     Line
     Insert
           Line
           Line
     Line
     Text
Do I have to combine the information for position, scaling and rotation of the "sub" inserts with the information of the "main" insert and if so, how do I have to do that ?
Coordinator
Sep 25, 2015 at 6:57 PM
Yes, you will have to concatenate the transformations. When you have nested Insert entities the world coordinate system of the child insert is the local coordinate system of its parent. The insert's method GetTransformation should help you.

Daniel
Apr 11, 2016 at 10:34 AM
Thank you very much for your help until now :)

Right now I am facing another issue concerning the display of ellipses. In the current dxf file there are a lot ellipses and in some cases there are negative values for scaling and/or a negative z-coordinate for the normal vector.
I have checked your ProcessEllipse method inside the insert.cs file, but this is not working in that case.
So I tried to expand this method to handle even those special cases but nevertheless it is not working either.
This is my code (i think that this might look quite confusing, I am sorry for that)
Ellipse copy = (Ellipse)ellipse.Clone();
copy.Center = trans * ellipse.Center + pos;
copy.Rotation += rotation;
copy.Normal = trans * ellipse.Normal;
if (copy.Normal.Z < 0)
{
    copy.MajorAxis = ellipse.MinorAxis * Math.Abs(scale.X);
    copy.MinorAxis = ellipse.MajorAxis * Math.Abs(scale.Y);
    copy.Rotation += 180.0;
}
else
{
    copy.MajorAxis = ellipse.MajorAxis * Math.Abs(scale.X);
    copy.MinorAxis = ellipse.MinorAxis * Math.Abs(scale.Y);
}
if (scale.X < 0 || scale.Y < 0)
{
     var endAngle = copy.EndAngle;
     var startAngle = copy.StartAngle;
     copy.StartAngle = GetRotationFromScaling(endAngle, scale.X, scale.Y);
     copy.EndAngle = GetRotationFromScaling(startAngle, scale.X, scale.Y);
     copy.Rotation = GetRotationFromScaling(copy.Rotation, scale.X, scale.Y);
}
copy.Normal = new Vector3(copy.Normal.X, copy.Normal.Y, Math.Abs(copy.Normal.Z));                        
var pts = copy.ToPolyline(10);
// Draw the lines which are approximating the ellipse
The method "GetRotationFromScaling()" is changing the first value depending on the both scaling values:
var newRotate = 0.0;
if (scaleX < 0 && scaleY < 0)
   rotate += 180;
else
{
    if (scaleX < 0)
    {
        if (rotate > 180)
          newRotate = 180 - rotate + 360;
        else
          newRotate = 180 - rotate;
        rotate = newRotate;
     }
     if (scaleY < 0)
        rotate = 360 - rotate;
}
I really dont know how to handle this.
Thank you in advance.
Coordinator
Apr 15, 2016 at 6:43 PM
I cannot give you a specific answer without doing it myself. All that commented code in the Insert class was just a work in progress, it is far from finish, and as I said you before it is not guarantee to work. And in the case of the ellipse it still needs some work to make it work under all circumstances. One thing is to talk about it and another to actually develop the code to make it work. But I can give you a few hints from what I've seen in your code.

The values of parameters of the ellipse: major axis, minor axis, start angle, end angle, and rotation are local to its coordinate system. Therefore, to properly apply the scale of the insert to the ellipses that are part of the block, you have to transform the scale vector to the local coordinates of the ellipse taking into account its normal vector and its rotation.

The axis of the ellipse represent the dimensions along the local X and Y axis, so multiplying the X and Y components of the transformed scale should be enough. If I remember correctly AutoCad will show an error if the minor axis is greater than the major axis, if the scale is not uniform perhaps you might need to switch them. The Z component of the scale will have to be apply to the elevation.

The start and end angle needs a little more work. The easiest way is to convert the angle to a vector (cos,sin) and apply the scale to it, the resulting angle of the scaled vector will be the new angle value. As with the axis, you might need to switch the start and end angles.

If you can reduce the cases when the normal of the insert and the ellipse are the same , it should not give you too many problems. It starts to get more complicated when they are not the same, or when the scale is not uniform and the rotation ellipse is not one of the quadrants. You will need to test it to get the proper order of transformations.

Daniel