How can I get the coordinates of the endpoints for a section marker line segment

How can I get the coordinates of the endpoints for a section marker line segment

Anonymous
Not applicable
3,357 Views
14 Replies
Message 1 of 15

How can I get the coordinates of the endpoints for a section marker line segment

Anonymous
Not applicable

I have a section marker for which I would like to do a rotation around one of the endpoints of the line segment leader but I haven't been able to figure out how to get the coordinates of the endpoint.  I'm able to get the bounding box of the overall section marker but not these specific coordinates.  How can I do this?

 

Section Marker Coordinates.png

Accepted solutions (1)
3,358 Views
14 Replies
Replies (14)
Message 2 of 15

jeremytammik
Autodesk
Autodesk

Dear Skeletank,

 

I am checking with the development team for you... hang on...

 

Cheers,

 

Jeremy



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

0 Likes
Message 3 of 15

Anonymous
Not applicable

Hi Jeremy,

 

Have you heard anything back from the development team?  My bigger problem involves reversing the effects of the built-in "Mirror Project" tool and part of that includes reference section markers inside of another section that has been flipped.  I would like to fix their orientation by rotating 180 degrees around the endpoint.

 

Thanks

Message 4 of 15

jeremytammik
Autodesk
Autodesk
Accepted solution

Yes.

 

They say:

 

1. The section marker element is not exposed as a specific element type so I don’t think this position can be read at this time. 

 

2. Regarding “Mirror Project”:  I don’t have good ideas to add.

 

Sorry for not being of more help!

 

Cheers,

 

Jeremy



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

Message 5 of 15

Anonymous
Not applicable

I was assuming that would be the response but thank you very much Jeremy for checking with the development team for me.

0 Likes
Message 6 of 15

FAIR59
Advisor
Advisor

I've found a workaround for your question

 

A transaction needs to be active when you call the method, as the method hides the section tag and viewer_reference_label_text temporarily.

 

        private Line GetSectionLine(Element _section, Autodesk.Revit.DB.View _view)
        {
            const double _correction = 21.130014403 / 304.8;
            if (_section.Category == null) return null;
            if ((BuiltInCategory)_section.Category.Id.IntegerValue != BuiltInCategory.OST_Viewers) return null;

            List<Autodesk.Revit.DB.View> _views = new FilteredElementCollector(_section.Document)
                .OfClass(typeof(Autodesk.Revit.DB.View))
                .Cast<Autodesk.Revit.DB.View>()
                .ToList();
            Autodesk.Revit.DB.View _viewFromSection = null;
            foreach (var v in _views)
            {
                if (_section.Name == v.Name && _section.GetTypeId() == v.GetTypeId()) _viewFromSection = v;
            }
            if (_viewFromSection == null) return null;
            ViewFamilyType _vType = _section.Document.GetElement(_section.GetTypeId()) as ViewFamilyType;
            BoundingBoxXYZ _bb1 = null;
            using (SubTransaction st1 = new SubTransaction(_section.Document))
            {
                st1.Start();
                Parameter par = _vType.get_Parameter(BuiltInParameter.SECTION_TAG);
                par.Set(ElementId.InvalidElementId);
                par = _vType.get_Parameter(BuiltInParameter.VIEWER_REFERENCE_LABEL_TEXT);
                par.Set(string.Empty);
                _view.Scale = 1;
                _section.Document.Regenerate();
                _bb1 = _section.get_BoundingBox(_view);
                st1.RollBack();
            }
            BoundingBoxXYZ _ViewBB = _viewFromSection.get_BoundingBox(_viewFromSection);
            BoundingBoxXYZ _bb = _section.get_BoundingBox(_view);
            XYZ pt1 = _bb.Min;
            XYZ pt2 = _bb.Max;
            if (_bb1 != null)
            {
                pt1 = _bb1.Min;
                pt2 = _bb1.Max;
            }
            XYZ Origin = _viewFromSection.Origin;
            XYZ ViewBasisX = _viewFromSection.RightDirection;
            XYZ ViewBasisY = _viewFromSection.ViewDirection;
            if (ViewBasisX.X < 0 ^ ViewBasisX.Y < 0)
            {
                double _d = pt1.Y;
                pt1 = new XYZ(pt1.X, pt2.Y, pt1.Z);
                pt2 = new XYZ(pt2.X, _d, pt2.Z);
            }
            XYZ ToPlane1 = pt1.Add(ViewBasisY.Multiply(ViewBasisY.DotProduct(Origin.Subtract(pt1))));
            XYZ ToPlane2 = pt2.Subtract(ViewBasisY.Multiply(ViewBasisY.DotProduct(pt2.Subtract(Origin))));
            XYZ _correctionVector = ToPlane2.Subtract(ToPlane1).Normalize().Multiply(_correction);
            XYZ endPoint0 = ToPlane1.Add(_correctionVector);
            XYZ endPoint1 = ToPlane2.Subtract(_correctionVector);

            return Line.CreateBound(endPoint0, endPoint1);
        }
Message 7 of 15

jeremytammik
Autodesk
Autodesk

Beautiful sample!

 

Especially after the development team said 'no hope'  🙂

 

Thank you, and congratulations!

 

Definitive blog post material, if I may...

 

Cheers,

 

Jeremy



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

Message 8 of 15

Anonymous
Not applicable

FAIR59,

 

Thanks for the response.  I have a few questions:

 

  1. Where did you come up with the "const double _correction = 21.130014403 / 304.8;" value?
  2. How do you distinguish between section vs. callout markers since they are both of category OST_VIEWERS?
  3. Would this work for section markers that are only references (such as ones that reference drafting views)?
  4. How do you know which endpoint is associated with the tail and which one is associated with the head?
0 Likes
Message 9 of 15

FAIR59
Advisor
Advisor

@jeremytammik : feel free to use my contributions for your blog

 

@Anonymous:

 

answer 1.

the boundingbox of a sectionline is the result of a number of elements

  1. the line
  2. the section head
  3. the reference label text
  4. the cycle symbol 

BoundingBox.PNG

 

in the method I "hide" 2 and 3. You can't hide the cycle symbol, so the result is to large. I simply added the resulting line without the correction to the project  and measured the surplus length. After checking that it is always the same, I implemented the constant  _correction = 21.130014403 / 304.8

 

answer 2.

I didn't distinguish between section vs. callout markers, I merely presumed you had a section marker. There are 2 ways to test

  1. if (_vType.FamilyName == "Section")

  2. if (_viewFromSection.GetType()== typeof(ViewSection))

callouts are PlanViews or Elevations, as far as I know.

 

answer 3.

I don't know

 

answer 4.

i'm afraid that is truly hidden. The Section Head and Tail stay in the same position when flipping the section, but the viewDirection and RightDirection changes.

The most you can get is a line in the View.RightDirection

 

            XYZ _direction = ToPlane2.Subtract(ToPlane1).Normalize();
            return _direction.IsAlmostEqualTo(ViewBasisX) ? Line.CreateBound(endPoint0, endPoint1) : Line.CreateBound(endPoint1, endPoint0);

 

  

 

 

Message 10 of 15

jeremytammik
Autodesk
Autodesk

Cool solution, cool answers!

 

Preserved by The Building Coder for posterity here:

 

http://thebuildingcoder.typepad.com/blog/2017/03/ttt-to-obtain-section-marker-endpoint.html

 

Thank you!

 

 Cheers,

 

Jeremy



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

0 Likes
Message 11 of 15

Dale.Bartlett
Collaborator
Collaborator

Amazing work. I would have just used Section.Line.StartPoint.X. Please, it's a joke...

The question: Where did you come up with the "const double _correction = 21.130014403 / 304.8;" value?

Am I understanding correctly that this value (21.1300 etc.) will be dependant on the size and scale of the section marker circle? If so, a custom one would be a different value, correct? Thanks for posting this very helpful code. Regards, Dale




______________
Yes, I'm Satoshi.
0 Likes
Message 12 of 15

DanielKP2Z9V
Advocate
Advocate

Has there been any development in accessing and modifying section markers from revit api? They are incredibly slow to edit by hand - programmatic access would be tremendously helpful. Length, start point and end point would help a lot.

0 Likes
Message 13 of 15

jeremy_tammik
Alumni
Alumni

Dear Daniel, 

  

I asked the Gemini LLM for you, as described in my blog post, using the following prompt:

  

  • You are a seasoned Revit add-in programmer and .NET expert with deep expertise in BIM principles and the Revit API. Your task is to address complex, technical questions raised by experienced Revit add-in developers in the Revit API forum. Leverage insights from The Building Coder blog, respected Revit API resources, and community feedback to provide innovative and practical solutions. Include clear explanations, advanced code examples, actionable snippets, and practical demonstrations to ensure effectiveness and clarity: it is tricky to access and modify the coordinates of the end point of a section view marker; The Building Coder published a tricky solution using the temporary transaction trick in 2017; is there any easier and more direct way to achieve that today?

  

It spouts a confident and sensible-sounding answer, but I have no idea whether it is hallucinating or based on true facts. 

  

I'll share it with you in case it contains any new hints or ideas that we were not aware of in the discussion above; you will be more capable than I at pointing out its faults, in case not:

  

GeminiYou're right, manipulating section view marker endpoints has historically been tricky. The "temporary transaction trick" described by The Building Coder in 2017 (and likely referencing Jeremy Tammik's work) was a clever workaround for limitations in the Revit API. While still functional, it's not the most elegant or performant approach. Thankfully, recent Revit API improvements offer a more direct and cleaner solution.

Let's break down the problem and the modern solution:

The Challenge:

Section view markers are represented by ViewSection elements. Their geometry, specifically the endpoint location, is tied to the view's crop region and internal Revit workings. Directly setting the endpoint coordinates can lead to unexpected behavior or exceptions because Revit manages the relationship between the section line and the generated section view.

The Modern Solution: CropBox Manipulation

The key is to understand that the section line's endpoint is directly related to the section view's CropBox. By modifying the CropBox, we indirectly control the section line's endpoint. This avoids the transactional complexities of the older approach.

Here's a breakdown of the process and a C# code example:

  1. Get the ViewSection: Obtain the ViewSection element representing the section view marker you want to modify. You can do this by selecting it, iterating through views, or other methods depending on your add-in's context.

  2. Access the CropBox: The ViewSection has a CropBox property. This is the crucial element we need to manipulate.

  3. Modify the CropBox's Max or Min Point: The CropBox is defined by a BoundingBoxXYZ. The section line's endpoint corresponds to one of the corner points of this bounding box. You'll typically adjust the Max point in the direction of the section line.

  4. Update the ViewSection: After modifying the CropBox, the ViewSection will automatically update, reflecting the changed endpoint. No explicit transaction is required for this specific operation.

C#
 
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;

namespace RevitAddin
{
    [Transaction(TransactionMode.Manual)] // Or Automatic if appropriate for your context
    public class ModifySectionEndpoint : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Document doc = uidoc.Document;

            // 1. Get the ViewSection (assuming you have it selected)
            ViewSection viewSection = null;
            Selection selection = uidoc.Selection;
            if (selection.GetElementIds().Count > 0)
            {
                Element element = doc.GetElement(selection.GetElementIds().First());
                viewSection = element as ViewSection;
            }

            if (viewSection == null)
            {
                TaskDialog.TaskDialog.Show("Error", "Please select a section view.");
                return Result.Failed;
            }


            // 2. Access the CropBox
            CropBox cropBox = viewSection.CropBox;

            // 3. Modify the Max point (adjust as needed for your section direction)
            XYZ currentMax = cropBox.Max;
            XYZ offset = new XYZ(1, 0, 0); // Example offset - adjust as needed
            XYZ newMax = currentMax + offset;

            cropBox.Max = newMax;

            // 4. Update is automatic - no transaction needed for CropBox modification in this context.

            uidoc.RefreshActiveView(); // Important: Refresh the view to see the change

            return Result.Succeeded;
        }
    }
}

Key Improvements over the "Temporary Transaction Trick":

  • Simplicity: Direct CropBox manipulation is much more straightforward than managing temporary transactions.
  • Performance: Avoids the overhead of creating and committing transactions, resulting in better performance, especially when modifying multiple section endpoints.
  • Clarity: The code is more readable and easier to understand, making maintenance and debugging simpler.

Important Considerations:

  • Section Direction: Ensure you modify the correct CropBox point (Max or Min) and the appropriate coordinates (X, Y, or Z) based on the section view's direction.
  • Units: Work with Revit's internal units (feet). Convert to/from your desired units as needed.
  • Error Handling: Include robust error handling to handle cases where the selected element isn't a ViewSection or if other unexpected issues occur.
  • View Refresh: The uidoc.RefreshActiveView() is often crucial to immediately visualize the change in the Revit UI.

By using this CropBox approach, you can efficiently and reliably manipulate section view marker endpoints in your Revit add-ins, leveraging the power of the modern Revit API. This method is significantly more efficient and easier to maintain than the older transactional workarounds.

   

What say you? True, false, ridiculous, helpful? Exploring the new technology and its limits... Thank you for checking and letting us know. 

   

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 14 of 15

DanielKP2Z9V
Advocate
Advocate

thanks Jeremy, I haven't tried asking this question to Gemini, but I tried all the other big 3 LLMs and none of them knew the answer. I don't think Gemini got it quite right neither sadly, because it assumes that you want section marker to be exactly where section's crop region is, which isn't always the case - sometimes you want to offset section markers slightly to avoid it clashing with other elements in a view.

 

So I think we need to nag autodesk to expose this functionality. I know it's an uphill battle, but this time, this time I believe it will work 🙂

0 Likes
Message 15 of 15

EIVOE
Explorer
Explorer

Only thing missing from this thread was a Revit idea link to Autodesk forums.

Here is some nagging:
Increased API Functionality for Sections - Autodesk Community

0 Likes