Skip to content

Draft IfcAlignment Implementation Guide - Request for feedback #169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
RickBrice opened this issue Dec 13, 2024 · 16 comments
Open

Draft IfcAlignment Implementation Guide - Request for feedback #169

RickBrice opened this issue Dec 13, 2024 · 16 comments

Comments

@RickBrice
Copy link

Friends of the IF - I have made good progress in developing an implementation guide for IfcAlignment and the related geometries.

The draft guide is attached.
IfcAlignment Implementation Guide.pdf

  1. Is such a guide needed? Is it worthwhile to spend time finishing the guide?
  2. Please review and offer comments. It is a draft and rough in places.
  3. Would anyone like to help finish this work?
@evandroAlfieri
Copy link
Contributor

@RickBrice this is fantastic! Thank you very much for this.
This is very precious supporting material. Let me send this to the IFC Implementers Forum distribution list, usually people reads emails more frequently than github posts ;)

If we get another couple of authors to chip in, I think we can publish it as official resource.

@RickBrice
Copy link
Author

RickBrice commented Mar 23, 2025

@evandroAlfieri @jmirtsch @peterrdf @apinzenoehler @SergejMuhic @aothms @civilx64

I am continuing to work on this IfcAlignment Geometry Implementation Guide. I am looking at cant and I believe there to be an error in @peterrdf EnrichIFC4x3 software that has led me to incorrectly defining the equations for cant in this document and may be misleading others who use the example datasets for development and testing.

The equation for cant has the same general mathematic form as the equation for curvature. For example, the BSI Standard 13803:2017 defines the mathematical function for Cosine curve cant transition as

$$D(s) = D_1 + \frac{1}{2}(1-cos(\frac{\pi s}{L_D}))\Delta D$$

The curvature equation is

$$\kappa(s) = \frac{1}{A_0} + \frac{1}{A_1}cos(\frac{\pi s}{L}) $$

With a few algebraic manipulations we can show that D(s) has the same form as k(s). However, we note that the cant equation yields values with length units and the curvature equation yields values with length^-1 units.

For this reason we let

$$ D(s) = \kappa(s) L^2 $$

which yields values with length units.

Studying the code in EnricnIFC4x3 from https://github.com/bSI-RailwayRoom/IFC-Rail-Unit-Test-Reference-Code/ one sees that

$$ \Delta D = D_e - D_s $$

Constant term:

$$ A_0 = \frac{L}{D_1 + \frac{1}{2} \Delta D} $$

Cosine term:

$$ A_1 = \frac{L}{ -\frac{1}{2} \Delta D } $$

The problem with A0 and A1 is that they are unitless quantities. These terms must have units of length when used in the curvature equation, k(s), defined in https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcCosineSpiral.htm.

Consider the example https://github.com/bSI-RailwayRoom/IFC-Rail-Unit-Test-Reference-Code/blob/master/alignment_testset/IFC-WithGeneratedGeometry/GENERATED__CantAlignment_CosineCurve_100.0_1000_300_1_Meter.ifc.

The cant segment is defined as

#64 = IFCALIGNMENTCANTSEGMENT($, $, 0., 100., 0., 0., 0., 0.16, .COSINECURVE.);

The geometric representation is

#113 = IFCCURVESEGMENT(.CONTINUOUS., #123, IFCLENGTHMEASURE(0.), IFCLENGTHMEASURE(100.), #127);
#127 = IFCCOSINESPIRAL(#128, -2500., 2500.);

From the cant segment definition

$$ L = 100 m $$ $$ D_1 = \frac{0 m + 0m}{2} = 0 m $$ $$ D_2 = \frac{0 m +0.16 m}{2} = 0.08 m $$ $$ \Delta D = 0.08m - 0.0m = 0.08 m $$

$$ A_0 = \frac{100 m}{0.0 m + 0.5(0.08 m)} = 2500 $$ $$ A_1 = \frac{100 m}{-0.5(0.08m)} = -2500 $$

The constant and cosine terms match the parameters in the geometric representation of the cant segment.

Evaluating the cant at the mid-point of the segment we get

$$ D(50m) = (100 m)^2 ( \frac{1}{2500} + \frac{1}{-2500}cos(\frac{\pi 50m}{100m})) = 800 m^2 $$

This results is obviously incorrect.

I believe the correct constant and cosine terms are

Constant term:

$$ A_0 = \frac{L^2}{D_1 + \frac{1}{2}\Delta D} $$

Cosine term:

$$ A_1 = \frac{L^2}{-\frac{1}{2}\Delta D} $$

which have units of length.

The revised calculation of the IfcCosineSpiral parameters is

$$ A_0 = \frac{(100 m)^2}{0.0 m + 0.5(0.08 m)} = 250000 m $$ $$ A_1 = \frac{(100 m)^2}{-0.5(0.08m)} = -250000 m $$

The cosine spiral definition is them

#127 = IFCCOSINESPIRAL(#128, -250000., 250000.);

and evaluation of the mid-segment cant is

$$ D(50) = (100 m)^2 ( \frac{1}{250000 m} + \frac{1}{-250000 m}cos(\frac{\pi 50m}{100m})) = 0.08 m $$

This is the correct result.

The EnrichIFC4x3 program uses

$$ D(s) = \kappa(s) L $$

$$ D(50) = (100 m) ( \frac{1}{2500} + \frac{1}{-2500}cos(\frac{\pi 50m}{100m})) = 0.08 m $$

which also yields the correct result, in the correct units, but for the wrong reason.

Implementer agreement is critical here. There is a very significant difference between these two representations of the same cant transition

#127 = IFCCOSINESPIRAL(#128, -2500., 2500.);

#127 = IFCCOSINESPIRAL(#128, -250000., 250000.);

The same concern holds true for polynomial spirals. The EnrichIFC4x3 program computes the polynomial coefficients and they all have the general form of

$$ A_i = \frac{L}{\sqrt[i+1]{|a_i|}}\frac{a_i}{|a_i|} $$

which does not yield coefficients with length units.

For the coefficient to have length units, its general form is

$$ A_i = \frac{L^{(i+2)/(i+1)}}{\sqrt[i+1]{|a_i|}}\frac{a_i}{|a_i|} $$

The fundamental question is the correct relationship between D(s) and k(s).

$$ D(s) = \kappa(s) L $$

OR

$$ D(s) = \kappa(s) L^2 $$

I believe the second relationship to be correct because it respects the units of measure of the parent curve terms and yields a result in the correct unit of measure.

@SamiLyden
Copy link

SamiLyden commented Mar 31, 2025

I kind of assumed that the documentation for ifcpolygonalcurve

1 | Position | IfcPlacement | No description available.
2 | CoefficientsX | OPTIONAL LIST [2:?] OF IfcReal | No description available.
3 | CoefficientsY | OPTIONAL LIST [2:?] OF IfcReal | No description available.
4 | CoefficientsZ | OPTIONAL LIST [2:?] OF IfcReal | No description available.

means that for example

Image

Now I guess for alignment this means what in the document but it kind of jumps from IfcPolynomialCurve(undocumented) -> alignment curve.

@RickBrice
Copy link
Author

@SamiLyden thank you for the feedback. Yes, I think the guidance document jumps from the general IfcPolynomialCurve, which could be used for any geometry, to the specific case of a cubic transition curve without explanation. I have made the same "jump" for the spiral types.

This was recently pointed out to me by others as well. I will endeavor to add introductory remarks in the document that distinguishes between general geometry and specific cases applicable to alignments.

There are some issues with mapping of business to geometry for cant in the document as well. I'll post an updated version soon.

@RickBrice
Copy link
Author

Here is an updated draft of the implementation guide. There is still much work to be done. Feedback is appreciated.

Alignment Geometry Implementation Guide.pdf

@SamiLyden there are some serious problems with IfcPolynomialCurve and CUBIC transition spirals and PARABOLICARC vertical curves in the IFC specification. They are highlighted in the document but to summarize:

  1. IfcPolynomialCurve is very clear that the coefficients are real numbers. They are unitless, scalar values.
  2. IfcAlignmentHorizontalSegmentTypeEnum provides an equation for CUBIC as y = (x^3)/(6RL). The coefficient is 1/6RL which has units of Length^-2. This is completely incorrect based on IfcPolynomialCurve.
  3. IfcAlignmentVerticalSegmentTypeEnum defines the general equation of a PARABOLICARC as y = ax^2 + bx + c. For y to have units of length, a must have units of Length^-1, b is unitless real value, and c has units of length. This too is completely incorrect based on IfcPolynomialCurve.

How are you determining the coefficients for IfcPolynomialCurve so it represents IfcAlignmentSegment for horizontal and vertical properly?

@civilx64
Copy link

civilx64 commented Apr 1, 2025

@RickBrice what would you think of publishing the guide somewhere online, to allow for multiple contributors to make updates as well as to comment on specific items? I would probably default to using markdown, placing the content in its own repo, and using a Github action to publish a new PDF on every push to main.

@SergejMuhic
Copy link

This would be the place for parabolic :https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/concepts/Partial_Templates/Geometry/Curve_Segment_Geometry/Parabolic_Transition_Segment/content.html

and for cubic
https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/concepts/Partial_Templates/Geometry/Curve_Segment_Geometry/Cubic_Transition_Segment/content.html

I think these should be usages directly on IfcAlignmentSegment. This would be correct from the point of view of the specification. Exactly how it worked in the IFC4 documentation. I am puzzled to see why the IFC4.3 documentation does not features a "General Usage" section anymore.

@RickBrice
Copy link
Author

The problem with parabolic and cubic is the unit of measure for the polynomial coefficients. IfcPolynomialCurve lists the coefficients as real values - these are scalar, unitless quantities.

From parabolic transition y = CoefficientsX[3]*x² the CoefficientsX[3] must have a units of 1/Length so that y is in units of length.

y = (1/Length)(Length^2) = Length

From cubic, y = CoefficientsX[3]*x³, the CoefficientsX[3] must have a unit of 1/(Length^2) so that y is in units of length.

y =(1/Length^2)(Length^3) = Length

The coefficients cannot be unitless, but they must be for IfcPolynomialCurve - this is an error in the specification.

@SergejMuhic
Copy link

SergejMuhic commented Apr 2, 2025

I agree, I have been facing this issue when specifying the definition for IfcPolynomialCurve. I have not found a good solution to this, so it seemed (for the time being) to be best, making the coefficients unitless.

Maybe a simple agreement in the form of: "the project length units define the units of the coefficients where the power of the coefficient is determined by the negative index subtracted by 1 in the Coefficients list i.e. index - 1 multiplied by -1". Could also make sense then to change IfcReal to IfcLengthMeasure just to have that explicit connection to units.

I don't have a better idea unfortunately, but maybe others come up with something.

@aothms
Copy link

aothms commented Apr 2, 2025

The only solution I can think would be

(a) to have the coefficients as a LIST OF IfcValue with a where rule enforcing the relationship you laid out above but then on the measure, so would get (IFCLENGTHMEASURE(1.), IFCNUMERICMEASURE(2.), IFCRECIPROCALLENGTHMASURE(3.)) for $$y=1 + 2x + 3x^3$$, but that's not a workable solution either because (a) we don't have that many measures (b) we can't get the unit easily from the measure in express so we cannot get the dimensional exponents either.

(b) define these as numeric measures, but access them by means of a derived attr that does the unit conversion based on the project length to the power ... That's more of a symbolic solution because the specification and unit remains wrong, just that you offer some sort of 'API' to deal with it embedded in the schema.

@SamiLyden
Copy link

SamiLyden commented Apr 2, 2025

Agree that this is a problem. especially since its in no way documented. so everyone now end up with whatever works for them.
I guess most solutions at the moment rely on '#7 = IFCSIUNIT(*, .LENGTHUNIT., $, .METRE.);'
The use of ifcpolynomialcurve was a pretty ad hoc solution used just because there does not seem to be alternative. (afaik) And is now applied incorrectly or in not intended way.

But I dont think the issue is the coefficients. Those are just a set of scalar multipliers. The whole thing is broken as the polynomial curve is defined for parameter values, for some reason we are now always using lengthmeasure as parameter value https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/lexical/IfcCurveSegment.htm
For the polynomial giving unit value as parameter means doing something like f(u)=x² and u = 1m or 1000mm would procude -> 1m² and 1000000mm² which are the same thing and would work just fine. But obviously wrong results for the polynomial.
hhowever if we use parametervalue for polynomial curve there is nothing anywhere stating that this produces a lengthmeasures at all. Other that the context which would mean that the result is in file scope length measure.

Tldr
For this to work both the polynomial and the parameter need to be in file scope length unit if using parameter value, and in the same length unit if using parameter value. (which I gues its always in file scope) the polynomial curve cannot change the unit the parameter has.

@RickBrice
Copy link
Author

RickBrice commented Apr 2, 2025

At this stage of the game, Ifc4x3 is an ISO standard so I don't think it can be changed. An agreement is needed for dealing with polynomials. Since we are talking about real world geometry the x, y, and z results of evaluating IfcPolynomial should have units of Length.

I don't think there is any choice but for coefficient $i$ to have units of $Length^{(1-i)}$. For the equations that follow
the unit of measure of the coefficients are:

$Length^{(1-i)}$ for $a_i$

$Length^{(1-j)}$ for $b_j$

$Length^{(1-k)}$ for $c_k$

When $u$ is parametrized in Length,

$Q(u) = ( x(u), y(u), z(u) )$

$x(u) = \sum\limits_{i=0}^{l} a_i u^i $

$y(u) = \sum\limits_{j=0}^{m} b_j u^j $

$z(u) = \sum\limits_{k=0}^{n} c_k u^k $

Example:
$u$ parametrized as Length
$a_i = (0,1)$
$b_j = (0,0,0,\frac{1}{6RL})$
$u(L) = ((0 + 1L), (0+0+0+\frac{1}{6RL} L^3) = (L,\frac{L^2}{6R})$

When $u$ is parametrized as a scalar such that $u=1$ corresponds to the same point as $L$ from the origin,

$Q(u) = ( x(u), y(u), z(u) )$

$x(u) = \sum\limits_{i=0}^{l} L^i a_i u^i $

$y(u) = \sum\limits_{j=0}^{m} L^j b_j u^j $

$z(u) = \sum\limits_{k=0}^{n} L^k c_k u^k $

Example:
$u$ parametrized as scalar
$a_i = (0,1)$
$b_j = (0,0,0,\frac{1}{6RL})$
$u(1) = ((0L^0 + 1L^1), (0L^0+0L^1+0L^2+\frac{1}{6RL} L^3 1^3) = (L,\frac{L^2}{6R})$

Since IfcCurveSegment.SegmentStart and .SegmentLength are agreed to be IfcLengthMeasure the first example seems to be the best we can do. If IfcCurveSegment.SegmentStart = IfcParameterValue(0.5) and IfcCurveSegment.SegmentLength = IfcParameterValue(0.9), there is no way to know the value of $L$ for the calculation in the second example.

@RickBrice
Copy link
Author

@civilx64 Good idea - I'll have to experiment with some Word to MD converters.

@civilx64
Copy link

civilx64 commented Apr 2, 2025

I have had good luck with pandoc although mostly going the other direction.

@SergejMuhic
Copy link

for some reason we are now always using lengthmeasure as parameter value

This was never the design intent. It was just there to make the first tests easier. I have posted an issue about that and have been trying even before publishing the ISO to fix this.

buildingSMART/IFC4.3.x-development#884

To no avail. It should never have been a select in the ISO!

@RickBrice agree, we make use of the ISO as is.

Your example can be extended to the higher order polynomial spirals. Using IfcLengthMeasure in IfcCurveSegment never made much sense for anything other the constant coefficients, so simpler curves such as IfcLine, IfcCircle, IfcClothoid. I brought the topic up many times.

(b) define these as numeric measures
I thought about the same thing.

ENTITY IfcPolynomialCurve
 SUBTYPE OF (IfcCurve);
	Position : IfcPlacement;
	CoefficientsX : OPTIONAL LIST [2:?] OF IfcLengthMeasure;
	CoefficientsY : OPTIONAL LIST [2:?] OF IfcLengthMeasure;
	CoefficientsZ : OPTIONAL LIST [2:?] OF IfcLengthMeasure;
 DERIVE
	TermsX : LIST [2:?] OF IfcLengthMeasure := IfcCalculateTerms(SELF.CoefficientsX, Coordinates);
	TermsX : LIST [2:?] OF IfcLengthMeasure := IfcCalculateTerms(SELF.CoefficientsY, Coordinates);
	TermsX : LIST [2:?] OF IfcLengthMeasure := IfcCalculateTerms(SELF.CoefficientsZ, Coordinates);
 WHERE
	CorrectPositionDim : ((Position.Dim=2) AND (NOT EXISTS(CoefficientsZ))) OR (Position.Dim=3);
	ValidCoefficients : (EXISTS(CoefficientsX) AND EXISTS(CoefficientsY)) OR (EXISTS(CoefficientsX) AND EXISTS(CoefficientsZ)) OR (EXISTS(CoefficientsY) AND EXISTS(CoefficientsZ)) OR (EXISTS(CoefficientsX) AND EXISTS(CoefficientsY) AND EXISTS(CoefficientsZ));
END_ENTITY;

The problem here is however, that the Coordinates are not in the instance.

So, as @RickBrice stated above and we treat the coefficients to be on the parameter u, we can put the equations back together. Parameter -&#8734; < u < &#8734;. As suggested here:
buildingSMART/IFC4.3.x-development#946 (comment)
Then the agreement in the scope of the current ISO would have to be that u is an IfcLengthMeasure unfortunately. Which makes no sense but the units have to come from somewhere.

For the future though, the definition could be modified like this:

ENTITY IfcPolynomialCurve
 SUBTYPE OF (IfcCurve);
	Position : IfcPlacement;
	CoefficientsX : OPTIONAL LIST [2:?] OF IfcLengthMeasure;
	CoefficientsY : OPTIONAL LIST [2:?] OF IfcLengthMeasure;
	CoefficientsZ : OPTIONAL LIST [2:?] OF IfcLengthMeasure;
 WHERE
	CorrectPositionDim : ((Position.Dim=2) AND (NOT EXISTS(CoefficientsZ))) OR (Position.Dim=3);
	ValidCoefficients : (EXISTS(CoefficientsX) AND EXISTS(CoefficientsY)) OR (EXISTS(CoefficientsX) AND EXISTS(CoefficientsZ)) OR (EXISTS(CoefficientsY) AND EXISTS(CoefficientsZ)) OR (EXISTS(CoefficientsX) AND EXISTS(CoefficientsY) AND EXISTS(CoefficientsZ));
END_ENTITY;

With the documentation on Coefficients : "The terms for the polynomial as IfcLengthMeasure where the value for the polynomial equation is calculated as
$${1\over Coefficient^{IndexOf(Coefficient) - 1)}}.$$"

@RickBrice
Copy link
Author

@civilx64 I have moved the guide to it own repo. Ready for contributions and PRs

https://github.com/[RickBrice/IFC-Alignment-Geometry-Implementation-Guide](https://github.com/RickBrice/IFC-Alignment-Geometry-Implementation-Guide/tree/main)/tree/main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants