Skip to content

V6 treats short parameter-trimmed conics as full circles by comparing radians with model length precision #578

Description

@tskarman

Summary

xBIM Geometry V6 can turn a short parameter-trimmed circle or ellipse into the complete basis conic. The affected code compares an angular parameter difference, in radians, with the IFC model precision, in model length units. If that dimensionally invalid comparison reports the parameters as equal, V6 deliberately constructs a full-period conic.

This produces a visible approximately 320 m diameter halo from an intended approximately 351 mm profile segment in Autodesk's well-known Revit 2015 Advanced Sample/Hospital Project file Revit-Hospital-Sample-Architecture.ifc. But a minimal repro file is supplied below.

This is what that looks like:

Image

Versions tested

Package source Xbim.Geometry version Result
Production package 6.3.873-netcore Reproduced
NuGet.org 6.3.891-netcore Reproduced
xBIM develop MyGet 6.3.897-netcore Reproduced
xBIM V5 comparison 5.1.820 Does not take the faulty full-conic branch

The develop package corresponds to source commit be4a6b95eec0b73140cbfd4a51300152c9e33781 on the repository's feature/netcore branch.

Source model

The original model is the Autodesk Revit 2015 Advanced Sample Project, also commonly described as the Hospital Project:

  • file: Revit-Hospital-Sample-Architecture.ifc;
  • schema: IFC2X3;
  • exporter: 20150702_1515(x64) - Exporter 15.5.0.0 - Alternate UI 15.5.0.0;
  • length unit: millimetres;
  • plane-angle unit: degrees;
  • geometric precision: 0.01.

The affected product is IfcColumn #143896, GlobalId 0Qqamdk$17GhXBxDp5aFHe. Its profile contains:

#143862=IFCCIRCLE(...,160200.000003463);
#143863=IFCTRIMMEDCURVE(#143862,(IFCPARAMETERVALUE(0.)),
  (IFCPARAMETERVALUE(0.125509171800891)),.T.,.PARAMETER.);

The self-contained IFC2X3 reproducer below retains the affected product's geometry and its original project, site, building, Level 1 storey, and spatial-containment chain. The same problem is not specific to Revit; Revit merely generated a representation that exposes a generic V6 tolerance defect.

Complete reduced IFC reproducer

Save this block as revit-2015-large-circle-trim.ifc.

ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition [CoordinationView_V2.0]'),'2;1');
FILE_NAME('Autodesk Revit 2015 Advanced Sample Project - reduced regression fixture','2016-01-23T23:11:34',(''),(''),'The EXPRESS Data Manager Version 5.02.0100.07 : 28 Aug 2013','20150702_1515(x64) - Exporter 15.5.0.0 - Alternate UI 15.5.0.0','');
FILE_SCHEMA(('IFC2X3'));
ENDSEC;
DATA;
#1=IFCORGANIZATION($,'Autodesk Revit 2015 (ENU)',$,$,$);
#5=IFCAPPLICATION(#1,'2015','Autodesk Revit 2015 (ENU)','Revit');
#6=IFCCARTESIANPOINT((0.,0.,0.));
#19=IFCDIRECTION((0.,0.,1.));
#31=IFCAXIS2PLACEMENT3D(#6,$,$);
#32=IFCLOCALPLACEMENT(#2372302,#31);
#35=IFCPERSON($,'','GH',$,$,$,$,$);
#37=IFCORGANIZATION($,'','',$,$);
#38=IFCPERSONANDORGANIZATION(#35,#37,$);
#41=IFCOWNERHISTORY(#38,#5,$,.NOCHANGE.,$,$,$,1440490985);
#42=IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.);
#46=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#47=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
#48=IFCMEASUREWITHUNIT(IFCRATIOMEASURE(0.0174532925199433),#46);
#49=IFCCONVERSIONBASEDUNIT(#47,.PLANEANGLEUNIT.,'DEGREE',#48);
#88=IFCUNITASSIGNMENT((#42,#49));
#90=IFCAXIS2PLACEMENT3D(#6,$,$);
#91=IFCDIRECTION((-0.0871557427476695,0.996194698091745));
#93=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,0.01,#90,#91);
#98=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#93,$,.MODEL_VIEW.,$);
#101=IFCPROJECT('2hExBg8jj4NRG6zzE$aSi6',#41,'Hospital Project',$,$,'Autodesk Revit sample','Project Status',(#93),#88);
#107=IFCPOSTALADDRESS($,$,$,$,('Enter address here'),$,'','','','<Default>');
#111=IFCBUILDING('2hExBg8jj4NRG6zzE$aSi7',#41,'',$,$,#32,$,'',.ELEMENT.,$,$,#107);
#117=IFCAXIS2PLACEMENT3D(#6,$,$);
#118=IFCLOCALPLACEMENT(#32,#117);
#120=IFCBUILDINGSTOREY('2hExBg8jj4NRG6zzD0RZML',#41,'Level 1',$,$,#118,$,'Level 1',.ELEMENT.,0.);
#39760=IFCCARTESIANTRANSFORMATIONOPERATOR3D($,$,#6,1.,$);
#143840=IFCCARTESIANPOINT((-117.026485049558,-116.975223248567));
#143842=IFCCARTESIANPOINT((233.79332117454,-116.975223248572));
#143844=IFCPOLYLINE((#143840,#143842));
#143846=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#143844);
#143847=IFCCARTESIANPOINT((-67.0804064917756,-66.9752232468841));
#143849=IFCDIRECTION((0.986471238240483,-0.163934426236665));
#143851=IFCAXIS2PLACEMENT2D(#143847,#143849);
#143852=IFCCIRCLE(#143851,304.999999999975);
#143853=IFCTRIMMEDCURVE(#143852,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(108.810968989093)),.T.,.PARAMETER.);
#143856=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#143853);
#143857=IFCCARTESIANPOINT((160082.963402356,-60.0438181634963));
#143859=IFCDIRECTION((-0.999998316074198,0.00183517020195723));
#143861=IFCAXIS2PLACEMENT2D(#143857,#143859);
#143862=IFCCIRCLE(#143861,160200.000003463);
#143863=IFCTRIMMEDCURVE(
  #143862,
  (IFCPARAMETERVALUE(0.)),
  (IFCPARAMETERVALUE(0.125509171800891)),
  .T.,.PARAMETER.);
#143866=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#143863);
#143867=IFCCOMPOSITECURVE((#143846,#143856,#143866),.F.);
#143872=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,'610mm Diameter',#143867);
#143873=IFCCARTESIANPOINT((81562.4442871042,64030.7615032145,0.));
#143875=IFCDIRECTION((-0.258819045102531,0.965925826289066,0.));
#143877=IFCAXIS2PLACEMENT3D(#143873,#19,#143875);
#143878=IFCEXTRUDEDAREASOLID(#143872,#143877,#19,5800.);
#143882=IFCSHAPEREPRESENTATION(#98,'Body','SweptSolid',(#143878));
#143884=IFCAXIS2PLACEMENT3D(#6,$,$);
#143885=IFCREPRESENTATIONMAP(#143884,#143882);
#143888=IFCMAPPEDITEM(#143885,#39760);
#143890=IFCSHAPEREPRESENTATION(#98,'Body','MappedRepresentation',(#143888));
#143892=IFCPRODUCTDEFINITIONSHAPE($,$,(#143890));
#143894=IFCAXIS2PLACEMENT3D(#6,$,$);
#143895=IFCLOCALPLACEMENT(#118,#143894);
#143896=IFCCOLUMN('0Qqamdk$17GhXBxDp5aFHe',#41,'M_Round Column:610mm Diameter:412031',$,'610mm Diameter',#143895,#143892,'412031');
#2372297=IFCCARTESIANPOINT((0.,0.,165811.2));
#2372299=IFCDIRECTION((0.996194698091745,-0.0871557427476695,0.));
#2372301=IFCAXIS2PLACEMENT3D(#2372297,#19,#2372299);
#2372302=IFCLOCALPLACEMENT($,#2372301);
#2372303=IFCSITE('2hExBg8jj4NRG6zzE$aSi4',#41,'Default',$,'',#2372302,$,$,.ELEMENT.,(42,21,30,344238),(-71,-3,-35,-194702),165811.2,$,$);
#2372315=IFCRELCONTAINEDINSPATIALSTRUCTURE('3Aw$FV5MbAufEo59tkoNgA',#41,$,$,(#143896),#120);
#2377568=IFCRELAGGREGATES('3ldi3SCOf4vPhFJoT0TUye',#41,$,$,#101,(#2372303));
#2377572=IFCRELAGGREGATES('27u5BTvUfB2fhXPe5h$W$S',#41,$,$,#2372303,(#111));
#2377576=IFCRELAGGREGATES('0bEVwXRmbBleAvzFSJirAn',#41,$,$,#111,(#120));
ENDSEC;
END-ISO-10303-21;

Actual behavior

After conversion to radians, the trim difference is approximately 0.00219055 rad. V6 compares it with the model's linear precision, 0.01 mm, decides that the trim parameters are equal, and returns the complete circle.

The resulting transformed bounds for product #143896 are approximately:

320399.997 x 320399.992 x 5800 mm

The X/Y size matches the 320400 mm diameter of the basis circle.

Expected behavior

The trimmed curve should remain the short intended arc. Its approximate length and endpoint chord are both about 350.926 mm, so its endpoints are not spatially coincident under any relevant model tolerance.

For comparison, V5 passes the two trim parameters to OpenCascade's Geom2d_TrimmedCurve without V6's nearly-equal shortcut. It does not create the full basis circle. Geometry produced after replacing only the affected trim with a tolerance-controlled polyline has bounds of approximately:

365.852 x 429.441 x 5800 mm

Suspected cause

The relevant V6 logic is in CurveFactory::BuildCurve2d(IIfcTrimmedCurve):

if (Math::Abs(u1 - u2) < ModelGeometryService->Precision)
{
    if (isConic)
        return Ptr()->BuildTrimmedCurve2d(basisCurve, 0, Math::PI * 2, true);
}

u1 and u2 have already been converted to radians, while Precision is expressed in model length units. A similar comparison exists in WireFactory::BuildWire(IIfcTrimmedCurve, bool).

The issue is therefore dimensional: radians are being compared directly with millimetres or another model length unit.

In the Autodesk sample, 143 parameter-trimmed circles satisfy this angular predicate even though their evaluated endpoint chords exceed the declared 0.01 mm precision. The smallest such chord is approximately 12.5 mm, so this is broader than the one unusually large circle.

Suggested fix

For periodic conics, determine whether the trims denote a full period by evaluating the two points on the basis curve and comparing their spatial distance with MinimumGap or another length tolerance:

distance(basisCurve(u1), basisCurve(u2)) <= MinimumGap

For a circle this is equivalent to:

2 * radius * sin(abs(u2 - u1) / 2) <= MinimumGap

Evaluating the basis curve is preferable because it also handles ellipses and transformed placements. The same predicate should be applied consistently in both CurveFactory and WireFactory.

The fix should preserve full-period conics whose parameter values differ but whose evaluated endpoints are genuinely coincident. It should also preserve SenseAgreement == false orientation.

Reproduction steps

  1. Open the original or reduced IFC with xBIM Essentials.
  2. Create an Xbim3DModelContext using XGeometryEngineVersion.V6.
  3. Call CreateContext(adjustWcs: true, generateBREPs: true).
  4. Find the shape instance whose IfcProductLabel is 143896.
  5. Transform its bounding box by the shape-instance transformation.
  6. Observe X/Y dimensions of approximately 320400 mm.
  7. Replace IfcTrimmedCurve #143863 with a polyline approximation of its evaluated arc and repeat.
  8. Observe X/Y dimensions below 500 mm while the extrusion remains approximately 5800 mm high.

generateBREPs: false produces the same incorrect full-circle bounds, so the behavior is not controlled by that option.

Workaround constraints

Switching the whole model context to XGeometryEngineVersion.V5 is not an adequate workaround for this sample because V5 aborts earlier on unrelated IfcExtrudedAreaSolid #65892. There does not appear to be a public V6 option that delegates only trimmed-curve construction to the V5/native implementation.

A downstream workaround can identify exactly the parameter-trimmed conics for which V6's angular comparison is true but the evaluated endpoint distance exceeds MinimumGap, then replace those trims with tolerance-controlled polylines before V6 geometry creation. Fixing the equality predicate in V6 is preferable.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions