Scale drawing to fit into the frame

1
oleg
9/20/2006 1:24 AM

I'm sorry for stupid question. If I have frame drawing (with header, spec sheet etc), I'm dynamically creating construction drawing. How can I insert drawing into existent frame and rescale it to fit.

Wout
9/20/2006 9:08 AM

Hi,

The question is not stupid, it's currently not so easy to achieve this, but here's the how to:

You need to scale the objects so they will fit. To know how much to scale, you have to know its size, i.e. its bounding box. Class WW.Base.Bounds3D facilitates in calculating this bounding box. Now calculating the bounding box of e.g. a circle is a bit tricky. The thing to do is to draw it as line segments, and derive the bounding box from it. This is what the  GDIGraphics3D class can do for you. It's not really set up to make it comfortable (I should probably make a separate helper class for this), but here's how: First setup a DrawContext.ModelSpace object, as arguments pass in the model, a default GraphicsConfig object, an identity transfrom and the GDIGraphics3D object. Then call method DxfEntity.Draw, passing this DrawContext object. The entity will then draw itself onto the GDIGraphics3D object. You can repeat this for multiple entities, or alternatively e.g. draw a DxfInsert, and all it's children are drawn recursively. Once that's done you can query the bounding box using the GDIGraphics3D.BoundingBox method.

When you have the bounding box, there are several approaches to scaling your objects. One is using an insert/block, and set the DxfInsert.ScaleFactor. Alternatively you can use a DxfViewport and play with model space and paper space. This is harder to setup, you'll have to get acquainted with paper space/model space first and understand 3D to get this to work properly.

I'll add an easier bounding box calculator in the next release.

Kind regards,

Wout

oleg
9/21/2006 12:02 AM

Thanks,
I more like idea of block/insert. Correct me if I'm wrong - I have to add all my drawing entities to the block and rescale it on the insert.

Wout
9/21/2006 12:04 AM

Yup, you got it right!

Wout

aps_brar
5/30/2012 10:21 AM

My problem is on same lines but a little bit different, I have an existing template that has a border. I have to scale my entities (that are not on one block/insert but on different blocks/inserts) to fit within the border. Any help on how to achieve this will be appreciated.

Wout
5/31/2012 12:05 PM

Hi,

The easiest approach is to wrap your multiple inserts in a single block, and create a new insert that positions and scales your new block. Basically the approach is the same as mentioned above.

- Wout

aps_brar
6/1/2012 1:40 AM

I ended up doing it in another way.
Using BoundsCalculator i get bounds of all the inserts and then use DxfUtil.GetScaleTransform to get the scale (out param), scale all the inserts to this value and then get the bounds of scaled inserts again using BoundsCalculator, now just align all scaled inserts within the rectangle by changing insert.InsertionPoint

Here is the code
------------------------------------------------------------------------------------------------
        Point3D minToFitIn = new Point3D(30, 60, 0);
        Point3D maxToFitIn = new Point3D(558, 390, 0);
        BoundsCalculator boundsCalculator = new BoundsCalculator();
        boundsCalculator.GetBounds(model, inserts);
        Bounds3D bounds = boundsCalculator.Bounds;
        double scale = 1;
        Matrix4D to2DTransform = DxfUtil.GetScaleTransform(bounds.Min, bounds.Max, minToFitIn, maxToFitIn, out scale);

        foreach (var insert in inserts)
        {
          insert.ScaleFactor = new WW.Math.Vector3D(scale, scale, scale);
        }

        BoundsCalculator boundsCalculator1 = new BoundsCalculator();
        boundsCalculator1.GetBounds(model, inserts);
        Bounds3D boundsAfterScale = boundsCalculator1.Bounds;
        Bounds3D boundsToFitIn = new Bounds3D(minToFitIn, maxToFitIn);
        double x = boundsToFitIn.Corner1.X;
        double y = boundsToFitIn.Corner1.Y;

        if (boundsAfterScale.Center.X != boundsToFitIn.Center.X)
          x = boundsToFitIn.Center.X - boundsAfterScale.Center.X;

        if(boundsAfterScale.Center.Y != boundsToFitIn.Center.Y)
          y = -(boundsAfterScale.Center.Y - boundsToFitIn.Center.Y);


        foreach (var insert in inserts)
        {
          insert.InsertionPoint = new Point3D(x, y, 0);
        }
------------------------------------------------------------------------------------------------

This gives me my desired result but I am not sure if I should use insert.InsertionPoint in the way I am using?
Can someone please confirm if this is the right way and will not lead me into some unseen problems in the future?

rammi
6/4/2012 1:15 PM

I'm surprised that you are getting the correct results. The code will only work of all inserts use the same insertion point, because during the second loop all insertions points are set to the same value.
What you should have done is to calculate a dislocation vector and add this to the insertion point:

C# Code:
      insert.InsertionPoint += dislocation;

Although the influence of the scaling to the bounds is deterministic (which makes the dislocation above calculate as fit center minus scaling times bound's center), so there's no need to calculate the bounds a second time, and all can be done in one loop.

But if you are using a recent CadLib version things can be handled a lot easier: we are currently adding the possibility to transform entities, but do not advertise it due to the fact that this is a complex task which is different for each type of entity, and we are not yet finished. But lucky for you for DxfInsert the implementation is already done. So you can do the following:

C# Code:
      Point3D minToFitIn = new Point3D(30, 60, 0);
      Point3D maxToFitIn = new Point3D(558, 390, 0);
      BoundsCalculator boundsCalculator = new BoundsCalculator();
      boundsCalculator.GetBounds(model, inserts);
      Bounds3D bounds = boundsCalculator.Bounds;
      Matrix4D insertTransform = DxfUtil.GetScaleTransform(bounds.Min, bounds.Max, minToFitIn, maxToFitIn);

      // just run over all entities and apply the transformation
      GraphicsConfig cg = GraphicsConfig.BlackBackground; // used for TreatAttributesAsPartOfInsert (default: true)
      foreach (var insert in inserts) {
        insert.TransformMe(cg, insertTransform);
      }

(Small note: the usage of the GraphicsConfig parameter is currently under discussion, so there may be a small change necessary in the future if we decide to handle this differently)

aps_brar
6/5/2012 2:39 AM

To be honest I was surprised myself to see the desired result even after setting the same insertion point for all the inserts.

Rammi Thank you for your code snippet, it is a lot less code and works perfectly and even scales and moves the attributes in the right place (actually that was my unforeseen problem with the code that I had, I converted some text to attributes and attributes were not scaling and moving with the inserts)

We purchased a 3.5 license in 2010, how do I get a license for version 4.

Wout
6/6/2012 11:56 AM

Hi,

Send me an e-mail and I will give you more details about the renewal.

- Wout

1