For the sake of my own comfort, your convenience and the completeness of the answer, I asked Gemini to answer this, as described in my recent blog post. Here is its reply:
Let's dive into this internal origin issue and how to reliably retrieve curve Z-coordinates relative to the project base point, regardless of the internal origin's position. You're right to suspect the internal origin, but the solution isn't about moving it (generally not recommended). Instead, we'll work with coordinate systems.
Understanding the Challenge
Revit uses different coordinate systems:
- Project Coordinate System: This is the coordinate system you typically work in, and its origin is the Project Base Point (PBP). This is what you care about for your Z-coordinate.
- Internal Coordinate System: This is Revit's internal coordinate system. Its origin is the internal origin. This is what's causing your confusion.
The issue arises because the Curve.GetEndPoint(0).Z
(or similar) returns coordinates in the Internal Coordinate System. We need to transform these coordinates to the Project Coordinate System.
The Solution: Coordinate Transformation
Here's the breakdown of the solution using the Revit API and C#:
Explanation and Key Improvements:
-
ProjectLocation
and GetTotalTransform()
: This is the crucial part. We get the ProjectLocation
and use GetTotalTransform()
to obtain the transformation that maps points from the Project Base Point (PBP) to the Internal Origin. This transform encapsulates the relationship between the two coordinate systems.
-
Inverse
Transform: We use pbpToInternalTransform.Inverse
because we want to go from Internal coordinates back to Project coordinates.
-
OfPoint()
: The Transform.OfPoint()
method applies the transformation to the point.
-
Helper Function: The GetYourCurve()
function is a placeholder. Replace it with your actual code to retrieve the curve you're working with (e.g., using FilteredElementCollector
, picking a curve, etc.).
-
Error Handling: In a production add-in, you would add error handling (e.g., checking if curve
is null, handling exceptions).
Practical Demonstration and Further Tips:
-
Debugging: Use the Revit API Debugger to inspect the pbpToInternalTransform
and the resulting points to understand the transformation.
-
Units: Be mindful of units. The Z-coordinate will be in the project's internal units (typically feet). You might need to convert to other units using UnitUtils.ConvertFromInternalUnits()
.
-
Curve Parameterization: If you need the Z at a specific parameter along the curve (not just the endpoint), you can use Curve.EvaluatePoint()
to get the point at that parameter, and then apply the same coordinate transformation. For example:
By using this coordinate transformation approach, you can reliably obtain Z-coordinates relative to the Project Base Point, regardless of the internal origin's position. This is the standard and most robust way to handle coordinate system differences in the Revit API. It's much cleaner and more reliable than trying to manipulate the internal origin itself.
This answer looks reasonable to me. Please check it suits your needs and please let us know how you end up solving this. Thank you!