Align views on sheet

Align views on sheet

michael
Participant Participant
3,315 Views
5 Replies
Message 1 of 6

Align views on sheet

michael
Participant
Participant

Hello,

 

I’m trying to align some views on a sheet such that elements on the views are aligned. I have an element (e.g. a wall, column, …) for whom I created an assembly and several views (“front”, “right” and “left”). On each view I placed some dimensions.

I want to place these views on a sheet such that the element is aligned on the sheet (such that the lower edge of the element is aligned). I know that I can place views using the Viewport.Create command on the sheet. I can then get the position of the viewport using the GetBoxOutline().MinimumPoint and MaximumPoint. I also know that I can move them using ElementTransformUtils.MoveElement.

My problem is that I don’t know how to determine the translation for each view to align my element. I think that I need to get the position of the lower edge with respect to the Viewport position for each view. Once I have these positions I can calculate the viewport position to ensure that the element is aligned. (Note that the distance between the lower edge of the element and the viewport’s lower edge is not the same for the 3 views).  I have the same problem with non-assembly views.

 

Any help would be appreciated!

0 Likes
Accepted solutions (2)
3,316 Views
5 Replies
Replies (5)
Message 2 of 6

jeremytammik
Autodesk
Autodesk
Accepted solution
0 Likes
Message 3 of 6

michael
Participant
Participant

Hi Jeremy,

 

Yes it works, I had to fiddle a bit with some transformations but it works. Thanks a lot.

 

Btw your blog is great, it healped me out several times 🙂

 

Best regards,

 

Michael

0 Likes
Message 4 of 6

jeremytammik
Autodesk
Autodesk

Dear Michael,

 

I am very glad it works and that the blog is helpful. Thank you for your appreciation. Is your solution generic enough to be worthwhile sharing? Thank you!

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 5 of 6

michael
Participant
Participant

Here's my mehtod. I don't know if it is the best,fastest or efficienst way. If you have any suggestion to improve my code, I am looking forward to heear from you.

public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            Document doc;
            UIApplication app;
            app = commandData.Application;
            doc = commandData.Application.ActiveUIDocument.Document;

            using (Transaction trans = new Transaction(doc, "Place views"))
            {
                trans.Start();
                View frontView = doc.GetElement(new ElementId(180041)) as View;
                View leftView = doc.GetElement(new ElementId(180032)) as View;

                AssemblyInstance assemblyInst = doc.GetElement(new ElementId(179915)) as AssemblyInstance;

                ViewSheet vSheet = doc.GetElement(new ElementId(180049)) as ViewSheet;

                // I assume that the scale is the same for both views
                int scale = frontView.Scale;
                leftView.Scale = scale;

                // Save current crop box values
                BoundingBoxXYZ savedBoxFront = null, savedBoxLeft = null;
                bool frontCropActive, frontCropVisible, leftCropActive, leftCropVisible;
                double farClipFront = 0, farClipLeft = 0;
                Parameter param;
                Transform transfromFront, transfromLeft;
                transfromFront = frontView.CropBox.Transform;
                transfromLeft = leftView.CropBox.Transform;

                // save old values. I have to store the farclip and reset it later
                savedBoxFront = frontView.CropBox;
                frontCropActive = frontView.CropBoxActive;
                frontCropVisible = frontView.CropBoxVisible;
                param = frontView.get_Parameter(BuiltInParameter.VIEWER_BOUND_OFFSET_FAR);
                if (param != null)
                {
                    farClipFront = param.AsDouble();
                }
                savedBoxLeft = leftView.CropBox;
                leftCropActive = leftView.CropBoxActive;
                leftCropVisible = leftView.CropBoxVisible;
                param = leftView.get_Parameter(BuiltInParameter.VIEWER_BOUND_OFFSET_FAR);
                if (param != null)
                {
                    farClipLeft = param.AsDouble();
                }

                // Here my approachs differs from yours. I'm starting form the old bounding box to ensure that I got the correct transformation.
                // I tried to create a new Transformation but this didn't worked.
                BoundingBoxXYZ newBoxFront = frontView.CropBox;
                newBoxFront.set_MinEnabled(0, true);
                newBoxFront.set_MinEnabled(1, true);
                newBoxFront.set_MinEnabled(2, true);
                newBoxFront.Min = new XYZ(-2000, -2000, 0);
                newBoxFront.set_MaxEnabled(0, true);
                newBoxFront.set_MaxEnabled(1, true);
                newBoxFront.set_MaxEnabled(2, true);
                newBoxFront.Max = new XYZ(2000, 2000, 0);

                BoundingBoxXYZ newBoxLeft = leftView.CropBox;
                newBoxLeft.set_MinEnabled(0, true);
                newBoxLeft.set_MinEnabled(1, true);
                newBoxLeft.set_MinEnabled(2, true);
                newBoxLeft.Min = new XYZ(-2000, -2000, 0);
                newBoxLeft.set_MaxEnabled(0, true);
                newBoxLeft.set_MaxEnabled(1, true);
                newBoxLeft.set_MaxEnabled(2, true);
                newBoxLeft.Max = new XYZ(2000, 2000, 0);

                frontView.CropBox = newBoxFront;
                leftView.CropBox = newBoxLeft;
                doc.Regenerate();
                frontView.CropBoxActive = true;
                leftView.CropBoxActive = true;


                doc.Regenerate();

                ElementId vid = vSheet.Id;
                var p = XYZ.Zero;

                var vpFront = Viewport.Create(doc, vid, frontView.Id, p);
                var vpLeft = Viewport.Create(doc, vid, leftView.Id, p);

                doc.Regenerate();

                // Align lower left - works 
                // because crop boxes are same
                Outline outline1 = vpFront.GetBoxOutline();
                Outline outline2 = vpLeft.GetBoxOutline();
                XYZ min1 = outline1.MinimumPoint;
                XYZ min2 = outline2.MinimumPoint;
                XYZ diffToMove = min1 - min2;
                ElementTransformUtils.MoveElement(doc, vpLeft.Id, diffToMove);
                // Tranform the view such that the origin of the assemblyInstance for each view is on the middle of the sheet
                // 1) Move the views such that the assembly Origin lies on the same on the origin of sheet
                XYZ translation = new XYZ((transfromFront.Origin - assemblyInst.GetTransform().Origin).DotProduct(transfromFront.BasisX), (transfromFront.Origin - assemblyInst.GetTransform().Origin).DotProduct(transfromFront.BasisY), 0) / scale;
                ElementTransformUtils.MoveElement(doc, vpFront.Id, translation);
                translation = new XYZ((transfromLeft.Origin - assemblyInst.GetTransform().Origin).DotProduct(transfromLeft.BasisX), (transfromLeft.Origin - assemblyInst.GetTransform().Origin).DotProduct(transfromLeft.BasisY), 0) / scale;
                ElementTransformUtils.MoveElement(doc, vpLeft.Id, translation);

                // 2) Move the views such that the assembly origin lies on the centerto the center of the sheet
                double width = 840 * 0.0032808399;
                double height = 594 * 0.0032808399;

                XYZ sheetMidpoint = (vSheet.Origin + XYZ.BasisX * width + XYZ.BasisY * height) / 2.0;
                ElementTransformUtils.MoveElement(doc, vpFront.Id, sheetMidpoint);
                ElementTransformUtils.MoveElement(doc, vpLeft.Id, sheetMidpoint);

                // Once the views are on the middle move the left view to the left of the front view:
                // Do the correct translations to suit the defined layout
                translation = XYZ.BasisX * (- ((outline1.MinimumPoint.X - outline1.MinimumPoint.X)/2 + (outline2.MinimumPoint.X - outline2.MinimumPoint.X) + 1));
                ElementTransformUtils.MoveElement(doc, vpLeft.Id, translation);
                doc.Regenerate();

                // Restore view crop boxes
                frontView.CropBox = savedBoxFront;
                frontView.CropBoxActive = frontCropActive;
                frontView.CropBoxVisible = frontCropVisible;
                param = frontView.get_Parameter(BuiltInParameter.VIEWER_BOUND_OFFSET_FAR);
                if (param != null)
                {
                    param.Set(farClipFront);
                }
                leftView.CropBox = savedBoxLeft;
                leftView.CropBoxActive = leftCropActive;
                leftView.CropBoxVisible = leftCropVisible;
                param = leftView.get_Parameter(BuiltInParameter.VIEWER_BOUND_OFFSET_FAR);
                if (param != null)
                {
                    param.Set(farClipLeft);
                }

                trans.Commit();
            }
            return Result.Succeeded;
        }

 

 

Michael

0 Likes
Message 6 of 6

jeremytammik
Autodesk
Autodesk
Accepted solution

Hi Michael,

 

Thank you very much for sharing that!

 

Looks impressive.

 

I do not see much to improve.

 

I would suggest just a few intermediate variables to make it more readable, e.g. like this:

 

  const BuiltInParameter _bipFarOffset
    = BuiltInParameter.VIEWER_BOUND_OFFSET_FAR;

  public Result Execute( 
    ExternalCommandData commandData, 
    ref string message, 
    ElementSet elements )
  {
    UIApplication app = commandData.Application;
    Document doc = app.ActiveUIDocument.Document;

    using( Transaction trans = new Transaction( doc ) )
    {
      trans.Start( "Place views" );

      View frontView = doc.GetElement( new ElementId( 180041 ) ) as View;
      View leftView = doc.GetElement( new ElementId( 180032 ) ) as View;

      AssemblyInstance assemblyInst = doc.GetElement( new ElementId( 179915 ) ) as AssemblyInstance;

      ViewSheet vSheet = doc.GetElement( new ElementId( 180049 ) ) as ViewSheet;

      // Assume that the scale is the same for both views

      int scale = frontView.Scale;
      leftView.Scale = scale;

      // Save current crop box values

      BoundingBoxXYZ savedBoxFront = null, savedBoxLeft = null;
      bool frontCropActive, frontCropVisible, leftCropActive, leftCropVisible;
      double farClipFront = 0, farClipLeft = 0;
      Parameter param;
      Transform transformFront = frontView.CropBox.Transform;
      Transform transformLeft = leftView.CropBox.Transform;

      // Save old values. I have to store the farclip and reset it later

      savedBoxFront = frontView.CropBox;
      frontCropActive = frontView.CropBoxActive;
      frontCropVisible = frontView.CropBoxVisible;
      param = frontView.get_Parameter( _bipFarOffset );
      if( param != null )
      {
        farClipFront = param.AsDouble();
      }
      savedBoxLeft = leftView.CropBox;
      leftCropActive = leftView.CropBoxActive;
      leftCropVisible = leftView.CropBoxVisible;
      param = leftView.get_Parameter( _bipFarOffset );
      if( param != null )
      {
        farClipLeft = param.AsDouble();
      }

      // Here my approach differs from yours. 
      // I'm starting from the old bounding box to 
      // ensure that I get the correct transformation.
      // I tried to create a new Transformation but 
      // this didn't work.

      BoundingBoxXYZ newBoxFront = frontView.CropBox;
      newBoxFront.set_MinEnabled( 0, true );
      newBoxFront.set_MinEnabled( 1, true );
      newBoxFront.set_MinEnabled( 2, true );
      newBoxFront.Min = new XYZ( -2000, -2000, 0 );
      newBoxFront.set_MaxEnabled( 0, true );
      newBoxFront.set_MaxEnabled( 1, true );
      newBoxFront.set_MaxEnabled( 2, true );
      newBoxFront.Max = new XYZ( 2000, 2000, 0 );

      BoundingBoxXYZ newBoxLeft = leftView.CropBox;
      newBoxLeft.set_MinEnabled( 0, true );
      newBoxLeft.set_MinEnabled( 1, true );
      newBoxLeft.set_MinEnabled( 2, true );
      newBoxLeft.Min = new XYZ( -2000, -2000, 0 );
      newBoxLeft.set_MaxEnabled( 0, true );
      newBoxLeft.set_MaxEnabled( 1, true );
      newBoxLeft.set_MaxEnabled( 2, true );
      newBoxLeft.Max = new XYZ( 2000, 2000, 0 );

      frontView.CropBox = newBoxFront;
      leftView.CropBox = newBoxLeft;
      doc.Regenerate();
      frontView.CropBoxActive = true;
      leftView.CropBoxActive = true;

      doc.Regenerate();

      ElementId vid = vSheet.Id;
      XYZ p = XYZ.Zero;

      var vpFront = Viewport.Create( doc, vid, frontView.Id, p );
      var vpLeft = Viewport.Create( doc, vid, leftView.Id, p );

      doc.Regenerate();

      // Align lower left - works 
      // because crop boxes are same

      Outline outline1 = vpFront.GetBoxOutline();
      Outline outline2 = vpLeft.GetBoxOutline();
      XYZ min1 = outline1.MinimumPoint;
      XYZ min2 = outline2.MinimumPoint;
      XYZ diffToMove = min1 - min2;
      ElementTransformUtils.MoveElement( doc, vpLeft.Id, diffToMove );

      // Tranform the view such that the origin 
      // of the assemblyInstance for each view is 
      // on the middle of the sheet
      // 1) Move the views such that the assembly
      // Origin lies on the same on the origin of sheet

      p = assemblyInst.GetTransform().Origin;

      XYZ v = transformFront.Origin - p;

      XYZ translation = new XYZ( 
        v.DotProduct( transformFront.BasisX ), 
        v.DotProduct( transformFront.BasisY ), 0 ) 
          / scale;

      ElementTransformUtils.MoveElement( doc, vpFront.Id, translation );

      v = transformLeft.Origin - p;

      translation = new XYZ( 
        v.DotProduct( transformLeft.BasisX ), 
        v.DotProduct( transformLeft.BasisY ), 0 ) 
          / scale;

      ElementTransformUtils.MoveElement( doc, vpLeft.Id, translation );

      // 2) Move the views such that the assembly 
      // origin lies on the center of the sheet

      double width = 840 * 0.0032808399;
      double height = 594 * 0.0032808399;

      XYZ sheetMidpoint = ( vSheet.Origin + XYZ.BasisX * width + XYZ.BasisY * height ) / 2.0;
      ElementTransformUtils.MoveElement( doc, vpFront.Id, sheetMidpoint );
      ElementTransformUtils.MoveElement( doc, vpLeft.Id, sheetMidpoint );

      // Once the views are on the middle, move the 
      // left view to the left of the front view:
      // Do the correct translations to suit the 
      // defined layout

      translation = XYZ.BasisX * ( 
        -( ( outline1.MinimumPoint.X - outline1.MinimumPoint.X ) 
        / 2 + ( outline2.MinimumPoint.X - outline2.MinimumPoint.X ) + 1 ) );

      ElementTransformUtils.MoveElement( doc, vpLeft.Id, translation );

      doc.Regenerate();

      // Restore view crop boxes

      frontView.CropBox = savedBoxFront;
      frontView.CropBoxActive = frontCropActive;
      frontView.CropBoxVisible = frontCropVisible;

      param = frontView.get_Parameter( _bipFarOffset );

      if( param != null )
      {
        param.Set( farClipFront );
      }

      leftView.CropBox = savedBoxLeft;
      leftView.CropBoxActive = leftCropActive;
      leftView.CropBoxVisible = leftCropVisible;
        
      param = leftView.get_Parameter( _bipFarOffset );

      if( param != null )
      {
        param.Set( farClipLeft );
      }

      trans.Commit();
    }
    return Result.Succeeded;
  }

 

Thank you!

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes