Create Section View Parallel to Wall

Here is a nice case that just came up and helped me heal my latent view manipulation phobia.

Before getting to that, a short pointer to a non-API issue:
The Shanghai Tower is currently being built to become one of the tallest and greenest buildings in the world.
Take a look at

Shanghai Tower: The Role of BIM in Building the Spirit of the City
,
a six-minute video explaining the concept and the role of Autodesk BIM solutions in its design, construction, and operation.

Back to the view creation issue, the question is how to set up a section view that is parallel to a given wall.

The CreateViewSection SDK sample can be used as a basis for exploration, and the discussion on

section view creation
spells
it out a bit further still.
We also previously discussed some further aspects of

elevation and section views

and looked at setting up the view parameters to

crop a 3D view to a room
.

Obviously all previous explorations in the area of creating views make use of the obsolete view creation methods on the creation document class, which have now been replaced by static methods on the view classes themselves.

The only sample using the new methods was the recent one to create a

structural plan view
,
without any need to explore the required transformation, view direction, or crop box.

To alleviate that, I implemented a new sample external command named CreateWallSectionView which expects a single straight perpendicular wall to be pre-selected and creates a section view parallel to the wall with its crop box set up to display the wall in its entirety.

The code is extremely straight-forward and actually worked right out of the box without any further tweaking.

It uses the wall location line as the main source of geometrical input.
It also queries the wall bounding box to obtain its height, and uses the wall type Width property to determine the total wall
thickness, although the latter is not used anywhere.

From the location line, it determines the wall direction and length.
It sets up the bounding box min and max values from the length and height.

The transform is defined using the wall direction defining the right-left and the global world coordinate system Z vector defining the upward direction.

Simple and precise.

Here is the entire code achieving this:


[Transaction( TransactionMode.Manual )]
public class Command : IExternalCommand
{
  public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements )
  {
    UIApplication uiapp = commandData.Application;
    UIDocument uidoc = uiapp.ActiveUIDocument;
    Document doc = uidoc.Document;
 
    // Retrieve wall from selection set
 
    Selection sel = uidoc.Selection;
 
    SelElementSet set = sel.Elements;
 
    Wall wall = null;
 
    if( 1 == set.Size )
    {
      foreach( Element e in set )
      {
        wall = e as Wall;
      }
    }
 
    if( null == wall )
    {
      message = "Please select exactly one wall element.";
 
      return Result.Failed;
    }
 
    // Ensure wall is straight
 
    LocationCurve lc = wall.Location as LocationCurve;
 
    Line line = lc.Curve as Line;
 
    if( null == line )
    {
      message = "Unable to retrieve wall location line.";
 
      return Result.Failed;
    }
 
    // Determine view family type to use
 
    ViewFamilyType vft
      = new FilteredElementCollector( doc )
        .OfClass( typeof( ViewFamilyType ) )
        .Cast<ViewFamilyType>()
        .FirstOrDefault<ViewFamilyType>( x =>
          ViewFamily.Section == x.ViewFamily );
 
    // Determine section box
 
    XYZ p = line.get_EndPoint( 0 );
    XYZ q = line.get_EndPoint( 1 );
    XYZ v = q - p;
 
    BoundingBoxXYZ bb = wall.get_BoundingBox( null );
    double minZ = bb.Min.Z;
    double maxZ = bb.Max.Z;
 
    double w = v.GetLength();
    double h = maxZ - minZ;
    double d = wall.WallType.Width;
    double offset = 0.1 * w;
 
    XYZ min = new XYZ( -w, minZ - offset, -offset );
    XYZ max = new XYZ( w, maxZ + offset, 0 );
 
    XYZ midpoint = p + 0.5 * v;
    XYZ walldir = v.Normalize();
    XYZ up = XYZ.BasisZ;
    XYZ viewdir = walldir.CrossProduct( up );
 
    Transform t = Transform.Identity;
    t.Origin = midpoint;
    t.BasisX = walldir;
    t.BasisY = up;
    t.BasisZ = viewdir;
 
    BoundingBoxXYZ sectionBox = new BoundingBoxXYZ();
    sectionBox.Transform = t;
    sectionBox.Min = min;
    sectionBox.Max = max;
 
    // Create wall section view
 
    using( Transaction tx = new Transaction( doc ) )
    {
      tx.Start( "Create Wall Section View" );
 
      ViewSection.CreateSection( doc, vft.Id, sectionBox );
 
      tx.Commit();
    }
    return Result.Succeeded;
  }
}

I tested the command in this simple project with three walls:

Three walls

Here are the three section views created by running the command on all three walls:

Three wall sections

The resulting section views are quite reasonably positioned:

Wall section view

Sign on the Dotted Line, Please

Question: I need the section box to equally surround the wall on both sides.

The section box generated by the code above has its dotted line in the middle of the wall.

How can I move the section box dotted line so that it is offset out of the wall instead?

Answer: The Min and Max properties of the bounding box determine the crop region and far clip
distance.
In the code above, I defined


  XYZ min = new XYZ( -w, minZ - offset, -offset );
  XYZ max = new XYZ( w, maxZ + offset, 0 );

This produces the dotted line in the middle of the wall, like this:

Dotted line in wall center

If I change the Max property Z value from zero to +offset, the section view dotted line is
offset from the wall in the way you wish:


  XYZ min = new XYZ( -w, minZ - offset, -offset );
  XYZ max = new XYZ( w, maxZ + offset, offset );

This produces the dotted line offset to the other side of the wall:

Dotted line offset from wall center

Perpendicular, not Parallel

Question: How can I set up the section view to be perpendicular to the wall and located at the wall centre point?

Answer: Well, obviously the same parameters as above apply.

Here is one little additional nice twist, though: instead of calculating the required transformation vectors based on the vector from the wall start point to its end point, we can obtain the wall location line curve tangent at its midpoint using the ComputeDerivatives method.
The advantage of this is that it will work for a curved wall as well.

Here as the method GetSectionViewPerpendiculatToWall taking a wall input argument.
It sets up and returns a section box for the section view creation at the wall midpoint and perpendicular to its location line.
It takes the wall thickness and height into account to set up a crop box showing just the wall with one foot of space around it:


/// <summary>
/// Return a section box for a view perpendicular 
/// to the given wall location line.
/// </summary>
BoundingBoxXYZ GetSectionViewPerpendiculatToWall(
  Wall wall )
{
  LocationCurve lc = wall.Location
    as LocationCurve;
 
  // Using 0.5 and "true" to specify that the 
  // parameter is normalized places the transform
  // origin at the center of the location curve
 
  Transform curveTransform = lc.Curve
    .ComputeDerivatives( 0.5, true );
 
  // The transform contains the location curve
  // mid-point and tangent, and we can obtain
  // its normal in the XY plane:
 
  XYZ origin = curveTransform.Origin;
  XYZ viewdir = curveTransform.BasisX.Normalize();
  XYZ up = XYZ.BasisZ;
  XYZ right = up.CrossProduct( viewdir );
 
  // Set up view transform, assuming wall's "up" 
  // is vertical. For a non-vertical situation 
  // such as section through a sloped floor, the 
  // surface normal would be needed
 
  Transform transform = Transform.Identity;
  transform.Origin = origin;
  transform.BasisX = right;
  transform.BasisY = up;
  transform.BasisZ = viewdir;
 
  BoundingBoxXYZ sectionBox = new BoundingBoxXYZ();
  sectionBox.Transform = transform;
 
  // Min & Max X values define the section
  // line length on each side of the wall.
  // Max Y is the height of the section box.
  // Max Z (5) is the far clip offset.
 
  double d = wall.WallType.Width;
  BoundingBoxXYZ bb = wall.get_BoundingBox( null );
  double minZ = bb.Min.Z;
  double maxZ = bb.Max.Z;
  double h = maxZ - minZ;
 
  sectionBox.Min = new XYZ( -2 * d, -1, 0 );
  sectionBox.Max = new XYZ( 2 * d, h + 1, 5 );
 
  return sectionBox;
}

This produces the following section view through of a wall with a window in its midpoint:

Section view perpendicular to wall

Here is
CreateWallSectionView.zip containing
the entire source code, Visual Studio solution and add-in manifest for this command.


Comments

13 responses to “Create Section View Parallel to Wall”

  1. Dear Jeremy,
    Help me at Wrapping of Wall layer finishing in view
    http://thebuildingcoder.typepad.com/.a/6a00e553e1689788330176157ad409970c-800wi
    Thanks

  2. Dear Do Tuan Hanh,
    ?
    Cheers, Jeremy.

  3. Hi Jeremy,
    How do I do this (Create Section View Parallel to Wall)without creating new section views, ie by changing only the crop box of an exisitng view.
    Regards,
    Hep

  4. Dear Hep,
    In the code above, I create a bounding box and pass it into the view creator method CreateSection.
    To modify an existing view, simply set up the same bounding box and assign it to the view SectionBox property instead.
    Cheers, Jeremy.

  5. Hi Jeremy,
    Have you been outdoor adventuring much lately?
    Here is a question I have been googling and had no success on so far.
    Do you know of a better method or a way to encourage the marker.CreateElevation() method to not get confused when it sees a second floor and create a view with a height close to the top of the floor rather than the ceiling?

    heres an example of my code:

    ElevationMarker marker = ElevationMarker.CreateElevationMarker(doc, viewFamilyTypes.First().Id, xyz, elevationScale);
    //create 4 internal elevations for on each marker index
    for (int i = 0; i < 4; i++)
    {
    ViewSection elevationView =
    marker.CreateElevation(doc, floorView.Id, i);
    cheers,
    Nik

  6. Dear Nik,
    Thanks for asking. No, not as much as I would like and need, I’m afraid. Too many comments on the blog, and other queries :-)
    No, I have never heard of such an issue before. How strange.
    It also seems a bit strange to me to create the marker first, and then use that to drive the elevation. Sounds like a very user interface oriented sort of approach.
    Have you tried to create the elevation all on its own? And add a marker afterwards?
    Alternatively, you should actually be able to create the new elevation anywhere you want and then modify its Z coordinate later to anything you like.
    I hope this helps.
    Cheers, Jeremy.

  7. nik mulconray Avatar
    nik mulconray

    Hi Jeremy,
    I was in a Mountaineering club in Adelaide, however I have been kept busy by my firm and as such have done one rail trail since moving to Brisbane.
    I will give your approaches a go and will let you know what works.
    Thanx again,
    Nik

  8. Dear Nik,
    Best of luck to you with all your approaches, both in programming, business and mountains!
    Cheers, Jeremy.

  9. Hi Jeremy, i am a newbie in programming and, for me, is has been a victory to make this little app run.
    The problem is when the wall is not located in a 0 elevation level, in this case, the new section view appears some distance up respect the wall (the Y coordinate appears to be wrong, X and Z are correct). I have tried to understand all the steps you made, but i miss myself in the transformation of the coordinates from the wall’s bounding box to the models coordinates, and i am afraid that there is the problem but dont know hot to solve.
    The next step for me is to isolate the wall in the section view and apply a view template to this view. (some suggestions will be apreciated )
    Cheers from Spain
    Luis

  10. Well, i have found a way to avoid my problem.
    In the part where you create the new sectionbox, if you add the minZ and the maxZ to the new min and max points, you are adding a full level height more. I noticed thath if my wall level is 10 meters, the new view appears 10 meters upper of where it has to appear…
    This are my “new” min and max, and they work.
    I also changed the lenght of the view to adjust to my wall.
    XYZ min = new XYZ( -w / 2, – offset, -offset );
    XYZ max = new XYZ( w / 2 , h + offset, offset );
    Now, i am trying to select the new sectionview, apply a view template and isolate the wall… and have no idea of how to do it hehe

  11. Dear Luis,
    Congratulations on your good progress.
    You will crack this :-)
    Cheers, Jeremy.

  12. Dear Jeremy,
    how to get the solid of a column
    thanks

  13. Dear Modar,
    There are about a hundred answers to that question right here on The Building Coder.
    Hint: search for get_Geometry.
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading