From da32031574665645bf558b8c467221718ca975df Mon Sep 17 00:00:00 2001 From: Stephen Lockley Date: Thu, 30 Apr 2020 11:17:35 +0100 Subject: [PATCH 1/2] Fix for Composite Curve generation in Issues #261. Use of OCC wirebuilder removed to allow priorty to edge connection to be wire ends rather than nearest vertex in the wires Improved tolerance calculation for models that are out of their defined tolerance --- .../TestFiles/composite_curve_issue_261.ifc | 232 ++++++++++++++++ .../WireAndFaceTests.cs | 11 + .../Xbim.Geometry.Engine.Interop.Tests.csproj | 3 + .../Factories/WireFactory.cpp | 9 + Xbim.Geometry.Engine/Factories/WireFactory.h | 11 + .../Xbim.Geometry.Engine.vcxproj | 2 + .../Xbim.Geometry.Engine.vcxproj.filters | 6 + Xbim.Geometry.Engine/XbimWire.cpp | 256 +++++++++++------- Xbim.Geometry.Engine/XbimWire.h | 7 + 9 files changed, 443 insertions(+), 94 deletions(-) create mode 100644 Xbim.Geometry.Engine.Interop.Tests/TestFiles/composite_curve_issue_261.ifc create mode 100644 Xbim.Geometry.Engine/Factories/WireFactory.cpp create mode 100644 Xbim.Geometry.Engine/Factories/WireFactory.h diff --git a/Xbim.Geometry.Engine.Interop.Tests/TestFiles/composite_curve_issue_261.ifc b/Xbim.Geometry.Engine.Interop.Tests/TestFiles/composite_curve_issue_261.ifc new file mode 100644 index 000000000..c207e2551 --- /dev/null +++ b/Xbim.Geometry.Engine.Interop.Tests/TestFiles/composite_curve_issue_261.ifc @@ -0,0 +1,232 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION ((''), '2;1'); +FILE_NAME ('', '2020-04-28T12:10:14', (''), (''), 'Processor version 5.0.0.0', 'Xbim.IO.MemoryModel', ''); +FILE_SCHEMA (('IFC2X3')); +ENDSEC; +DATA; +#1=IFCCOMPOSITECURVE((#2,#8,#15,#19,#25,#31,#35,#40,#46,#50,#55,#60,#64,#68,#73,#77,#82,#87,#91,#95,#100,#104,#108,#113,#117,#121,#126,#130,#134,#139,#143,#147,#152,#156,#160,#165,#169,#173,#178,#182,#187,#192,#196),.F.); +#2=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#3); +#3=IFCTRIMMEDCURVE(#4,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(50.0000000006965)),.T.,.PARAMETER.); +#4=IFCLINE(#5,#6); +#5=IFCCARTESIANPOINT((0.,0.,0.)); +#6=IFCVECTOR(#7,1.); +#7=IFCDIRECTION((0.999999999999215,1.25306505651584E-06,3.49245254934071E-11)); +#8=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#9); +#9=IFCTRIMMEDCURVE(#10,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632677167)),.T.,.PARAMETER.); +#10=IFCCIRCLE(#11,30.); +#11=IFCAXIS2PLACEMENT3D(#12,#13,#14); +#12=IFCCARTESIANPOINT((49.9999999995551,1.40164756885497E-05,30.0000000018989)); +#13=IFCDIRECTION((1.53493365368072E-06,-0.999999999996636,-2.0910068997036E-06)); +#14=IFCDIRECTION((1.80929462523238E-07,1.43799648415969E-06,-0.99999999999895)); +#15=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#16); +#16=IFCTRIMMEDCURVE(#17,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.5707963268186)),.T.,.PARAMETER.); +#17=IFCCIRCLE(#18,30.); +#18=IFCAXIS2PLACEMENT3D(#12,#13,#7); +#19=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#20); +#20=IFCTRIMMEDCURVE(#21,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000006876)),.T.,.PARAMETER.); +#21=IFCLINE(#22,#23); +#22=IFCCARTESIANPOINT((49.9999999986908,-4.87137330935639E-05,60.000000001601)); +#23=IFCVECTOR(#24,1.); +#24=IFCDIRECTION((-0.999999999999215,-1.25306514232965E-06,-3.50554134578805E-11)); +#25=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#26); +#26=IFCTRIMMEDCURVE(#27,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632683607)),.T.,.PARAMETER.); +#27=IFCCIRCLE(#28,30.); +#28=IFCAXIS2PLACEMENT3D(#29,#13,#30); +#29=IFCCARTESIANPOINT((-780.000000006111,-0.00125997850773274,29.9999999686622)); +#30=IFCDIRECTION((-7.6311770711312E-09,-1.43796308472523E-06,0.999999999998966)); +#31=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#32); +#32=IFCTRIMMEDCURVE(#33,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671677)),.T.,.PARAMETER.); +#33=IFCCIRCLE(#34,30.); +#34=IFCAXIS2PLACEMENT3D(#29,#13,#24); +#35=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#36); +#36=IFCTRIMMEDCURVE(#37,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000050748)),.T.,.PARAMETER.); +#37=IFCLINE(#38,#39); +#38=IFCCARTESIANPOINT((-780.000000043591,-0.00119724830085488,6.19616713493087E-09)); +#39=IFCVECTOR(#7,1.); +#40=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#41); +#41=IFCTRIMMEDCURVE(#42,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671683)),.T.,.PARAMETER.); +#42=IFCCIRCLE(#43,30.); +#43=IFCAXIS2PLACEMENT3D(#44,#45,#30); +#44=IFCCARTESIANPOINT((50.0000000061672,0.000139476887909495,-29.999999991404)); +#45=IFCDIRECTION((-1.53493371287315E-06,0.999999999996636,2.09100689982117E-06)); +#46=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#47); +#47=IFCTRIMMEDCURVE(#48,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.5707963268731)),.T.,.PARAMETER.); +#48=IFCCIRCLE(#49,30.); +#49=IFCAXIS2PLACEMENT3D(#44,#45,#7); +#50=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#51); +#51=IFCTRIMMEDCURVE(#52,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000010356)),.T.,.PARAMETER.); +#52=IFCLINE(#53,#54); +#53=IFCCARTESIANPOINT((50.0000000126015,0.000202207094901041,-59.9999999848882)); +#54=IFCVECTOR(#24,1.); +#55=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#56); +#56=IFCTRIMMEDCURVE(#57,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632687285)),.T.,.PARAMETER.); +#57=IFCCIRCLE(#58,30.); +#58=IFCAXIS2PLACEMENT3D(#59,#13,#30); +#59=IFCCARTESIANPOINT((-779.999999996792,-0.00100905767979498,-89.9999999870483)); +#60=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#61); +#61=IFCTRIMMEDCURVE(#62,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671727)),.T.,.PARAMETER.); +#62=IFCCIRCLE(#63,30.); +#63=IFCAXIS2PLACEMENT3D(#59,#13,#24); +#64=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#65); +#65=IFCTRIMMEDCURVE(#66,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000020537)),.T.,.PARAMETER.); +#66=IFCLINE(#67,#6); +#67=IFCCARTESIANPOINT((-780.000000004069,-0.000946327472831854,-119.999999979712)); +#68=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#69); +#69=IFCTRIMMEDCURVE(#70,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671727)),.T.,.PARAMETER.); +#70=IFCCIRCLE(#71,30.); +#71=IFCAXIS2PLACEMENT3D(#72,#45,#30); +#72=IFCCARTESIANPOINT((50.000000015484,0.000390397715875679,-149.999999977149)); +#73=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#74); +#74=IFCTRIMMEDCURVE(#75,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632687272)),.T.,.PARAMETER.); +#75=IFCCIRCLE(#76,30.); +#76=IFCAXIS2PLACEMENT3D(#72,#45,#7); +#77=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#78); +#78=IFCTRIMMEDCURVE(#79,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000012055)),.T.,.PARAMETER.); +#79=IFCLINE(#80,#81); +#80=IFCCARTESIANPOINT((50.0000000236123,0.000453127922384056,-179.999999968943)); +#81=IFCVECTOR(#24,1.); +#82=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#83); +#83=IFCTRIMMEDCURVE(#84,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632687303)),.T.,.PARAMETER.); +#84=IFCCIRCLE(#85,30.); +#85=IFCAXIS2PLACEMENT3D(#86,#13,#30); +#86=IFCCARTESIANPOINT((-779.999999987477,-0.000758136858621583,-209.999999971212)); +#87=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#88); +#88=IFCTRIMMEDCURVE(#89,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671677)),.T.,.PARAMETER.); +#89=IFCCIRCLE(#90,30.); +#90=IFCAXIS2PLACEMENT3D(#86,#13,#24); +#91=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#92); +#92=IFCTRIMMEDCURVE(#93,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000022394)),.T.,.PARAMETER.); +#93=IFCLINE(#94,#6); +#94=IFCCARTESIANPOINT((-779.999999996613,-0.000695406645348839,-239.999999962022)); +#95=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#96); +#96=IFCTRIMMEDCURVE(#97,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671677)),.T.,.PARAMETER.); +#97=IFCCIRCLE(#98,30.); +#98=IFCAXIS2PLACEMENT3D(#99,#45,#30); +#99=IFCCARTESIANPOINT((50.0000000247918,0.000641318529773116,-269.999999959623)); +#100=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#101); +#101=IFCTRIMMEDCURVE(#102,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632684798)),.T.,.PARAMETER.); +#102=IFCCIRCLE(#103,30.); +#103=IFCAXIS2PLACEMENT3D(#99,#45,#7); +#104=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#105); +#105=IFCTRIMMEDCURVE(#106,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000014769)),.T.,.PARAMETER.); +#106=IFCLINE(#107,#54); +#107=IFCCARTESIANPOINT((50.0000000348932,0.000704048736281493,-299.999999950195)); +#108=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#109); +#109=IFCTRIMMEDCURVE(#110,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632684779)),.T.,.PARAMETER.); +#110=IFCCIRCLE(#111,30.); +#111=IFCAXIS2PLACEMENT3D(#112,#13,#30); +#112=IFCCARTESIANPOINT((-779.999999978158,-0.000507216038386105,-329.999999973254)); +#113=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#114); +#114=IFCTRIMMEDCURVE(#115,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671708)),.T.,.PARAMETER.); +#115=IFCCIRCLE(#116,30.); +#116=IFCAXIS2PLACEMENT3D(#112,#13,#24); +#117=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#118); +#118=IFCTRIMMEDCURVE(#119,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000045739)),.T.,.PARAMETER.); +#119=IFCLINE(#120,#39); +#120=IFCCARTESIANPOINT((-780.000000010641,-0.000444485830996655,-359.999999940715)); +#121=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#122); +#122=IFCTRIMMEDCURVE(#123,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.5707963267169)),.T.,.PARAMETER.); +#123=IFCCIRCLE(#124,30.); +#124=IFCAXIS2PLACEMENT3D(#125,#45,#30); +#125=IFCCARTESIANPOINT((50.0000000341123,0.000892239371324877,-389.999999938206)); +#126=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#127); +#127=IFCTRIMMEDCURVE(#128,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632687303)),.T.,.PARAMETER.); +#128=IFCCIRCLE(#129,30.); +#129=IFCAXIS2PLACEMENT3D(#125,#45,#7); +#130=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#131); +#131=IFCTRIMMEDCURVE(#132,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000015602)),.T.,.PARAMETER.); +#132=IFCLINE(#133,#81); +#133=IFCCARTESIANPOINT((50.0000000457892,0.000954969578799592,-419.999999926452)); +#134=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#135); +#135=IFCTRIMMEDCURVE(#136,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.5707963268729)),.T.,.PARAMETER.); +#136=IFCCIRCLE(#137,30.); +#137=IFCAXIS2PLACEMENT3D(#138,#13,#30); +#138=IFCCARTESIANPOINT((-779.999999968847,-0.000256295203172385,-449.99999992872)); +#139=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#140); +#140=IFCTRIMMEDCURVE(#141,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671695)),.T.,.PARAMETER.); +#141=IFCCIRCLE(#142,30.); +#142=IFCAXIS2PLACEMENT3D(#138,#13,#24); +#143=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#144); +#144=IFCTRIMMEDCURVE(#145,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000026012)),.T.,.PARAMETER.); +#145=IFCLINE(#146,#6); +#146=IFCCARTESIANPOINT((-779.999999981592,-0.00019356500300205,-479.99999991592)); +#147=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#148); +#148=IFCTRIMMEDCURVE(#149,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671695)),.T.,.PARAMETER.); +#149=IFCCIRCLE(#150,30.); +#150=IFCAXIS2PLACEMENT3D(#151,#45,#30); +#151=IFCCARTESIANPOINT((50.0000000434328,0.0011431601920151,-509.999999913466)); +#152=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#153); +#153=IFCTRIMMEDCURVE(#154,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632687284)),.T.,.PARAMETER.); +#154=IFCCIRCLE(#155,30.); +#155=IFCAXIS2PLACEMENT3D(#151,#45,#7); +#156=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#157); +#157=IFCTRIMMEDCURVE(#158,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000017407)),.T.,.PARAMETER.); +#158=IFCLINE(#159,#23); +#159=IFCCARTESIANPOINT((50.0000000569123,0.00120589039272545,-539.999999899911)); +#160=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#161); +#161=IFCTRIMMEDCURVE(#162,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632687284)),.T.,.PARAMETER.); +#162=IFCCIRCLE(#163,30.); +#163=IFCAXIS2PLACEMENT3D(#164,#13,#30); +#164=IFCCARTESIANPOINT((-779.999999959526,-5.37437568937094E-06,-569.999999902234)); +#165=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#166); +#166=IFCTRIMMEDCURVE(#167,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671702)),.T.,.PARAMETER.); +#167=IFCCIRCLE(#168,30.); +#168=IFCAXIS2PLACEMENT3D(#164,#13,#24); +#169=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#170); +#170=IFCTRIMMEDCURVE(#171,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000027747)),.T.,.PARAMETER.); +#171=IFCLINE(#172,#6); +#172=IFCCARTESIANPOINT((-779.999999974015,5.73558244809647E-05,-599.999999887687)); +#173=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#174); +#174=IFCTRIMMEDCURVE(#175,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632671702)),.T.,.PARAMETER.); +#175=IFCCIRCLE(#176,30.); +#176=IFCAXIS2PLACEMENT3D(#177,#45,#30); +#177=IFCCARTESIANPOINT((50.000000052746,0.0013940810131885,-629.999999885179)); +#178=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#179); +#179=IFCTRIMMEDCURVE(#180,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632687284)),.T.,.PARAMETER.); +#180=IFCCIRCLE(#181,30.); +#181=IFCAXIS2PLACEMENT3D(#177,#45,#7); +#182=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#183); +#183=IFCTRIMMEDCURVE(#184,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(830.000000020899)),.T.,.PARAMETER.); +#184=IFCLINE(#185,#186); +#185=IFCCARTESIANPOINT((50.0000000680901,0.00145681122018004,-659.999999869759)); +#186=IFCVECTOR(#24,1.); +#187=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#188); +#188=IFCTRIMMEDCURVE(#189,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632681858)),.T.,.PARAMETER.); +#189=IFCCIRCLE(#190,30.); +#190=IFCAXIS2PLACEMENT3D(#191,#45,#14); +#191=IFCCARTESIANPOINT((-779.999999951821,0.000120086031500932,-629.999999872213)); +#192=IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#193); +#193=IFCTRIMMEDCURVE(#194,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.57079632677046)),.T.,.PARAMETER.); +#194=IFCCIRCLE(#195,30.); +#195=IFCAXIS2PLACEMENT3D(#191,#45,#24); +#196=IFCCOMPOSITECURVESEGMENT(.DISCONTINUOUS.,.T.,#197); +#197=IFCTRIMMEDCURVE(#171,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(50.000000000928)),.T.,.PARAMETER.); +#198=IFCPROJECT('1EVvgQI8b09w9KP51HvyfM',#209,'Viaduc du Cher',$,$,$,$,(#210),#214); +#199=IFCOWNERHISTORY(#202,#203,$,.ADDED.,1588075815,$,$,0); +#200=IFCPERSON($,'Steve','',$,$,$,$,$); +#201=IFCORGANIZATION($,'Unspecified',$,$,$); +#202=IFCPERSONANDORGANIZATION(#200,#201,$); +#203=IFCAPPLICATION(#201,'Unspecified','Unspecified',$); +#204=IFCOWNERHISTORY(#205,#208,$,.NOCHANGE.,$,$,$,1489153534); +#205=IFCPERSONANDORGANIZATION(#206,#207,$); +#206=IFCPERSON('VINCIC-FR\\nicolas.legain','Undefined',$,$,$,$,$,$); +#207=IFCORGANIZATION($,'Trimble Solutions Corporation',$,$,$); +#208=IFCAPPLICATION(#207,'2016 Service Pack 5','Tekla Structures','Multi material modeling'); +#209=IFCOWNERHISTORY(#202,#203,$,.MODIFIED.,1588075815,$,$,0); +#210=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#211,$); +#211=IFCAXIS2PLACEMENT3D(#5,#212,#213); +#212=IFCDIRECTION((0.,0.,1.)); +#213=IFCDIRECTION((1.,0.,0.)); +#214=IFCUNITASSIGNMENT((#215,#216,#217,#218,#219,#220,#221,#222,#223)); +#215=IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.); +#216=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); +#217=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.); +#218=IFCSIUNIT(*,.MASSUNIT.,.KILO.,.GRAM.); +#219=IFCSIUNIT(*,.TIMEUNIT.,$,.SECOND.); +#220=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#221=IFCSIUNIT(*,.SOLIDANGLEUNIT.,$,.STERADIAN.); +#222=IFCSIUNIT(*,.THERMODYNAMICTEMPERATUREUNIT.,$,.DEGREE_CELSIUS.); +#223=IFCSIUNIT(*,.LUMINOUSINTENSITYUNIT.,$,.LUMEN.); +ENDSEC; +END-ISO-10303-21; diff --git a/Xbim.Geometry.Engine.Interop.Tests/WireAndFaceTests.cs b/Xbim.Geometry.Engine.Interop.Tests/WireAndFaceTests.cs index 1595de501..356c4520a 100644 --- a/Xbim.Geometry.Engine.Interop.Tests/WireAndFaceTests.cs +++ b/Xbim.Geometry.Engine.Interop.Tests/WireAndFaceTests.cs @@ -32,6 +32,17 @@ static public void Cleanup() geomEngine = null; logger = null; } + + [TestMethod] + public void Composite_curve_issue_261() + { + using (var model = MemoryModel.OpenRead(@"TestFiles\Composite_curve_issue_261.ifc")) + { + var composite_curve = model.Instances.OfType().FirstOrDefault(); + var wire = geomEngine.CreateWire(composite_curve); + } + } + [TestMethod] public void TestIfFaceIsPlanar() { diff --git a/Xbim.Geometry.Engine.Interop.Tests/Xbim.Geometry.Engine.Interop.Tests.csproj b/Xbim.Geometry.Engine.Interop.Tests/Xbim.Geometry.Engine.Interop.Tests.csproj index 424c19542..90eeb4142 100644 --- a/Xbim.Geometry.Engine.Interop.Tests/Xbim.Geometry.Engine.Interop.Tests.csproj +++ b/Xbim.Geometry.Engine.Interop.Tests/Xbim.Geometry.Engine.Interop.Tests.csproj @@ -54,6 +54,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Xbim.Geometry.Engine/Factories/WireFactory.cpp b/Xbim.Geometry.Engine/Factories/WireFactory.cpp new file mode 100644 index 000000000..9b8bfdc74 --- /dev/null +++ b/Xbim.Geometry.Engine/Factories/WireFactory.cpp @@ -0,0 +1,9 @@ +#include "WireFactory.h" + + +// Builds a wire from a list of contiguous edges, duplicate vertices at nodes are removed +int WireFactory::Make(TopTools_ListOfShape& edgeList, TopoDS_Wire& resultWire) +{ + + return 0; +} diff --git a/Xbim.Geometry.Engine/Factories/WireFactory.h b/Xbim.Geometry.Engine/Factories/WireFactory.h new file mode 100644 index 000000000..508e93694 --- /dev/null +++ b/Xbim.Geometry.Engine/Factories/WireFactory.h @@ -0,0 +1,11 @@ +#pragma once +#include +#include +#include +class WireFactory +{ +public: + // Builds a wire from a list of contiguous edges, duplicate vertices at nodes are removed + static int Make(TopTools_ListOfShape& edgeList, TopoDS_Wire& resultWire); +}; + diff --git a/Xbim.Geometry.Engine/Xbim.Geometry.Engine.vcxproj b/Xbim.Geometry.Engine/Xbim.Geometry.Engine.vcxproj index 8b6854742..013a20fa4 100644 --- a/Xbim.Geometry.Engine/Xbim.Geometry.Engine.vcxproj +++ b/Xbim.Geometry.Engine/Xbim.Geometry.Engine.vcxproj @@ -180,6 +180,7 @@ Create Create + @@ -188,6 +189,7 @@ + diff --git a/Xbim.Geometry.Engine/Xbim.Geometry.Engine.vcxproj.filters b/Xbim.Geometry.Engine/Xbim.Geometry.Engine.vcxproj.filters index 224af5c11..1ae187e8c 100644 --- a/Xbim.Geometry.Engine/Xbim.Geometry.Engine.vcxproj.filters +++ b/Xbim.Geometry.Engine/Xbim.Geometry.Engine.vcxproj.filters @@ -9423,6 +9423,9 @@ Header Files + + Header Files + @@ -15317,6 +15320,9 @@ Source Files + + Source Files + diff --git a/Xbim.Geometry.Engine/XbimWire.cpp b/Xbim.Geometry.Engine/XbimWire.cpp index 6d9378f95..680bd1b50 100644 --- a/Xbim.Geometry.Engine/XbimWire.cpp +++ b/Xbim.Geometry.Engine/XbimWire.cpp @@ -12,7 +12,7 @@ #include #include #include -#include + #include #include #include @@ -129,7 +129,7 @@ namespace Xbim } XbimWire::XbimWire(double precision) { Init(precision); } XbimWire::XbimWire(IIfcCurve^ profile, ILogger^ logger, XbimConstraints constraints) { Init(profile, logger, constraints); } - + XbimWire::XbimWire(IIfcCompositeCurve^ compCurve, ILogger^ logger, XbimConstraints constraints) { Init(compCurve, logger, constraints); } XbimWire::XbimWire(IIfcCompositeCurveSegment^ profile, ILogger^ logger, XbimConstraints constraints) { Init(profile, logger, constraints); }; XbimWire::XbimWire(IIfcPolyline^ profile, ILogger^ logger, XbimConstraints constraints) { Init(profile, logger, constraints); } @@ -408,13 +408,13 @@ namespace Xbim XbimGeometryCreator::LogWarning(logger, pline, "Polyline with less than 2 points is an empty line. It has been ignored"); return; } - + bool done = false; bool tryAgain = true; while (!done) { - + TColgp_SequenceOfPnt pointSeq; BRepBuilderAPI_MakeWire wireMaker; @@ -427,14 +427,14 @@ namespace Xbim bool close = (constraints & XbimConstraints::Closed) == XbimConstraints::Closed; bool notSelfIntersecting = (constraints & XbimConstraints::NotSelfIntersecting) == XbimConstraints::NotSelfIntersecting; bool isClosed = XbimFace::RemoveDuplicatePoints(pointSeq, close, tolerance); - + if (pointSeq.Length() < 2) { XbimGeometryCreator::LogWarning(logger, pline, "Polyline with less than 2 points is an empty line. It has been ignored"); return; } - + BRepBuilderAPI_MakePolygon polyMaker; for (int i = 1; i <= pointSeq.Length(); ++i) @@ -450,7 +450,7 @@ namespace Xbim if (notSelfIntersecting) {//check for no self intersection TopoDS_Wire wire = polyMaker.Wire(); //get a handle to the wire to avoid garbage collection - + //double tolerance = profile->Model->ModelFactors->Precision; Handle(Geom_Plane) planeSurface = new Geom_Plane(gp_Pnt(0, 0, 0), gp_Vec(0, 0, 1)); ShapeAnalysis_Wire wireChecker; @@ -473,11 +473,11 @@ namespace Xbim wireFixer.FixIntersectingEdgesMode() = true; wireFixer.FixNonAdjacentIntersectingEdgesMode() = true; wireFixer.ModifyTopologyMode() = true; - + bool fixed = wireFixer.Perform(); if (!fixed) // we have a self intersection but the tools cannot fix it, normally means two points are too near { - + tolerance = pline->Model->ModelFactors->OneMilliMeter / 10; //use a normal modelling precision @@ -540,7 +540,7 @@ namespace Xbim int pointCount = coordList->Count; TColgp_Array1OfPnt poles(1, pointCount); int n = 1; - for each (IItemSet^ coll in coordList) + for each (IItemSet ^ coll in coordList) { IEnumerator^ enumer = coll->GetEnumerator(); enumer->MoveNext(); @@ -806,7 +806,7 @@ namespace Xbim } } } - + void XbimWire::Init(IIfcCurve^ curve, ILogger^ logger, XbimConstraints constraints) { @@ -842,121 +842,189 @@ namespace Xbim void XbimWire::Init(IIfcCompositeCurve^ cCurve, ILogger^ logger, XbimConstraints constraints) { double tolerance = cCurve->Model->ModelFactors->Precision; - BRepBuilderAPI_MakeWire converter; + //BRepBuilderAPI_MakeWire converter; ShapeFix_ShapeTolerance fTol; double fiveMilli = 5 * cCurve->Model->ModelFactors->OneMilliMeter; //we are going to accept that a gap of 5mm is not a gap - gp_Pnt resultWireFirst; - gp_Pnt resultWireLast; + + bool firstPass = true; bool isContinuous = true; //assume continuous or closed unless last segment is discontinuous int segCount = cCurve->Segments->Count; int segIdx = 1; - - for each (IIfcCompositeCurveSegment ^ seg in cCurve->Segments) //every segment shall be a bounded curve - { - bool lastSeg = (segIdx == segCount); - - if (!dynamic_cast(seg->ParentCurve)) + BRep_Builder builder; + TopoDS_Wire resultWire; + builder.MakeWire(resultWire); + + for each (IIfcCompositeCurveSegment ^ seg in cCurve->Segments) //every segment shall be a bounded curve { - XbimGeometryCreator::LogWarning(logger, seg, "Composite curve contains a segment with is not a bounded curve. It has been ignored"); - return; - } - XbimWire^ segWire = gcnew XbimWire(seg, logger, constraints); + bool lastSeg = (segIdx == segCount); + + if (!dynamic_cast(seg->ParentCurve)) + { + XbimGeometryCreator::LogWarning(logger, seg, "Composite curve contains a segment with is not a bounded curve. It has been ignored"); + continue; + } - if (lastSeg && seg->Transition == IfcTransitionCode::DISCONTINUOUS) isContinuous = false; - if (segWire->IsValid) - { - gp_Pnt segWireFirst = segWire->StartPoint; - gp_Pnt segWireLast = segWire->EndPoint; + if (lastSeg && seg->Transition == IfcTransitionCode::DISCONTINUOUS) isContinuous = false; - if (!firstPass) + XbimWire^ xbimWire = gcnew XbimWire(seg, logger, constraints); + if (xbimWire->IsValid ) { - //simple clockwise end of last wire to start of first - double distFirstToLast = segWireFirst.Distance(resultWireLast); - double distLastToLast = segWireLast.Distance(resultWireLast); - if (!(distFirstToLast <= tolerance || distLastToLast <= tolerance)) + TopoDS_Wire segWire = xbimWire; + for (BRepTools_WireExplorer wireEx(segWire); wireEx.More(); wireEx.Next()) { - //see if the nearest is within 5mm - - if (distFirstToLast <= fiveMilli) + if (firstPass) { - fTol.LimitTolerance(segWire->StartVertex, distFirstToLast + tolerance); + builder.Add(resultWire, TopoDS::Edge(wireEx.Current())); + continue; } - else if (distLastToLast <= fiveMilli) - { - fTol.LimitTolerance(segWire->EndVertex, distLastToLast + tolerance); - } - else // it will not join + else { - //see if we can reverse the segment to fit - double distLastToFirst = segWireLast.Distance(resultWireFirst); - double distFirstToFirst = segWireFirst.Distance(resultWireFirst); - if (distFirstToFirst <= tolerance || distLastToFirst <= tolerance) + TopoDS_Vertex resultWireFirstVertex; + TopoDS_Vertex resultWireLastVertex; + gp_Pnt resultWireFirstPoint; + gp_Pnt resultWireLastPoint; + TopExp::Vertices(resultWire, resultWireFirstVertex, resultWireLastVertex); + if (resultWireFirstVertex.IsNull() || resultWireLastVertex.IsNull()) //this should never happen + { + + XbimGeometryCreator::LogWarning(logger, cCurve, "Failed to build composite curve. It has been ignored"); + return; + } + if (resultWireFirstVertex.IsEqual(resultWireLastVertex)) { - segWire->Reverse(); //just reverse it and add it, it was topologivally incorrect + XbimGeometryCreator::LogWarning(logger, cCurve, "Composite curve is closed. Further segments cannot be added and are ignored"); + pWire = new TopoDS_Wire(); + *pWire = resultWire; + pWire->Closed(true); + fTol.LimitTolerance(*pWire, tolerance); + return; } + resultWireFirstPoint = BRep_Tool::Pnt(resultWireFirstVertex); + resultWireLastPoint = BRep_Tool::Pnt(resultWireLastVertex); + + TopoDS_Edge anEdge = TopoDS::Edge(wireEx.Current()); + TopoDS_Vertex edgeFirstVertex = wireEx.CurrentVertex(); + TopoDS_Vertex edgeLastVertex = TopExp::LastVertex(anEdge, Standard_True); + if (edgeFirstVertex.IsEqual(edgeLastVertex)) //get the next vertex + edgeLastVertex = TopExp::FirstVertex(anEdge, Standard_True); + gp_Pnt edgeFirstPoint = BRep_Tool::Pnt(edgeFirstVertex); + gp_Pnt edgeLastPoint = BRep_Tool::Pnt(edgeLastVertex); + //simple clockwise end of last wire to start of first + double distFirstToLast = edgeFirstPoint.Distance(resultWireLastPoint); + double distLastToLast = edgeLastPoint.Distance(resultWireLastPoint); + if (distFirstToLast <= tolerance) + ModifyWireAddEdge(resultWire, anEdge, edgeFirstVertex, edgeFirstPoint, edgeLastVertex, resultWireLastVertex, resultWireLastPoint, distFirstToLast); + else if (distLastToLast <= tolerance) + ModifyWireAddEdge(resultWire, anEdge, edgeLastVertex, edgeLastPoint, edgeFirstVertex, resultWireLastVertex, resultWireLastPoint, distLastToLast); else { - if (distFirstToFirst <= fiveMilli) - { - fTol.LimitTolerance(segWire->StartVertex, distFirstToFirst + tolerance); - segWire->Reverse(); - } - else if (distLastToFirst <= fiveMilli) - { - fTol.LimitTolerance(segWire->EndVertex, distLastToFirst + tolerance); - segWire->Reverse(); - } - else + //see if the nearest is within 5mm + if (distFirstToLast <= fiveMilli) //its going to join to the first + ModifyWireAddEdge(resultWire, anEdge, edgeFirstVertex, edgeFirstPoint, edgeLastVertex, resultWireLastVertex, resultWireLastPoint, distFirstToLast); + else if (distLastToLast <= fiveMilli) + ModifyWireAddEdge(resultWire, anEdge, edgeLastVertex, edgeLastPoint, edgeFirstVertex, resultWireLastVertex, resultWireLastPoint, distLastToLast); + else // it will not join { + //see if we can reverse the segment to fit + double distLastToFirst = edgeLastPoint.Distance(resultWireFirstPoint); + double distFirstToFirst = edgeFirstPoint.Distance(resultWireFirstPoint); + if (distLastToFirst <= tolerance) + ModifyWireAddEdge(resultWire, anEdge, edgeLastVertex, edgeLastPoint, edgeFirstVertex, resultWireFirstVertex, resultWireFirstPoint, distLastToFirst); + else if (distFirstToFirst <= tolerance) + ModifyWireAddEdge(resultWire, anEdge, edgeFirstVertex, edgeFirstPoint, edgeLastVertex, resultWireFirstVertex, resultWireFirstPoint, distFirstToFirst); + else + { + if (distFirstToFirst <= fiveMilli) + { + anEdge.Reverse(); + ModifyWireAddEdge(resultWire, anEdge, edgeFirstVertex, edgeFirstPoint, edgeLastVertex, resultWireFirstVertex, resultWireFirstPoint, distFirstToFirst); + } + else if (distLastToFirst <= fiveMilli) + { + anEdge.Reverse(); + ModifyWireAddEdge(resultWire, anEdge, edgeLastVertex, edgeLastPoint, edgeFirstVertex, resultWireFirstVertex, resultWireFirstPoint, distLastToFirst); + } + else + { #ifdef _DEBUG - //XbimWire^ currentWire = gcnew XbimWire(converter.Wire()); - + //XbimWire^ currentWire = gcnew XbimWire(resultWire); + //String^ rep = currentWire->ToBRep; #endif // _DEBUG - XbimGeometryCreator::LogWarning(logger, seg, "Unconnected composite curve segment. Curve is incomplete"); - continue; + XbimGeometryCreator::LogWarning(logger, seg, "Unconnected composite curve segment. Curve is incomplete"); + continue; + } + } } } } } + firstPass = false; } - firstPass = false; - bool ok = false; - try - { - converter.Add(segWire); - ok = converter.IsDone(); - if (ok) - { - BRepAdaptor_CompCurve cc(converter.Wire(), Standard_True); - resultWireFirst = cc.Value(cc.FirstParameter()); - resultWireLast = cc.Value(cc.LastParameter()); - } - } - catch (const std::exception&) - { - ok = false; - } - if (!ok) + else { - XbimGeometryCreator::LogWarning(logger, seg, "Failed to join composite curve segment. It has been ignored"); - return; + XbimGeometryCreator::LogWarning(logger, seg, "Invalid edge of a composite curve found. It could not be created"); } + segIdx++; + } + pWire = new TopoDS_Wire(); + *pWire = resultWire; + fTol.LimitTolerance(*pWire, tolerance); + + } + //This is going to be added to to the selected vertex and the tolerances will be adjusted. the duplicate points will be removed + void XbimWire::ModifyWireAddEdge(TopoDS_Wire& resultWire, const TopoDS_Edge& edgeToAdd, const TopoDS_Vertex& edgeVertexToJoin, gp_Pnt edgePointToJoin, const TopoDS_Vertex& + nextEdgeVertex, const TopoDS_Vertex& wireVertexToJoin, gp_Pnt wirePointToJoin, double distance) + { + + TopoDS_Shape emptyEdge = edgeToAdd.EmptyCopied(); + TopoDS_Edge myEdge = TopoDS::Edge(emptyEdge); + BRep_Builder B; + Standard_Real tolE, tolW; + tolW = BRep_Tool::Tolerance(wireVertexToJoin); + tolE = BRep_Tool::Tolerance(edgeVertexToJoin); - } - else - { - XbimGeometryCreator::LogWarning(logger, seg, "Invalid edge of a composite curve found. It could not be created"); - } - segIdx++; + + Standard_Real maxtol = .5 * (tolW + tolE + distance), cW =1, cE=0; + bool adjust = false; + if (maxtol > tolW && maxtol > tolE) + { + cW = (maxtol - tolE) / distance; + cE = 1. - cW; + adjust = true; + } + else if (maxtol > tolW) + { + maxtol = tolE; + cW = 0.; + cE = 1.; + adjust = true; + } + /*else we don't need to do this case as the wore tolerance and position is not changing + { + maxtol = tolW; + cW = 1.; + cE = 0.; + adjust = false; + }*/ + if (adjust) + { + gp_Pnt PC(cW * wirePointToJoin.X() + cE * edgePointToJoin.X(), cW * wirePointToJoin.Y() + cE * edgePointToJoin.Y(), cW * wirePointToJoin.Z() + cE * edgePointToJoin.Z()); + B.UpdateVertex(wireVertexToJoin, PC, maxtol); } - pWire = new TopoDS_Wire(); - *pWire = converter.Wire(); - fTol.LimitTolerance(*pWire, tolerance); - } + TopoDS_Vertex firstEdgeVertex = wireVertexToJoin; + firstEdgeVertex.Orientation(TopAbs_FORWARD); + B.Add(myEdge, firstEdgeVertex); + TopoDS_Vertex nextEdgeVertexCopy = nextEdgeVertex; + nextEdgeVertexCopy.Orientation(TopAbs_REVERSED); + B.Add(myEdge, nextEdgeVertexCopy); + B.Transfert(edgeToAdd, myEdge, edgeVertexToJoin, firstEdgeVertex); + B.Add(resultWire, myEdge); + + } void XbimWire::Init(IIfcPolyLoop^ polyloop, ILogger^ logger, XbimConstraints /*constraints*/) { @@ -2422,7 +2490,7 @@ namespace Xbim Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, fEdge, lEdge); // if first is < lp and last < lp then we need to do both trims on this edge - if (first > fp&& first < lp && last < lp) + if (first > fp && first < lp && last < lp) { gp_Pnt pFirst = cc.Value(first); double uOnEdgeFirst; diff --git a/Xbim.Geometry.Engine/XbimWire.h b/Xbim.Geometry.Engine/XbimWire.h index 9e908eefe..2e0ab78ab 100644 --- a/Xbim.Geometry.Engine/XbimWire.h +++ b/Xbim.Geometry.Engine/XbimWire.h @@ -8,6 +8,7 @@ #include #include #include "XbimConstraints.h" +#include using namespace System; using namespace System::Collections::Generic; @@ -32,6 +33,12 @@ namespace Xbim void set(TopoDS_Wire* val)sealed { ptrContainer = IntPtr(val); } } void InstanceCleanup(); + void ModifyWireAddEdge(TopoDS_Wire& resultWire, + const TopoDS_Edge& EE, + const TopoDS_Vertex& edgeVertexToJoin, gp_Pnt edgePointToJoin, + const TopoDS_Vertex& nextEdgeVertex, + const TopoDS_Vertex& wireVertexToJoin, gp_Pnt wirePointToJoin, + double distance); #pragma region initialisation functions void Init(double precision); From 903b99ea279f908ad5314a01f59f4d30de23c715 Mon Sep 17 00:00:00 2001 From: Stephen Lockley Date: Thu, 30 Apr 2020 15:34:53 +0100 Subject: [PATCH 2/2] Fix for a polyline or composite being the first member of a compoiste curve wire --- Xbim.Geometry.Engine/XbimWire.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Xbim.Geometry.Engine/XbimWire.cpp b/Xbim.Geometry.Engine/XbimWire.cpp index 680bd1b50..8e98bf7be 100644 --- a/Xbim.Geometry.Engine/XbimWire.cpp +++ b/Xbim.Geometry.Engine/XbimWire.cpp @@ -877,6 +877,7 @@ namespace Xbim if (firstPass) { builder.Add(resultWire, TopoDS::Edge(wireEx.Current())); + firstPass = false; continue; } else