From 1d2c578ddd0c15a7f0cd3bd9e33eca8e9417d3b1 Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Tue, 24 Sep 2024 10:51:53 -0400 Subject: [PATCH 01/17] add ALB011 unit test files --- ...-incorrect_radius_parabolic_curve_type.ifc | 273 ++++++++++++++++++ ...ss-correct_radius_parabolic_curve_type.ifc | 273 ++++++++++++++++++ 2 files changed, 546 insertions(+) create mode 100644 test/files/alb011/alb011-fail-incorrect_radius_parabolic_curve_type.ifc create mode 100644 test/files/alb011/alb011-pass-correct_radius_parabolic_curve_type.ifc diff --git a/test/files/alb011/alb011-fail-incorrect_radius_parabolic_curve_type.ifc b/test/files/alb011/alb011-fail-incorrect_radius_parabolic_curve_type.ifc new file mode 100644 index 00000000..706d0d55 --- /dev/null +++ b/test/files/alb011/alb011-fail-incorrect_radius_parabolic_curve_type.ifc @@ -0,0 +1,273 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); +FILE_NAME('alb011-fail-incorrect_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_SCHEMA(('IFC4X3_ADD2')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,'',$,$,$,$,$); +#2=IFCORGANIZATION('redacted','redacted',$,(#18),$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +#4=IFCAPPLICATION(#2,'redacted','redacted','redacted'); +#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,1721342253,#3,#4,1721342253); +#6=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#7=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#8=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#9=IFCUNITASSIGNMENT((#7,#8)); +#10=IFCPROJECT('2NKwV2qd55_Ou$L3sGEcJ5',#5,'Unnamed Bridge Project',$,$,$,$,(#34),#9); +#11=IFCDIRECTION((1.,0.,0.)); +#12=IFCDIRECTION((0.,0.,1.)); +#13=IFCCARTESIANPOINT((0.,0.,0.)); +#14=IFCAXIS2PLACEMENT3D(#13,#12,#11); +#15=IFCLOCALPLACEMENT($,#14); +#16=IFCSITE('1bkdwWptL9p8EOgG7oGLm8',#5,'Site of Unnamed Bridge',$,$,#15,$,$,.ELEMENT.,$,$,$,$,$); +#17=IFCRELAGGREGATES('2OyduV47v3MfrT$j43zMqR',#5,$,$,#10,(#16)); +#18=IFCACTORROLE(.CIVILENGINEER.,$,$); +#19=IFCPROPERTYENUMERATION('PEnum_ProjectType',(IFCLABEL('MODIFICATION'),IFCLABEL('NEWBUILD'),IFCLABEL('OPERATIONMAINTENANCE'),IFCLABEL('RENOVATION'),IFCLABEL('REPAIR')),$); +#20=IFCPROPERTYENUMERATEDVALUE('ProjectType',$,(IFCLABEL('NEWBUILD')),#19); +#21=IFCPROPERTYSET('20vQbRVmnED8iLLqekYzX1',$,'Pset_ProjectCommon',$,(#20)); +#22=IFCRELDEFINESBYPROPERTIES('1U4REvlNHDgv01F5_XE5w9',$,$,$,(#10),#21); +#23=IFCPROPERTYSINGLEVALUE('ContractNumber',$,IFCLABEL('Unknown'),$); +#24=IFCPROPERTYSINGLEVALUE('DesignNumber',$,IFCLABEL('Unknown'),$); +#25=IFCPROPERTYSINGLEVALUE('ProjectNumber',$,IFCLABEL('Unknown'),$); +#26=IFCPROPERTYSINGLEVALUE('ProjectWebsite',$,IFCLABEL('Unknown'),$); +#27=IFCPROPERTYSET('38HZ$LnA18KP01_4uL6vpy',$,'AASHTO_ProjectCommon',$,(#23,#24,#25,#26)); +#28=IFCRELDEFINESBYPROPERTIES('0SVmDQPaH0v993Ve$aV21O',$,$,$,(#10),#27); +#29=IFCDIRECTION((0.,1.)); +#30=IFCDIRECTION((1.,0.,0.)); +#31=IFCDIRECTION((0.,0.,1.)); +#32=IFCCARTESIANPOINT((0.,0.,0.)); +#33=IFCAXIS2PLACEMENT3D(#32,#31,#30); +#34=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#33,#29); +#35=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#34,$,.MODEL_VIEW.,$); +#36=IFCCARTESIANPOINT((152.4,762.)); +#37=IFCALIGNMENTHORIZONTALSEGMENT($,$,#36,5.70829809225671,0.,0.,596.427809947411,$,.LINE.); +#38=IFCALIGNMENTSEGMENT('1yKEFhEET3lxaALz5ILLKJ',$,'H1',$,$,#217,#219,#37); +#39=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#40=IFCAXIS2PLACEMENT2D(#36,#39); +#41=IFCCARTESIANPOINT((0.,0.)); +#42=IFCDIRECTION((1.,0.)); +#43=IFCVECTOR(#42,1.); +#44=IFCLINE(#41,#43); +#45=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#40,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(596.427809947411),#44); +#46=IFCCARTESIANPOINT((652.954206637821,437.698259801391)); +#47=IFCALIGNMENTHORIZONTALSEGMENT($,$,#46,5.70829809225671,304.8,304.8,584.978933611456,$,.CIRCULARARC.); +#48=IFCALIGNMENTSEGMENT('3bkfv7AiX7u8eHZy2v00yU',$,'H2',$,$,#217,#221,#47); +#49=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#50=IFCAXIS2PLACEMENT2D(#46,#49); +#51=IFCCARTESIANPOINT((0.,0.)); +#52=IFCDIRECTION((1.,0.)); +#53=IFCAXIS2PLACEMENT2D(#51,#52); +#54=IFCCIRCLE(#53,304.8); +#55=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#50,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(584.978933611456),#54); +#56=IFCCARTESIANPOINT((1115.70375380811,625.065837937277)); +#57=IFCALIGNMENTHORIZONTALSEGMENT($,$,#56,1.34433500821182,0.,0.,575.126530840636,$,.LINE.); +#58=IFCALIGNMENTSEGMENT('1y1cFxO7DCO8ifhYDB3kg5',$,'H3',$,$,#217,#223,#57); +#59=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#60=IFCAXIS2PLACEMENT2D(#56,#59); +#61=IFCCARTESIANPOINT((0.,0.)); +#62=IFCDIRECTION((1.,0.)); +#63=IFCVECTOR(#62,1.); +#64=IFCLINE(#61,#63); +#65=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#60,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(575.126530840636),#64); +#66=IFCCARTESIANPOINT((1244.83726354192,1185.50768428765)); +#67=IFCALIGNMENTHORIZONTALSEGMENT($,$,#66,1.34433500821182,-381.,-381.,563.305699668461,$,.CIRCULARARC.); +#68=IFCALIGNMENTSEGMENT('2ZhQROlxz9yvU3hgu8kF3y',$,'H4',$,$,#217,#225,#67); +#69=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#70=IFCAXIS2PLACEMENT2D(#66,#69); +#71=IFCCARTESIANPOINT((0.,0.)); +#72=IFCDIRECTION((1.,0.)); +#73=IFCAXIS2PLACEMENT2D(#71,#72); +#74=IFCCIRCLE(#73,381.); +#75=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#70,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-563.305699668461),#74); +#76=IFCCARTESIANPOINT((1667.0700765915,1477.5379910302)); +#77=IFCALIGNMENTHORIZONTALSEGMENT($,$,#76,6.14902766534295,0.,0.,476.89956141461,$,.LINE.); +#78=IFCALIGNMENTSEGMENT('1XuHWXwT969Q35ImfH0Ogg',$,'H5',$,$,#217,#227,#77); +#79=IFCDIRECTION((0.99101435288277,-0.133755569530191)); +#80=IFCAXIS2PLACEMENT2D(#76,#79); +#81=IFCCARTESIANPOINT((0.,0.)); +#82=IFCDIRECTION((1.,0.)); +#83=IFCVECTOR(#82,1.); +#84=IFCLINE(#81,#83); +#85=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#80,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(476.89956141461),#84); +#86=IFCCARTESIANPOINT((2139.68438683688,1413.75001858449)); +#87=IFCALIGNMENTHORIZONTALSEGMENT($,$,#86,6.14902766534296,-289.56,-289.56,319.772021994801,$,.CIRCULARARC.); +#88=IFCALIGNMENTSEGMENT('1WyDRQrLf4Pfa7hc66x7z4',$,'H6',$,$,#217,#229,#87); +#89=IFCDIRECTION((0.99101435288277,-0.13375556953019)); +#90=IFCAXIS2PLACEMENT2D(#86,#89); +#91=IFCCARTESIANPOINT((0.,0.)); +#92=IFCDIRECTION((1.,0.)); +#93=IFCAXIS2PLACEMENT2D(#91,#92); +#94=IFCCIRCLE(#93,289.56); +#95=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#90,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-319.772021994801),#94); +#96=IFCCARTESIANPOINT((2374.67351814968,1221.25187786577)); +#97=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); +#98=IFCALIGNMENTSEGMENT('2Gm5hd_S9FihJigptQqiqo',$,'H7',$,$,#217,#231,#97); +#99=IFCDIRECTION((0.447213595499958,-0.894427190999916)); +#100=IFCAXIS2PLACEMENT2D(#96,#99); +#101=IFCCARTESIANPOINT((0.,0.)); +#102=IFCDIRECTION((1.,0.)); +#103=IFCVECTOR(#102,1.); +#104=IFCLINE(#101,#103); +#105=IFCCURVESEGMENT(.DISCONTINUOUS.,#100,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#104); +#106=IFCALIGNMENTHORIZONTAL('2xHGSjSTHDOuz10zo9imZ$',$,'Horizontal Alignment',$,$,$,$); +#107=IFCRELNESTS('3mBmExvib60u04Ek8FIcUL',$,$,'Nests horizontal alignment segments with horizontal alignment',#106,(#38,#48,#58,#68,#78,#88,#98)); +#108=IFCCOMPOSITECURVE((#45,#55,#65,#75,#85,#95,#105),.F.); +#109=IFCALIGNMENTVERTICALSEGMENT($,$,0.,365.76,30.48,0.0175,0.0175,$,.CONSTANTGRADIENT.); +#110=IFCALIGNMENTSEGMENT('0wiwmz1qT5CguAmO4rZfuD',$,'V1',$,$,#217,#233,#109); +#111=IFCCARTESIANPOINT((0.,30.48)); +#112=IFCDIRECTION((0.999846863274572,0.0175)); +#113=IFCAXIS2PLACEMENT2D(#111,#112); +#114=IFCCARTESIANPOINT((0.,0.)); +#115=IFCDIRECTION((1.,0.)); +#116=IFCVECTOR(#115,1.); +#117=IFCLINE(#114,#116); +#118=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#113,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#117); +#119=IFCALIGNMENTVERTICALSEGMENT($,$,365.76,487.68,36.8808,0.0175,-0.01,100.0,.PARABOLICARC.); +#120=IFCALIGNMENTSEGMENT('0GMpbyK7LAOhZ3MKPhlSDJ',$,'V2',$,$,#217,#235,#119); +#121=IFCCARTESIANPOINT((365.76,36.8808)); +#122=IFCDIRECTION((0.999846863274572,0.0175)); +#123=IFCAXIS2PLACEMENT2D(#121,#122); +#124=IFCCARTESIANPOINT((0.,0.)); +#125=IFCDIRECTION((1.,0.)); +#126=IFCAXIS2PLACEMENT2D(#124,#125); +#127=IFCPOLYNOMIALCURVE(#126,(0.,1.),(36.8808,0.0175,-2.8194717847769E-05),$); +#128=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#123,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.68),#127); +#129=IFCALIGNMENTVERTICALSEGMENT($,$,853.440000000001,487.679999999999,38.7096,-0.01,-0.01,$,.CONSTANTGRADIENT.); +#130=IFCALIGNMENTSEGMENT('3WSKXiwfv2AhAYT1b$NDBj',$,'V3',$,$,#217,#237,#129); +#131=IFCCARTESIANPOINT((853.440000000001,38.7096)); +#132=IFCDIRECTION((0.999949998749938,-0.01)); +#133=IFCAXIS2PLACEMENT2D(#131,#132); +#134=IFCCARTESIANPOINT((0.,0.)); +#135=IFCDIRECTION((1.,0.)); +#136=IFCVECTOR(#135,1.); +#137=IFCLINE(#134,#136); +#138=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#133,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.679999999999),#137); +#139=IFCALIGNMENTVERTICALSEGMENT($,$,1341.12,365.76,33.8328,-0.01,0.02,12192.,.PARABOLICARC.); +#140=IFCALIGNMENTSEGMENT('0f3kcHMir0A9axLpYF$KeL',$,'V4',$,$,#217,#239,#139); +#141=IFCCARTESIANPOINT((1341.12,33.8328)); +#142=IFCDIRECTION((0.999949998749938,-0.01)); +#143=IFCAXIS2PLACEMENT2D(#141,#142); +#144=IFCCARTESIANPOINT((0.,0.)); +#145=IFCDIRECTION((1.,0.)); +#146=IFCAXIS2PLACEMENT2D(#144,#145); +#147=IFCPOLYNOMIALCURVE(#146,(0.,1.),(33.8328,-0.01,4.1010498687664E-05),$); +#148=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#143,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#147); +#149=IFCALIGNMENTVERTICALSEGMENT($,$,1706.88,243.84,35.6616,0.02,0.02,$,.CONSTANTGRADIENT.); +#150=IFCALIGNMENTSEGMENT('1oYMRqw$r2aO6hIvJEhzgO',$,'V5',$,$,#217,#241,#149); +#151=IFCCARTESIANPOINT((1706.88,35.6616)); +#152=IFCDIRECTION((0.999799979995999,0.02)); +#153=IFCAXIS2PLACEMENT2D(#151,#152); +#154=IFCCARTESIANPOINT((0.,0.)); +#155=IFCDIRECTION((1.,0.)); +#156=IFCVECTOR(#155,1.); +#157=IFCLINE(#154,#156); +#158=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#153,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#157); +#159=IFCALIGNMENTVERTICALSEGMENT($,$,1950.72,609.6,40.5384,0.02,-0.02,-15240.,.PARABOLICARC.); +#160=IFCALIGNMENTSEGMENT('2rmRh3RID4Dx1Xv2vdnAcV',$,'V6',$,$,#217,#243,#159); +#161=IFCCARTESIANPOINT((1950.72,40.5384)); +#162=IFCDIRECTION((0.999799979995999,0.02)); +#163=IFCAXIS2PLACEMENT2D(#161,#162); +#164=IFCCARTESIANPOINT((0.,0.)); +#165=IFCDIRECTION((1.,0.)); +#166=IFCAXIS2PLACEMENT2D(#164,#165); +#167=IFCPOLYNOMIALCURVE(#166,(0.,1.),(40.5384,0.02,-3.28083989501312E-05),$); +#168=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#163,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(609.6),#167); +#169=IFCALIGNMENTVERTICALSEGMENT($,$,2560.32,304.799999999999,40.5384,-0.02,-0.02,$,.CONSTANTGRADIENT.); +#170=IFCALIGNMENTSEGMENT('2kGQnCzmbB1hLZpc8B8fx7',$,'V7',$,$,#217,#245,#169); +#171=IFCCARTESIANPOINT((2560.32,40.5384)); +#172=IFCDIRECTION((0.999799979995999,-0.02)); +#173=IFCAXIS2PLACEMENT2D(#171,#172); +#174=IFCCARTESIANPOINT((0.,0.)); +#175=IFCDIRECTION((1.,0.)); +#176=IFCVECTOR(#175,1.); +#177=IFCLINE(#174,#176); +#178=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#173,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(304.799999999999),#177); +#179=IFCALIGNMENTVERTICALSEGMENT($,$,2865.12,243.84,34.4424,-0.02,-0.005,16256.,.PARABOLICARC.); +#180=IFCALIGNMENTSEGMENT('3hljyR0Hr0$hbnPws3P554',$,'V8',$,$,#217,#247,#179); +#181=IFCCARTESIANPOINT((2865.12,34.4424)); +#182=IFCDIRECTION((0.999799979995999,-0.02)); +#183=IFCAXIS2PLACEMENT2D(#181,#182); +#184=IFCCARTESIANPOINT((0.,0.)); +#185=IFCDIRECTION((1.,0.)); +#186=IFCAXIS2PLACEMENT2D(#184,#185); +#187=IFCPOLYNOMIALCURVE(#186,(0.,1.),(34.4424,-0.02,3.0757874015748E-05),$); +#188=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#183,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#187); +#189=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,7.55055747737515,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.); +#190=IFCALIGNMENTSEGMENT('0Yj$$A801BgAySuKuq8FH1',$,'V9',$,$,#217,#249,#189); +#191=IFCCARTESIANPOINT((3108.96,31.3944)); +#192=IFCDIRECTION((0.999987499921874,-0.005)); +#193=IFCAXIS2PLACEMENT2D(#191,#192); +#194=IFCCARTESIANPOINT((0.,0.)); +#195=IFCDIRECTION((1.,0.)); +#196=IFCVECTOR(#195,1.); +#197=IFCLINE(#194,#196); +#198=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#193,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(7.55055747737515),#197); +#199=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,0.,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.); +#200=IFCALIGNMENTSEGMENT('0FSjBm0hj8PwKhufHaF1ZA',$,'V10',$,$,#217,#251,#199); +#201=IFCCARTESIANPOINT((3108.96,31.3944)); +#202=IFCDIRECTION((0.999987499921874,-0.005)); +#203=IFCAXIS2PLACEMENT2D(#201,#202); +#204=IFCCARTESIANPOINT((0.,0.)); +#205=IFCDIRECTION((1.,0.)); +#206=IFCVECTOR(#205,1.); +#207=IFCLINE(#204,#206); +#208=IFCCURVESEGMENT(.DISCONTINUOUS.,#203,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#207); +#209=IFCALIGNMENTVERTICAL('2nEoeLO$jCAgLWqX3ZS4ZL',$,'Vertical Alignment',$,$,#15,$); +#210=IFCRELNESTS('1Zi6YpAun30A67NCfsmR6h',$,$,'Nests vertical alignment segments with vertical alignment',#209,(#110,#120,#130,#140,#150,#160,#170,#180,#190,#200)); +#211=IFCGRADIENTCURVE((#118,#128,#138,#148,#158,#168,#178,#188,#198,#208),.F.,#108,$); +#212=IFCSHAPEREPRESENTATION(#35,'Axis','Curve3D',(#211)); +#213=IFCDIRECTION((1.,0.,0.)); +#214=IFCDIRECTION((0.,0.,1.)); +#215=IFCCARTESIANPOINT((0.,0.,0.)); +#216=IFCAXIS2PLACEMENT3D(#215,#214,#213); +#217=IFCLOCALPLACEMENT($,#216); +#218=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#45)); +#219=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#218)); +#220=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#55)); +#221=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#220)); +#222=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#65)); +#223=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#222)); +#224=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#75)); +#225=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#224)); +#226=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#85)); +#227=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#226)); +#228=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#95)); +#229=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#228)); +#230=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#105)); +#231=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#230)); +#232=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#118)); +#233=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#232)); +#234=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#128)); +#235=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#234)); +#236=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#138)); +#237=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#236)); +#238=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#148)); +#239=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#238)); +#240=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#158)); +#241=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#240)); +#242=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#168)); +#243=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#242)); +#244=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#178)); +#245=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#244)); +#246=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#188)); +#247=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#246)); +#248=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#198)); +#249=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#248)); +#250=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#208)); +#251=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#250)); +#252=IFCPRODUCTDEFINITIONSHAPE('Alignment Product Definition Shape',$,(#212)); +#253=IFCALIGNMENT('0qKahqjPjBeuEjpOKkk23s',$,'Unnamed alignment',$,$,#15,#252,$); +#254=IFCRELNESTS('3p2wDzu0r4qBoQ$kirOpI9',$,'Nest horizontal and vertical alignment layouts with the alignment',$,#253,(#106,#209)); +#255=IFCRELAGGREGATES('1K9FW2VIP3Uf303$idpLPY',$,'Alignments in project',$,#10,(#253)); +#256=IFCRELREFERENCEDINSPATIALSTRUCTURE('10jns2II51eA4MvJstMUh6',$,$,$,(#253),#16); +#257=IFCPROPERTYSINGLEVALUE('Station',$,IFCLENGTHMEASURE(3048.),$); +#258=IFCPROPERTYSET('0ykDGVR8D9JvgG2BE$m9Y0',$,'Pset_Stationing',$,(#257)); +#259=IFCPOINTBYDISTANCEEXPRESSION(IFCLENGTHMEASURE(0.),$,$,$,#211); +#260=IFCAXIS2PLACEMENTLINEAR(#259,$,$); +#261=IFCLINEARPLACEMENT($,#260,$); +#262=IFCREFERENT('2MIQXRsdHE1ehEM_GIWxfu',$,'Start of alignment station',$,$,#261,$,.STATION.); +#263=IFCRELNESTS('0UMvxWgzT2mO2ObhWRe5TZ',$,'Nests Referents with station information with alignment',$,#253,(#262)); +#264=IFCRELDEFINESBYPROPERTIES('3SkNbYBX97uBNi5kNrE0qi',$,'Relates station properties to referent',$,(#262),#258); +ENDSEC; +END-ISO-10303-21; diff --git a/test/files/alb011/alb011-pass-correct_radius_parabolic_curve_type.ifc b/test/files/alb011/alb011-pass-correct_radius_parabolic_curve_type.ifc new file mode 100644 index 00000000..b4e55c5c --- /dev/null +++ b/test/files/alb011/alb011-pass-correct_radius_parabolic_curve_type.ifc @@ -0,0 +1,273 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); +FILE_NAME('alb011-pass-correct_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_SCHEMA(('IFC4X3_ADD2')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,'',$,$,$,$,$); +#2=IFCORGANIZATION('redacted','redacted',$,(#18),$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +#4=IFCAPPLICATION(#2,'redacted','redacted','redacted'); +#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,1721342253,#3,#4,1721342253); +#6=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#7=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#8=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#9=IFCUNITASSIGNMENT((#7,#8)); +#10=IFCPROJECT('2NKwV2qd55_Ou$L3sGEcJ5',#5,'Unnamed Bridge Project',$,$,$,$,(#34),#9); +#11=IFCDIRECTION((1.,0.,0.)); +#12=IFCDIRECTION((0.,0.,1.)); +#13=IFCCARTESIANPOINT((0.,0.,0.)); +#14=IFCAXIS2PLACEMENT3D(#13,#12,#11); +#15=IFCLOCALPLACEMENT($,#14); +#16=IFCSITE('1bkdwWptL9p8EOgG7oGLm8',#5,'Site of Unnamed Bridge',$,$,#15,$,$,.ELEMENT.,$,$,$,$,$); +#17=IFCRELAGGREGATES('2OyduV47v3MfrT$j43zMqR',#5,$,$,#10,(#16)); +#18=IFCACTORROLE(.CIVILENGINEER.,$,$); +#19=IFCPROPERTYENUMERATION('PEnum_ProjectType',(IFCLABEL('MODIFICATION'),IFCLABEL('NEWBUILD'),IFCLABEL('OPERATIONMAINTENANCE'),IFCLABEL('RENOVATION'),IFCLABEL('REPAIR')),$); +#20=IFCPROPERTYENUMERATEDVALUE('ProjectType',$,(IFCLABEL('NEWBUILD')),#19); +#21=IFCPROPERTYSET('20vQbRVmnED8iLLqekYzX1',$,'Pset_ProjectCommon',$,(#20)); +#22=IFCRELDEFINESBYPROPERTIES('1U4REvlNHDgv01F5_XE5w9',$,$,$,(#10),#21); +#23=IFCPROPERTYSINGLEVALUE('ContractNumber',$,IFCLABEL('Unknown'),$); +#24=IFCPROPERTYSINGLEVALUE('DesignNumber',$,IFCLABEL('Unknown'),$); +#25=IFCPROPERTYSINGLEVALUE('ProjectNumber',$,IFCLABEL('Unknown'),$); +#26=IFCPROPERTYSINGLEVALUE('ProjectWebsite',$,IFCLABEL('Unknown'),$); +#27=IFCPROPERTYSET('38HZ$LnA18KP01_4uL6vpy',$,'AASHTO_ProjectCommon',$,(#23,#24,#25,#26)); +#28=IFCRELDEFINESBYPROPERTIES('0SVmDQPaH0v993Ve$aV21O',$,$,$,(#10),#27); +#29=IFCDIRECTION((0.,1.)); +#30=IFCDIRECTION((1.,0.,0.)); +#31=IFCDIRECTION((0.,0.,1.)); +#32=IFCCARTESIANPOINT((0.,0.,0.)); +#33=IFCAXIS2PLACEMENT3D(#32,#31,#30); +#34=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#33,#29); +#35=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#34,$,.MODEL_VIEW.,$); +#36=IFCCARTESIANPOINT((152.4,762.)); +#37=IFCALIGNMENTHORIZONTALSEGMENT($,$,#36,5.70829809225671,0.,0.,596.427809947411,$,.LINE.); +#38=IFCALIGNMENTSEGMENT('1yKEFhEET3lxaALz5ILLKJ',$,'H1',$,$,#217,#219,#37); +#39=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#40=IFCAXIS2PLACEMENT2D(#36,#39); +#41=IFCCARTESIANPOINT((0.,0.)); +#42=IFCDIRECTION((1.,0.)); +#43=IFCVECTOR(#42,1.); +#44=IFCLINE(#41,#43); +#45=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#40,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(596.427809947411),#44); +#46=IFCCARTESIANPOINT((652.954206637821,437.698259801391)); +#47=IFCALIGNMENTHORIZONTALSEGMENT($,$,#46,5.70829809225671,304.8,304.8,584.978933611456,$,.CIRCULARARC.); +#48=IFCALIGNMENTSEGMENT('3bkfv7AiX7u8eHZy2v00yU',$,'H2',$,$,#217,#221,#47); +#49=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#50=IFCAXIS2PLACEMENT2D(#46,#49); +#51=IFCCARTESIANPOINT((0.,0.)); +#52=IFCDIRECTION((1.,0.)); +#53=IFCAXIS2PLACEMENT2D(#51,#52); +#54=IFCCIRCLE(#53,304.8); +#55=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#50,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(584.978933611456),#54); +#56=IFCCARTESIANPOINT((1115.70375380811,625.065837937277)); +#57=IFCALIGNMENTHORIZONTALSEGMENT($,$,#56,1.34433500821182,0.,0.,575.126530840636,$,.LINE.); +#58=IFCALIGNMENTSEGMENT('1y1cFxO7DCO8ifhYDB3kg5',$,'H3',$,$,#217,#223,#57); +#59=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#60=IFCAXIS2PLACEMENT2D(#56,#59); +#61=IFCCARTESIANPOINT((0.,0.)); +#62=IFCDIRECTION((1.,0.)); +#63=IFCVECTOR(#62,1.); +#64=IFCLINE(#61,#63); +#65=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#60,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(575.126530840636),#64); +#66=IFCCARTESIANPOINT((1244.83726354192,1185.50768428765)); +#67=IFCALIGNMENTHORIZONTALSEGMENT($,$,#66,1.34433500821182,-381.,-381.,563.305699668461,$,.CIRCULARARC.); +#68=IFCALIGNMENTSEGMENT('2ZhQROlxz9yvU3hgu8kF3y',$,'H4',$,$,#217,#225,#67); +#69=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#70=IFCAXIS2PLACEMENT2D(#66,#69); +#71=IFCCARTESIANPOINT((0.,0.)); +#72=IFCDIRECTION((1.,0.)); +#73=IFCAXIS2PLACEMENT2D(#71,#72); +#74=IFCCIRCLE(#73,381.); +#75=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#70,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-563.305699668461),#74); +#76=IFCCARTESIANPOINT((1667.0700765915,1477.5379910302)); +#77=IFCALIGNMENTHORIZONTALSEGMENT($,$,#76,6.14902766534295,0.,0.,476.89956141461,$,.LINE.); +#78=IFCALIGNMENTSEGMENT('1XuHWXwT969Q35ImfH0Ogg',$,'H5',$,$,#217,#227,#77); +#79=IFCDIRECTION((0.99101435288277,-0.133755569530191)); +#80=IFCAXIS2PLACEMENT2D(#76,#79); +#81=IFCCARTESIANPOINT((0.,0.)); +#82=IFCDIRECTION((1.,0.)); +#83=IFCVECTOR(#82,1.); +#84=IFCLINE(#81,#83); +#85=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#80,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(476.89956141461),#84); +#86=IFCCARTESIANPOINT((2139.68438683688,1413.75001858449)); +#87=IFCALIGNMENTHORIZONTALSEGMENT($,$,#86,6.14902766534296,-289.56,-289.56,319.772021994801,$,.CIRCULARARC.); +#88=IFCALIGNMENTSEGMENT('1WyDRQrLf4Pfa7hc66x7z4',$,'H6',$,$,#217,#229,#87); +#89=IFCDIRECTION((0.99101435288277,-0.13375556953019)); +#90=IFCAXIS2PLACEMENT2D(#86,#89); +#91=IFCCARTESIANPOINT((0.,0.)); +#92=IFCDIRECTION((1.,0.)); +#93=IFCAXIS2PLACEMENT2D(#91,#92); +#94=IFCCIRCLE(#93,289.56); +#95=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#90,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-319.772021994801),#94); +#96=IFCCARTESIANPOINT((2374.67351814968,1221.25187786577)); +#97=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); +#98=IFCALIGNMENTSEGMENT('2Gm5hd_S9FihJigptQqiqo',$,'H7',$,$,#217,#231,#97); +#99=IFCDIRECTION((0.447213595499958,-0.894427190999916)); +#100=IFCAXIS2PLACEMENT2D(#96,#99); +#101=IFCCARTESIANPOINT((0.,0.)); +#102=IFCDIRECTION((1.,0.)); +#103=IFCVECTOR(#102,1.); +#104=IFCLINE(#101,#103); +#105=IFCCURVESEGMENT(.DISCONTINUOUS.,#100,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#104); +#106=IFCALIGNMENTHORIZONTAL('2xHGSjSTHDOuz10zo9imZ$',$,'Horizontal Alignment',$,$,$,$); +#107=IFCRELNESTS('3mBmExvib60u04Ek8FIcUL',$,$,'Nests horizontal alignment segments with horizontal alignment',#106,(#38,#48,#58,#68,#78,#88,#98)); +#108=IFCCOMPOSITECURVE((#45,#55,#65,#75,#85,#95,#105),.F.); +#109=IFCALIGNMENTVERTICALSEGMENT($,$,0.,365.76,30.48,0.0175,0.0175,$,.CONSTANTGRADIENT.); +#110=IFCALIGNMENTSEGMENT('0wiwmz1qT5CguAmO4rZfuD',$,'V1',$,$,#217,#233,#109); +#111=IFCCARTESIANPOINT((0.,30.48)); +#112=IFCDIRECTION((0.999846863274572,0.0175)); +#113=IFCAXIS2PLACEMENT2D(#111,#112); +#114=IFCCARTESIANPOINT((0.,0.)); +#115=IFCDIRECTION((1.,0.)); +#116=IFCVECTOR(#115,1.); +#117=IFCLINE(#114,#116); +#118=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#113,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#117); +#119=IFCALIGNMENTVERTICALSEGMENT($,$,365.76,487.68,36.8808,0.0175,-0.01,-17733.81818,.PARABOLICARC.); +#120=IFCALIGNMENTSEGMENT('0GMpbyK7LAOhZ3MKPhlSDJ',$,'V2',$,$,#217,#235,#119); +#121=IFCCARTESIANPOINT((365.76,36.8808)); +#122=IFCDIRECTION((0.999846863274572,0.0175)); +#123=IFCAXIS2PLACEMENT2D(#121,#122); +#124=IFCCARTESIANPOINT((0.,0.)); +#125=IFCDIRECTION((1.,0.)); +#126=IFCAXIS2PLACEMENT2D(#124,#125); +#127=IFCPOLYNOMIALCURVE(#126,(0.,1.),(36.8808,0.0175,-2.8194717847769E-05),$); +#128=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#123,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.68),#127); +#129=IFCALIGNMENTVERTICALSEGMENT($,$,853.440000000001,487.679999999999,38.7096,-0.01,-0.01,$,.CONSTANTGRADIENT.); +#130=IFCALIGNMENTSEGMENT('3WSKXiwfv2AhAYT1b$NDBj',$,'V3',$,$,#217,#237,#129); +#131=IFCCARTESIANPOINT((853.440000000001,38.7096)); +#132=IFCDIRECTION((0.999949998749938,-0.01)); +#133=IFCAXIS2PLACEMENT2D(#131,#132); +#134=IFCCARTESIANPOINT((0.,0.)); +#135=IFCDIRECTION((1.,0.)); +#136=IFCVECTOR(#135,1.); +#137=IFCLINE(#134,#136); +#138=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#133,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.679999999999),#137); +#139=IFCALIGNMENTVERTICALSEGMENT($,$,1341.12,365.76,33.8328,-0.01,0.02,12192.,.PARABOLICARC.); +#140=IFCALIGNMENTSEGMENT('0f3kcHMir0A9axLpYF$KeL',$,'V4',$,$,#217,#239,#139); +#141=IFCCARTESIANPOINT((1341.12,33.8328)); +#142=IFCDIRECTION((0.999949998749938,-0.01)); +#143=IFCAXIS2PLACEMENT2D(#141,#142); +#144=IFCCARTESIANPOINT((0.,0.)); +#145=IFCDIRECTION((1.,0.)); +#146=IFCAXIS2PLACEMENT2D(#144,#145); +#147=IFCPOLYNOMIALCURVE(#146,(0.,1.),(33.8328,-0.01,4.1010498687664E-05),$); +#148=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#143,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#147); +#149=IFCALIGNMENTVERTICALSEGMENT($,$,1706.88,243.84,35.6616,0.02,0.02,$,.CONSTANTGRADIENT.); +#150=IFCALIGNMENTSEGMENT('1oYMRqw$r2aO6hIvJEhzgO',$,'V5',$,$,#217,#241,#149); +#151=IFCCARTESIANPOINT((1706.88,35.6616)); +#152=IFCDIRECTION((0.999799979995999,0.02)); +#153=IFCAXIS2PLACEMENT2D(#151,#152); +#154=IFCCARTESIANPOINT((0.,0.)); +#155=IFCDIRECTION((1.,0.)); +#156=IFCVECTOR(#155,1.); +#157=IFCLINE(#154,#156); +#158=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#153,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#157); +#159=IFCALIGNMENTVERTICALSEGMENT($,$,1950.72,609.6,40.5384,0.02,-0.02,-15240.,.PARABOLICARC.); +#160=IFCALIGNMENTSEGMENT('2rmRh3RID4Dx1Xv2vdnAcV',$,'V6',$,$,#217,#243,#159); +#161=IFCCARTESIANPOINT((1950.72,40.5384)); +#162=IFCDIRECTION((0.999799979995999,0.02)); +#163=IFCAXIS2PLACEMENT2D(#161,#162); +#164=IFCCARTESIANPOINT((0.,0.)); +#165=IFCDIRECTION((1.,0.)); +#166=IFCAXIS2PLACEMENT2D(#164,#165); +#167=IFCPOLYNOMIALCURVE(#166,(0.,1.),(40.5384,0.02,-3.28083989501312E-05),$); +#168=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#163,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(609.6),#167); +#169=IFCALIGNMENTVERTICALSEGMENT($,$,2560.32,304.799999999999,40.5384,-0.02,-0.02,$,.CONSTANTGRADIENT.); +#170=IFCALIGNMENTSEGMENT('2kGQnCzmbB1hLZpc8B8fx7',$,'V7',$,$,#217,#245,#169); +#171=IFCCARTESIANPOINT((2560.32,40.5384)); +#172=IFCDIRECTION((0.999799979995999,-0.02)); +#173=IFCAXIS2PLACEMENT2D(#171,#172); +#174=IFCCARTESIANPOINT((0.,0.)); +#175=IFCDIRECTION((1.,0.)); +#176=IFCVECTOR(#175,1.); +#177=IFCLINE(#174,#176); +#178=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#173,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(304.799999999999),#177); +#179=IFCALIGNMENTVERTICALSEGMENT($,$,2865.12,243.84,34.4424,-0.02,-0.005,16256.,.PARABOLICARC.); +#180=IFCALIGNMENTSEGMENT('3hljyR0Hr0$hbnPws3P554',$,'V8',$,$,#217,#247,#179); +#181=IFCCARTESIANPOINT((2865.12,34.4424)); +#182=IFCDIRECTION((0.999799979995999,-0.02)); +#183=IFCAXIS2PLACEMENT2D(#181,#182); +#184=IFCCARTESIANPOINT((0.,0.)); +#185=IFCDIRECTION((1.,0.)); +#186=IFCAXIS2PLACEMENT2D(#184,#185); +#187=IFCPOLYNOMIALCURVE(#186,(0.,1.),(34.4424,-0.02,3.0757874015748E-05),$); +#188=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#183,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#187); +#189=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,7.55055747737515,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.); +#190=IFCALIGNMENTSEGMENT('0Yj$$A801BgAySuKuq8FH1',$,'V9',$,$,#217,#249,#189); +#191=IFCCARTESIANPOINT((3108.96,31.3944)); +#192=IFCDIRECTION((0.999987499921874,-0.005)); +#193=IFCAXIS2PLACEMENT2D(#191,#192); +#194=IFCCARTESIANPOINT((0.,0.)); +#195=IFCDIRECTION((1.,0.)); +#196=IFCVECTOR(#195,1.); +#197=IFCLINE(#194,#196); +#198=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#193,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(7.55055747737515),#197); +#199=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,0.,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.); +#200=IFCALIGNMENTSEGMENT('0FSjBm0hj8PwKhufHaF1ZA',$,'V10',$,$,#217,#251,#199); +#201=IFCCARTESIANPOINT((3108.96,31.3944)); +#202=IFCDIRECTION((0.999987499921874,-0.005)); +#203=IFCAXIS2PLACEMENT2D(#201,#202); +#204=IFCCARTESIANPOINT((0.,0.)); +#205=IFCDIRECTION((1.,0.)); +#206=IFCVECTOR(#205,1.); +#207=IFCLINE(#204,#206); +#208=IFCCURVESEGMENT(.DISCONTINUOUS.,#203,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#207); +#209=IFCALIGNMENTVERTICAL('2nEoeLO$jCAgLWqX3ZS4ZL',$,'Vertical Alignment',$,$,#15,$); +#210=IFCRELNESTS('1Zi6YpAun30A67NCfsmR6h',$,$,'Nests vertical alignment segments with vertical alignment',#209,(#110,#120,#130,#140,#150,#160,#170,#180,#190,#200)); +#211=IFCGRADIENTCURVE((#118,#128,#138,#148,#158,#168,#178,#188,#198,#208),.F.,#108,$); +#212=IFCSHAPEREPRESENTATION(#35,'Axis','Curve3D',(#211)); +#213=IFCDIRECTION((1.,0.,0.)); +#214=IFCDIRECTION((0.,0.,1.)); +#215=IFCCARTESIANPOINT((0.,0.,0.)); +#216=IFCAXIS2PLACEMENT3D(#215,#214,#213); +#217=IFCLOCALPLACEMENT($,#216); +#218=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#45)); +#219=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#218)); +#220=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#55)); +#221=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#220)); +#222=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#65)); +#223=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#222)); +#224=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#75)); +#225=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#224)); +#226=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#85)); +#227=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#226)); +#228=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#95)); +#229=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#228)); +#230=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#105)); +#231=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#230)); +#232=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#118)); +#233=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#232)); +#234=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#128)); +#235=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#234)); +#236=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#138)); +#237=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#236)); +#238=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#148)); +#239=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#238)); +#240=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#158)); +#241=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#240)); +#242=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#168)); +#243=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#242)); +#244=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#178)); +#245=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#244)); +#246=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#188)); +#247=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#246)); +#248=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#198)); +#249=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#248)); +#250=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#208)); +#251=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#250)); +#252=IFCPRODUCTDEFINITIONSHAPE('Alignment Product Definition Shape',$,(#212)); +#253=IFCALIGNMENT('0qKahqjPjBeuEjpOKkk23s',$,'Unnamed alignment',$,$,#15,#252,$); +#254=IFCRELNESTS('3p2wDzu0r4qBoQ$kirOpI9',$,'Nest horizontal and vertical alignment layouts with the alignment',$,#253,(#106,#209)); +#255=IFCRELAGGREGATES('1K9FW2VIP3Uf303$idpLPY',$,'Alignments in project',$,#10,(#253)); +#256=IFCRELREFERENCEDINSPATIALSTRUCTURE('10jns2II51eA4MvJstMUh6',$,$,$,(#253),#16); +#257=IFCPROPERTYSINGLEVALUE('Station',$,IFCLENGTHMEASURE(3048.),$); +#258=IFCPROPERTYSET('0ykDGVR8D9JvgG2BE$m9Y0',$,'Pset_Stationing',$,(#257)); +#259=IFCPOINTBYDISTANCEEXPRESSION(IFCLENGTHMEASURE(0.),$,$,$,#211); +#260=IFCAXIS2PLACEMENTLINEAR(#259,$,$); +#261=IFCLINEARPLACEMENT($,#260,$); +#262=IFCREFERENT('2MIQXRsdHE1ehEM_GIWxfu',$,'Start of alignment station',$,$,#261,$,.STATION.); +#263=IFCRELNESTS('0UMvxWgzT2mO2ObhWRe5TZ',$,'Nests Referents with station information with alignment',$,#253,(#262)); +#264=IFCRELDEFINESBYPROPERTIES('3SkNbYBX97uBNi5kNrE0qi',$,'Relates station properties to referent',$,(#262),#258); +ENDSEC; +END-ISO-10303-21; From 9bd31c83cd4bd4d13feeec0ec092314c79c8d6cd Mon Sep 17 00:00:00 2001 From: fg55b Date: Fri, 27 Sep 2024 00:12:22 -0300 Subject: [PATCH 02/17] feat/first commit of ALB011 --- ...rtical-segment-radius-of-curvature.feature | 19 ++++++ features/steps/thens/attributes.py | 60 +++++++++++++++++++ ...incorrect_radius_parabolic_curve_type.ifc} | 0 ...1-correct_radius_parabolic_curve_type.ifc} | 0 4 files changed, 79 insertions(+) create mode 100644 features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature rename test/files/alb011/{alb011-fail-incorrect_radius_parabolic_curve_type.ifc => fail-alb011-incorrect_radius_parabolic_curve_type.ifc} (100%) rename test/files/alb011/{alb011-pass-correct_radius_parabolic_curve_type.ifc => pass-alb011-correct_radius_parabolic_curve_type.ifc} (100%) diff --git a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature new file mode 100644 index 00000000..4ac1f20f --- /dev/null +++ b/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature @@ -0,0 +1,19 @@ +@implementer-agreement +@ALB +@version1 +@E00020 +Feature: ALB011 - Alignment vertical segment radius of curvature + The rule verifies if the curvature radius is provided in the correct predefined types and evaluates + its congruence with the start point gradient, the end point gradient, and the horizontal length of the segment. + + Background: + Given A model with Schema "IFC4.3" + Given An IfcAlignmentVerticalSegment + + Scenario: Validating the radius of curvature of vertical segment + Given PredefinedType != 'CIRCULARARC' or 'PARABOLICARC' + Then The value of attribute RadiusOfCurvature must be empty + + Scenario: Validating the radius of curvature value of vertical segment + Given PredefinedType = 'CIRCULARARC' or 'PARABOLICARC' + Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) \ No newline at end of file diff --git a/features/steps/thens/attributes.py b/features/steps/thens/attributes.py index 6d2b5b11..dcfdd57d 100644 --- a/features/steps/thens/attributes.py +++ b/features/steps/thens/attributes.py @@ -127,3 +127,63 @@ def step_impl(context, inst, segment_type, length_attribute): raise ValueError(f"Invalid segment_type '{segment_type}'.") +@gherkin_ifc.step('{attribute_compared} value must be {comparison_op} the expression: {expression}') +def step_impl(context, inst, attribute_compared:str, comparison_op:str, expression:str): + ''' + Compare a attribute to a expression based on attributes. + + The {comparison_op} operator can be 'equal to', 'not equal to', 'greater than', 'less than', 'greater than or equal to', and 'less than or equal to'. + + The {expression} should be composed by attribute values, and use the following operators: + + : addition; + - : subtraction; + * : multiplication; + / : division; + % : modulus; + ** : exponentiation.''' + + operators = { + '+' : operator.add, + '-' : operator.sub, + '*' : operator.mul, + '/' : operator.truediv, + '%' : operator.mod, + '^' : operator.pow, + 'equal to' : operator.eq, + 'not equal to' : operator.ne, + 'greater than' : operator.gt, + 'less than' : operator.gt, + 'greater than or equal to' : operator.ge, + 'less than or equal to' : operator.le, + } + + # Get compared attribute value + attr_compared_value = getattr(inst, attribute_compared, 'Attribute not found') + + # Replace attribute names with attribute values in the expression + for string in expression.split(): + # Checks if the string is not a operator neither parenthesis + if string not in [*operators, '(', ')']: + if hasattr(inst, string): + expression = expression.replace(string, str(getattr(inst, string))) + else: + raise Exception('Attribute not found') + + # Evaluate the string expression using eval + try: + expression_value = eval(expression) + except Exception as e: + raise ValueError(f"Error evaluating expression: {e}") + + print(attr_compared_value) + print(expression_value) + print() + + # Compare the attribute with the expression value + comparison_func = operators.get(comparison_op) + if comparison_func: + result = comparison_func(attr_compared_value, expression_value) + if not result: + yield ValidationOutcome(inst=inst, severity=OutcomeSeverity.ERROR) + else: + raise ValueError(f"Invalid comparison operator: {comparison_op}") \ No newline at end of file diff --git a/test/files/alb011/alb011-fail-incorrect_radius_parabolic_curve_type.ifc b/test/files/alb011/fail-alb011-incorrect_radius_parabolic_curve_type.ifc similarity index 100% rename from test/files/alb011/alb011-fail-incorrect_radius_parabolic_curve_type.ifc rename to test/files/alb011/fail-alb011-incorrect_radius_parabolic_curve_type.ifc diff --git a/test/files/alb011/alb011-pass-correct_radius_parabolic_curve_type.ifc b/test/files/alb011/pass-alb011-correct_radius_parabolic_curve_type.ifc similarity index 100% rename from test/files/alb011/alb011-pass-correct_radius_parabolic_curve_type.ifc rename to test/files/alb011/pass-alb011-correct_radius_parabolic_curve_type.ifc From bc9c3e8c16aaf5079683ebbbb6155ca4405d94e5 Mon Sep 17 00:00:00 2001 From: fg55b Date: Sun, 29 Sep 2024 13:39:19 -0300 Subject: [PATCH 03/17] feat/added scenarios and steps Scenarios for validating the horizontal continuity were added. Those scenarios should be implemented in another rule, but were maintained in the commit to be evaluated, and should be altered after --- ...rtical-segment-radius-of-curvature.feature | 32 +++++- features/steps/givens/attributes.py | 7 ++ features/steps/thens/attributes.py | 106 ++++++++++++++++-- 3 files changed, 129 insertions(+), 16 deletions(-) diff --git a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature index 4ac1f20f..caec8420 100644 --- a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature +++ b/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature @@ -2,18 +2,38 @@ @ALB @version1 @E00020 -Feature: ALB011 - Alignment vertical segment radius of curvature - The rule verifies if the curvature radius is provided in the correct predefined types and evaluates - its congruence with the start point gradient, the end point gradient, and the horizontal length of the segment. +Feature: ALB011 - Congruency and alignment of vertical segment + The rule verifies if the congruence of the data provided in IfcAlignmentVerticalSegment attributes according to its + predefined type, as well evaluating the congruency of the attributes in the connection between segments. Background: Given A model with Schema "IFC4.3" - Given An IfcAlignmentVerticalSegment + Given An IfcAlignmentVertical + Given A relationship IfcRelNests from IfcAlignmentVertical to IfcAlignmentSegment and following that + Given Its attribute DesignParameters - Scenario: Validating the radius of curvature of vertical segment + Scenario: Validating the horizontal continuity + Given Each instance pair at depth 1 + Then First instance StartDistAlong + HorizontalLength value must be equal to the second instance StartDistAlong at depth 1 + + Scenario: Validating the absence of curvature radius for constant gradient vertical segment Given PredefinedType != 'CIRCULARARC' or 'PARABOLICARC' Then The value of attribute RadiusOfCurvature must be empty + Scenario: Validating the end gradient for constant gradient vertical segment + Given PredefinedType = 'CONSTANTGRADIENT' + Then EndGradient value must be equal to the expression: StartGradient + Scenario: Validating the radius of curvature value of vertical segment Given PredefinedType = 'CIRCULARARC' or 'PARABOLICARC' - Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) \ No newline at end of file + Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) + + # Scenario: Validating the vertical continuity TODO + + # Scenario: Validating the tangential continuity (it will be ensured by IfcCurveSegment.Transition) TODO + # Given Its attribute Representation + # Given Its attribute Representations + # Given Its attribute Items + # Given Print at depth 1 + # Given Each instance pair at depth 1 + # Then First instance EndGradient value must be equal to the second instance StartGradient at depth 1 \ No newline at end of file diff --git a/features/steps/givens/attributes.py b/features/steps/givens/attributes.py index a6f59b59..e149833c 100644 --- a/features/steps/givens/attributes.py +++ b/features/steps/givens/attributes.py @@ -162,3 +162,10 @@ def step_impl(context, inst, ff : FirstOrFinal): @gherkin_ifc.step("An IFC model") def step_impl(context): yield ValidationOutcome(instance_id = context.model, severity=OutcomeSeverity.PASSED) + +@gherkin_ifc.step('Each instance pair at depth 1') +def step_impl(context, inst): + pairs = list() + for i in range(0, len(inst) - 1): + pairs.append([inst[i], inst[i+1]]) + yield ValidationOutcome(instance_id = [pairs], severity=OutcomeSeverity.PASSED) diff --git a/features/steps/thens/attributes.py b/features/steps/thens/attributes.py index dcfdd57d..00e93960 100644 --- a/features/steps/thens/attributes.py +++ b/features/steps/thens/attributes.py @@ -1,5 +1,5 @@ import operator - +import ifcopenshell from utils import misc, system, geometry from validation_handling import gherkin_ifc @@ -148,7 +148,7 @@ def step_impl(context, inst, attribute_compared:str, comparison_op:str, expressi '*' : operator.mul, '/' : operator.truediv, '%' : operator.mod, - '^' : operator.pow, + '**' : operator.pow, 'equal to' : operator.eq, 'not equal to' : operator.ne, 'greater than' : operator.gt, @@ -158,16 +158,22 @@ def step_impl(context, inst, attribute_compared:str, comparison_op:str, expressi } # Get compared attribute value - attr_compared_value = getattr(inst, attribute_compared, 'Attribute not found') + + attr_compared_value = getattr(inst, attribute_compared, 'Compared attribute not found') + if isinstance(attr_compared_value, ifcopenshell.entity_instance): + raise Exception('Compared attribute value is an IFC entity') # Replace attribute names with attribute values in the expression for string in expression.split(): # Checks if the string is not a operator neither parenthesis if string not in [*operators, '(', ')']: if hasattr(inst, string): - expression = expression.replace(string, str(getattr(inst, string))) + if not isinstance(getattr(inst, string), ifcopenshell.entity_instance): + expression = expression.replace(string, str(getattr(inst, string))) + else: + raise Exception('Expression attribute value is an IFC entity') else: - raise Exception('Attribute not found') + raise Exception('Expression attribute not found') # Evaluate the string expression using eval try: @@ -175,15 +181,95 @@ def step_impl(context, inst, attribute_compared:str, comparison_op:str, expressi except Exception as e: raise ValueError(f"Error evaluating expression: {e}") - print(attr_compared_value) - print(expression_value) - print() - # Compare the attribute with the expression value comparison_func = operators.get(comparison_op) if comparison_func: result = comparison_func(attr_compared_value, expression_value) if not result: - yield ValidationOutcome(inst=inst, severity=OutcomeSeverity.ERROR) + yield ValidationOutcome( + inst=inst, + expected=f"A value {comparison_op} {expression_value}", + observed={attr_compared_value}, + severity=OutcomeSeverity.ERROR, + ) + else: + raise ValueError(f"Invalid comparison operator: {comparison_op}") + +@gherkin_ifc.step('First instance {first_expression} value must be {comparison_op} the second instance {second_expression}') +@gherkin_ifc.step('First instance {first_expression} value must be {comparison_op} the second instance {second_expression} at depth 1') +def step_impl(context, inst, first_expression:str, comparison_op:str, second_expression:str): + ''' + Compare expressions based on attributes from two different instances. + + The {comparison_op} operator can be 'equal to', 'not equal to', 'greater than', 'less than', 'greater than or equal to', and 'less than or equal to'. + + The {expression} should be composed by attribute values, and use the following operators: + + : addition; + - : subtraction; + * : multiplication; + / : division; + % : modulus; + ** : exponentiation.''' + + operators = { + '+' : operator.add, + '-' : operator.sub, + '*' : operator.mul, + '/' : operator.truediv, + '%' : operator.mod, + '**' : operator.pow, + 'equal to' : operator.eq, + 'not equal to' : operator.ne, + 'greater than' : operator.gt, + 'less than' : operator.gt, + 'greater than or equal to' : operator.ge, + 'less than or equal to' : operator.le, + } + + # Get both instances + first_instance, second_instance = inst[0], inst[1] + + # Replace attribute names with attribute values in the expression of the first instance + for string in first_expression.split(): + # Checks if the string is not a operator neither parenthesis + if string not in [*operators, '(', ')']: + if hasattr(first_instance, string): + if not isinstance(getattr(first_instance, string), ifcopenshell.entity_instance): + first_expression = first_expression.replace(string, str(getattr(first_instance, string))) + else: + raise Exception('Expression attribute value is an IFC entity') + else: + raise Exception('Expression attribute not found') + + # Replace attribute names with attribute values in the expression of the second instance + for string in second_expression.split(): + # Checks if the string is not a operator neither parenthesis + if string not in [*operators, '(', ')']: + if hasattr(second_instance, string): + if not isinstance(getattr(second_instance, string), ifcopenshell.entity_instance): + second_expression = second_expression.replace(string, str(getattr(second_instance, string))) + else: + raise Exception('Expression attribute value is an IFC entity') + else: + raise Exception('Expression attribute not found') + + # Evaluate the string expressions using eval + try: + first_expression_value = eval(first_expression) + second_expression_value = eval(second_expression) + except Exception as e: + raise ValueError(f"Error evaluating expression: {e}") + + # Compare the expression values + comparison_func = operators.get(comparison_op) + if comparison_func: + result = comparison_func(first_expression_value, second_expression_value) + if not result: + yield ValidationOutcome( + inst=inst, + expected=f"A value {comparison_op} {second_expression_value}", + observed={first_expression_value}, + severity=OutcomeSeverity.ERROR, + ) else: raise ValueError(f"Invalid comparison operator: {comparison_op}") \ No newline at end of file From fc93553c8f6eb1dd333a0b6cb0ec4ca72a873636 Mon Sep 17 00:00:00 2001 From: fg55b Date: Wed, 2 Oct 2024 08:09:09 -0300 Subject: [PATCH 04/17] feat/added precision tolerance to the comparison It was created a function of comparison that considers the instance context precision tolerance. This function was added in the 'then' step that compares an attributes to an expression. --- ...rtical-segment-radius-of-curvature.feature | 18 +++--- features/steps/thens/attributes.py | 58 ++++++++++++------- features/steps/utils/geometry.py | 27 +++++++++ 3 files changed, 74 insertions(+), 29 deletions(-) diff --git a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature index caec8420..763c91af 100644 --- a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature +++ b/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature @@ -2,9 +2,9 @@ @ALB @version1 @E00020 -Feature: ALB011 - Congruency and alignment of vertical segment - The rule verifies if the congruence of the data provided in IfcAlignmentVerticalSegment attributes according to its - predefined type, as well evaluating the congruency of the attributes in the connection between segments. +Feature: ALB011 - Alignment vertical segment radius of curvature + The rule verifies if the radius of curvature was provided only to the correct type of vertical segment, CIRCULARARC and PARABOLICARC, + and validate it based in the 'RadiusOfCurvature = HorizontalLength/(EndGradient-StartGradient)' expression. Background: Given A model with Schema "IFC4.3" @@ -12,17 +12,17 @@ Feature: ALB011 - Congruency and alignment of vertical segment Given A relationship IfcRelNests from IfcAlignmentVertical to IfcAlignmentSegment and following that Given Its attribute DesignParameters - Scenario: Validating the horizontal continuity - Given Each instance pair at depth 1 - Then First instance StartDistAlong + HorizontalLength value must be equal to the second instance StartDistAlong at depth 1 + # Scenario: Validating the horizontal continuity + # Given Each instance pair at depth 1 + # Then First instance StartDistAlong + HorizontalLength value must be equal to the second instance StartDistAlong at depth 1 Scenario: Validating the absence of curvature radius for constant gradient vertical segment Given PredefinedType != 'CIRCULARARC' or 'PARABOLICARC' Then The value of attribute RadiusOfCurvature must be empty - Scenario: Validating the end gradient for constant gradient vertical segment - Given PredefinedType = 'CONSTANTGRADIENT' - Then EndGradient value must be equal to the expression: StartGradient + # Scenario: Validating the end gradient for constant gradient vertical segment + # Given PredefinedType = 'CONSTANTGRADIENT' + # Then EndGradient value must be equal to the expression: StartGradient Scenario: Validating the radius of curvature value of vertical segment Given PredefinedType = 'CIRCULARARC' or 'PARABOLICARC' diff --git a/features/steps/thens/attributes.py b/features/steps/thens/attributes.py index 00e93960..976ad77c 100644 --- a/features/steps/thens/attributes.py +++ b/features/steps/thens/attributes.py @@ -180,20 +180,29 @@ def step_impl(context, inst, attribute_compared:str, comparison_op:str, expressi expression_value = eval(expression) except Exception as e: raise ValueError(f"Error evaluating expression: {e}") - - # Compare the attribute with the expression value - comparison_func = operators.get(comparison_op) - if comparison_func: - result = comparison_func(attr_compared_value, expression_value) - if not result: + + # Compare the attribute with the expression value, considering the precision + entity_contexts = geometry.recurrently_get_entity_attr(context, inst, 'IfcRepresentation', 'ContextOfItems') + precision = geometry.get_precision_from_contexts(entity_contexts) + + try: + result = geometry.compare_with_precision(attr_compared_value, expression_value, precision, comparison_op) + if result: + yield ValidationOutcome( + inst=inst, + expected=f"A value {comparison_op} {expression_value} with precision {precision}", + observed=attr_compared_value, + severity=OutcomeSeverity.PASSED, + ) + else: yield ValidationOutcome( inst=inst, expected=f"A value {comparison_op} {expression_value}", - observed={attr_compared_value}, + observed=attr_compared_value, severity=OutcomeSeverity.ERROR, - ) - else: - raise ValueError(f"Invalid comparison operator: {comparison_op}") + ) + except ValueError as e: + raise ValueError(f"Error during comparison: {e}") @gherkin_ifc.step('First instance {first_expression} value must be {comparison_op} the second instance {second_expression}') @gherkin_ifc.step('First instance {first_expression} value must be {comparison_op} the second instance {second_expression} at depth 1') @@ -259,17 +268,26 @@ def step_impl(context, inst, first_expression:str, comparison_op:str, second_exp second_expression_value = eval(second_expression) except Exception as e: raise ValueError(f"Error evaluating expression: {e}") - - # Compare the expression values - comparison_func = operators.get(comparison_op) - if comparison_func: - result = comparison_func(first_expression_value, second_expression_value) - if not result: + + # Compare the attribute with the expression value, considering the precision + entity_contexts = geometry.recurrently_get_entity_attr(context, inst, 'IfcRepresentation', 'ContextOfItems') + precision = geometry.get_precision_from_contexts(entity_contexts) + + try: + result = geometry.compare_with_precision(first_expression_value, second_expression_value, precision, comparison_op) + if result: + yield ValidationOutcome( + inst=inst, + expected=f"A value {comparison_op} {second_expression_value} with precision {precision}", + observed=first_expression_value, + severity=OutcomeSeverity.PASSED, + ) + else: yield ValidationOutcome( inst=inst, expected=f"A value {comparison_op} {second_expression_value}", - observed={first_expression_value}, + observed=first_expression_value, severity=OutcomeSeverity.ERROR, - ) - else: - raise ValueError(f"Invalid comparison operator: {comparison_op}") \ No newline at end of file + ) + except ValueError as e: + raise ValueError(f"Error during comparison: {e}") \ No newline at end of file diff --git a/features/steps/utils/geometry.py b/features/steps/utils/geometry.py index b6ddc384..34612877 100644 --- a/features/steps/utils/geometry.py +++ b/features/steps/utils/geometry.py @@ -178,3 +178,30 @@ def alignment_segment_angular_difference( delta = abs(current_start_direction - preceding_end_direction) return delta + + +def compare_with_precision(value_1, value_2, precision, comparison_operator): + '''Compare the value_1 with value_2 according to a comparison operator. + + The valid comparison operators are: + 'equal to'; + 'not equal to'; + 'greater than'; + 'less than'; + 'greater than or equal to'; + 'less than or equal to'. + ''' + if comparison_operator == 'equal to': + return math.isclose(value_1, value_2, abs_tol=precision) + elif comparison_operator == 'not equal to': + return not math.isclose(value_1, value_2, abs_tol=precision) + elif comparison_operator == 'greater than': + return value_1 > value_2 and not math.isclose(value_1, value_2, abs_tol=precision) + elif comparison_operator == 'less than': + return value_1 < value_2 and not math.isclose(value_1, value_2, abs_tol=precision) + elif comparison_operator == 'greater than or equal to': + return value_1 > value_2 or math.isclose(value_1, value_2, abs_tol=precision) + elif comparison_operator == 'less than or equal to': + return value_1 < value_2 or math.isclose(value_1, value_2, abs_tol=precision) + else: + raise ValueError(f"Invalid comparison operator: {comparison_operator}") \ No newline at end of file From b89ae4534fffe6585e627f47c93ae69b57705379 Mon Sep 17 00:00:00 2001 From: fg55b Date: Wed, 2 Oct 2024 08:36:22 -0300 Subject: [PATCH 05/17] feat/update compare function description --- features/steps/utils/geometry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/utils/geometry.py b/features/steps/utils/geometry.py index 34612877..937823a1 100644 --- a/features/steps/utils/geometry.py +++ b/features/steps/utils/geometry.py @@ -181,7 +181,7 @@ def alignment_segment_angular_difference( def compare_with_precision(value_1, value_2, precision, comparison_operator): - '''Compare the value_1 with value_2 according to a comparison operator. + '''Compare the value_1 with value_2 according to a comparison operator, considering a precision tolerance. The valid comparison operators are: 'equal to'; From 99696021c6f9ef0b5e1c4daf6f2d1d857c5b7768 Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Wed, 2 Oct 2024 09:11:12 -0400 Subject: [PATCH 06/17] rename ALB011 to ALB012 ALB010 is already in use. Renaming this feature will allow for a new rule ALB011 to check RadiusOfCurvature for the horizontal layout. (IVS-137) --- ...rtical-segment-radius-of-curvature.feature | 39 ------------------- ...rtical-segment-radius-of-curvature.feature | 32 +++++++++++++++ 2 files changed, 32 insertions(+), 39 deletions(-) delete mode 100644 features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature create mode 100644 features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature diff --git a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature deleted file mode 100644 index caec8420..00000000 --- a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature +++ /dev/null @@ -1,39 +0,0 @@ -@implementer-agreement -@ALB -@version1 -@E00020 -Feature: ALB011 - Congruency and alignment of vertical segment - The rule verifies if the congruence of the data provided in IfcAlignmentVerticalSegment attributes according to its - predefined type, as well evaluating the congruency of the attributes in the connection between segments. - - Background: - Given A model with Schema "IFC4.3" - Given An IfcAlignmentVertical - Given A relationship IfcRelNests from IfcAlignmentVertical to IfcAlignmentSegment and following that - Given Its attribute DesignParameters - - Scenario: Validating the horizontal continuity - Given Each instance pair at depth 1 - Then First instance StartDistAlong + HorizontalLength value must be equal to the second instance StartDistAlong at depth 1 - - Scenario: Validating the absence of curvature radius for constant gradient vertical segment - Given PredefinedType != 'CIRCULARARC' or 'PARABOLICARC' - Then The value of attribute RadiusOfCurvature must be empty - - Scenario: Validating the end gradient for constant gradient vertical segment - Given PredefinedType = 'CONSTANTGRADIENT' - Then EndGradient value must be equal to the expression: StartGradient - - Scenario: Validating the radius of curvature value of vertical segment - Given PredefinedType = 'CIRCULARARC' or 'PARABOLICARC' - Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) - - # Scenario: Validating the vertical continuity TODO - - # Scenario: Validating the tangential continuity (it will be ensured by IfcCurveSegment.Transition) TODO - # Given Its attribute Representation - # Given Its attribute Representations - # Given Its attribute Items - # Given Print at depth 1 - # Given Each instance pair at depth 1 - # Then First instance EndGradient value must be equal to the second instance StartGradient at depth 1 \ No newline at end of file diff --git a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature new file mode 100644 index 00000000..22f5ef27 --- /dev/null +++ b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature @@ -0,0 +1,32 @@ +@implementer-agreement +@ALB +@version1 +@E00020 +Feature: ALB011 - Vertical alignment design parameters + The rule verifies the correctness and agreement of design parameters for vertical alignment segments. + + Background: + Given A model with Schema "IFC4.3" + Given An IfcAlignmentVertical + Given A relationship IfcRelNests from IfcAlignmentVertical to IfcAlignmentSegment and following that + Given Its attribute DesignParameters + + Scenario: Validating agreement between StartDistAlong and HorizontalLength + Given Each instance pair at depth 1 + Then First instance StartDistAlong + HorizontalLength value must be equal to the second instance StartDistAlong at depth 1 + + Scenario: Validating the end gradient for constant gradient segments + Given PredefinedType = 'CONSTANTGRADIENT' + Then EndGradient value must be equal to the expression: StartGradient + + Scenario: Validating the absence of curvature radius for constant gradient vertical segment + Given PredefinedType != 'CIRCULARARC' or 'PARABOLICARC' + Then The value of attribute RadiusOfCurvature must be empty + + Scenario: Validating the radius of curvature for parabolic segments + Given PredefinedType = 'PARABOLICARC' + Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) + + Scenario: Validating the radius of curvature for circular segments + Given PredefinedType = 'CIRCULARARC' + Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) From 7f21949850fddda1954a7f7bba296298991bf5d1 Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Wed, 9 Oct 2024 21:33:05 -0400 Subject: [PATCH 07/17] rename ALB011 to ALB012 (IVS-143) --- ...nt-vertical-segment-radius-of-curvature.feature | 14 -------------- ...nt-vertical-segment-radius-of-curvature.feature | 12 ++---------- ...io02-incorrect_radius_parabolic_curve_type.ifc} | 2 +- ...alb012-correct_radius_parabolic_curve_type.ifc} | 2 +- 4 files changed, 4 insertions(+), 26 deletions(-) delete mode 100644 features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature rename test/files/{alb011/fail-alb011-incorrect_radius_parabolic_curve_type.ifc => alb012/fail-alb012-scenario02-incorrect_radius_parabolic_curve_type.ifc} (99%) rename test/files/{alb011/pass-alb011-correct_radius_parabolic_curve_type.ifc => alb012/pass-alb012-correct_radius_parabolic_curve_type.ifc} (99%) diff --git a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature deleted file mode 100644 index 9c0ccc1d..00000000 --- a/features/ALB011_Alignment-vertical-segment-radius-of-curvature.feature +++ /dev/null @@ -1,14 +0,0 @@ - - Scenario: Validating the radius of curvature value of vertical segment - Given PredefinedType = 'CIRCULARARC' or 'PARABOLICARC' - Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) - - # Scenario: Validating the vertical continuity TODO - - # Scenario: Validating the tangential continuity (it will be ensured by IfcCurveSegment.Transition) TODO - # Given Its attribute Representation - # Given Its attribute Representations - # Given Its attribute Items - # Given Print at depth 1 - # Given Each instance pair at depth 1 - # Then First instance EndGradient value must be equal to the second instance StartGradient at depth 1 \ No newline at end of file diff --git a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature index 22f5ef27..e8473562 100644 --- a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature +++ b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature @@ -2,7 +2,7 @@ @ALB @version1 @E00020 -Feature: ALB011 - Vertical alignment design parameters +Feature: ALB012 - Alignment vertical segment radius of curvature The rule verifies the correctness and agreement of design parameters for vertical alignment segments. Background: @@ -11,16 +11,8 @@ Feature: ALB011 - Vertical alignment design parameters Given A relationship IfcRelNests from IfcAlignmentVertical to IfcAlignmentSegment and following that Given Its attribute DesignParameters - Scenario: Validating agreement between StartDistAlong and HorizontalLength - Given Each instance pair at depth 1 - Then First instance StartDistAlong + HorizontalLength value must be equal to the second instance StartDistAlong at depth 1 - - Scenario: Validating the end gradient for constant gradient segments - Given PredefinedType = 'CONSTANTGRADIENT' - Then EndGradient value must be equal to the expression: StartGradient - Scenario: Validating the absence of curvature radius for constant gradient vertical segment - Given PredefinedType != 'CIRCULARARC' or 'PARABOLICARC' + Given PredefinedType = 'CONSTANTGRADIENT' Then The value of attribute RadiusOfCurvature must be empty Scenario: Validating the radius of curvature for parabolic segments diff --git a/test/files/alb011/fail-alb011-incorrect_radius_parabolic_curve_type.ifc b/test/files/alb012/fail-alb012-scenario02-incorrect_radius_parabolic_curve_type.ifc similarity index 99% rename from test/files/alb011/fail-alb011-incorrect_radius_parabolic_curve_type.ifc rename to test/files/alb012/fail-alb012-scenario02-incorrect_radius_parabolic_curve_type.ifc index 706d0d55..600e44c8 100644 --- a/test/files/alb011/fail-alb011-incorrect_radius_parabolic_curve_type.ifc +++ b/test/files/alb012/fail-alb012-scenario02-incorrect_radius_parabolic_curve_type.ifc @@ -1,7 +1,7 @@ ISO-10303-21; HEADER; FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); -FILE_NAME('alb011-fail-incorrect_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_NAME('fail-alb012-incorrect_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); FILE_SCHEMA(('IFC4X3_ADD2')); ENDSEC; DATA; diff --git a/test/files/alb011/pass-alb011-correct_radius_parabolic_curve_type.ifc b/test/files/alb012/pass-alb012-correct_radius_parabolic_curve_type.ifc similarity index 99% rename from test/files/alb011/pass-alb011-correct_radius_parabolic_curve_type.ifc rename to test/files/alb012/pass-alb012-correct_radius_parabolic_curve_type.ifc index b4e55c5c..020d0ae7 100644 --- a/test/files/alb011/pass-alb011-correct_radius_parabolic_curve_type.ifc +++ b/test/files/alb012/pass-alb012-correct_radius_parabolic_curve_type.ifc @@ -1,7 +1,7 @@ ISO-10303-21; HEADER; FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); -FILE_NAME('alb011-pass-correct_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_NAME('pass-alb011-correct_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); FILE_SCHEMA(('IFC4X3_ADD2')); ENDSEC; DATA; From 29922bd0a776ed0764b7237c3a9e167799a0b8dc Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Thu, 10 Oct 2024 09:03:31 -0400 Subject: [PATCH 08/17] finalize ALB012 feature file and unit tests ALB012 focuses solely on 'RadiusOfCurvature' design parameter and includes a scenario that fixes #241. (IVS-137) --- ...rtical-segment-radius-of-curvature.feature | 8 +- ...enario01-constant_gradient_with_radius.ifc | 273 ++++++++++++++++++ ...12-correct_radius_parabolic_curve_type.ifc | 2 +- 3 files changed, 276 insertions(+), 7 deletions(-) create mode 100644 test/files/alb012/fail-alb012-scenario01-constant_gradient_with_radius.ifc diff --git a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature index e8473562..547e8cbf 100644 --- a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature +++ b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature @@ -3,7 +3,7 @@ @version1 @E00020 Feature: ALB012 - Alignment vertical segment radius of curvature - The rule verifies the correctness and agreement of design parameters for vertical alignment segments. + The rule verifies the 'RadiusOfCurvature' design parameter for vertical alignment segments. Background: Given A model with Schema "IFC4.3" @@ -12,13 +12,9 @@ Feature: ALB012 - Alignment vertical segment radius of curvature Given Its attribute DesignParameters Scenario: Validating the absence of curvature radius for constant gradient vertical segment - Given PredefinedType = 'CONSTANTGRADIENT' + Given PredefinedType != 'ARC' or 'PARABOLICARC' Then The value of attribute RadiusOfCurvature must be empty Scenario: Validating the radius of curvature for parabolic segments Given PredefinedType = 'PARABOLICARC' Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) - - Scenario: Validating the radius of curvature for circular segments - Given PredefinedType = 'CIRCULARARC' - Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) diff --git a/test/files/alb012/fail-alb012-scenario01-constant_gradient_with_radius.ifc b/test/files/alb012/fail-alb012-scenario01-constant_gradient_with_radius.ifc new file mode 100644 index 00000000..6867e0b1 --- /dev/null +++ b/test/files/alb012/fail-alb012-scenario01-constant_gradient_with_radius.ifc @@ -0,0 +1,273 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); +FILE_NAME('fail-alb012-scenario01-constant_gradient_with_radius.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_SCHEMA(('IFC4X3_ADD2')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,'',$,$,$,$,$); +#2=IFCORGANIZATION('redacted','redacted',$,(#18),$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +#4=IFCAPPLICATION(#2,'redacted','redacted','redacted'); +#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,1721342253,#3,#4,1721342253); +#6=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#7=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#8=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#9=IFCUNITASSIGNMENT((#7,#8)); +#10=IFCPROJECT('2NKwV2qd55_Ou$L3sGEcJ5',#5,'Unnamed Bridge Project',$,$,$,$,(#34),#9); +#11=IFCDIRECTION((1.,0.,0.)); +#12=IFCDIRECTION((0.,0.,1.)); +#13=IFCCARTESIANPOINT((0.,0.,0.)); +#14=IFCAXIS2PLACEMENT3D(#13,#12,#11); +#15=IFCLOCALPLACEMENT($,#14); +#16=IFCSITE('1bkdwWptL9p8EOgG7oGLm8',#5,'Site of Unnamed Bridge',$,$,#15,$,$,.ELEMENT.,$,$,$,$,$); +#17=IFCRELAGGREGATES('2OyduV47v3MfrT$j43zMqR',#5,$,$,#10,(#16)); +#18=IFCACTORROLE(.CIVILENGINEER.,$,$); +#19=IFCPROPERTYENUMERATION('PEnum_ProjectType',(IFCLABEL('MODIFICATION'),IFCLABEL('NEWBUILD'),IFCLABEL('OPERATIONMAINTENANCE'),IFCLABEL('RENOVATION'),IFCLABEL('REPAIR')),$); +#20=IFCPROPERTYENUMERATEDVALUE('ProjectType',$,(IFCLABEL('NEWBUILD')),#19); +#21=IFCPROPERTYSET('20vQbRVmnED8iLLqekYzX1',$,'Pset_ProjectCommon',$,(#20)); +#22=IFCRELDEFINESBYPROPERTIES('1U4REvlNHDgv01F5_XE5w9',$,$,$,(#10),#21); +#23=IFCPROPERTYSINGLEVALUE('ContractNumber',$,IFCLABEL('Unknown'),$); +#24=IFCPROPERTYSINGLEVALUE('DesignNumber',$,IFCLABEL('Unknown'),$); +#25=IFCPROPERTYSINGLEVALUE('ProjectNumber',$,IFCLABEL('Unknown'),$); +#26=IFCPROPERTYSINGLEVALUE('ProjectWebsite',$,IFCLABEL('Unknown'),$); +#27=IFCPROPERTYSET('38HZ$LnA18KP01_4uL6vpy',$,'AASHTO_ProjectCommon',$,(#23,#24,#25,#26)); +#28=IFCRELDEFINESBYPROPERTIES('0SVmDQPaH0v993Ve$aV21O',$,$,$,(#10),#27); +#29=IFCDIRECTION((0.,1.)); +#30=IFCDIRECTION((1.,0.,0.)); +#31=IFCDIRECTION((0.,0.,1.)); +#32=IFCCARTESIANPOINT((0.,0.,0.)); +#33=IFCAXIS2PLACEMENT3D(#32,#31,#30); +#34=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#33,#29); +#35=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#34,$,.MODEL_VIEW.,$); +#36=IFCCARTESIANPOINT((152.4,762.)); +#37=IFCALIGNMENTHORIZONTALSEGMENT($,$,#36,5.70829809225671,0.,0.,596.427809947411,$,.LINE.); +#38=IFCALIGNMENTSEGMENT('1yKEFhEET3lxaALz5ILLKJ',$,'H1',$,$,#217,#219,#37); +#39=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#40=IFCAXIS2PLACEMENT2D(#36,#39); +#41=IFCCARTESIANPOINT((0.,0.)); +#42=IFCDIRECTION((1.,0.)); +#43=IFCVECTOR(#42,1.); +#44=IFCLINE(#41,#43); +#45=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#40,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(596.427809947411),#44); +#46=IFCCARTESIANPOINT((652.954206637821,437.698259801391)); +#47=IFCALIGNMENTHORIZONTALSEGMENT($,$,#46,5.70829809225671,304.8,304.8,584.978933611456,$,.CIRCULARARC.); +#48=IFCALIGNMENTSEGMENT('3bkfv7AiX7u8eHZy2v00yU',$,'H2',$,$,#217,#221,#47); +#49=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#50=IFCAXIS2PLACEMENT2D(#46,#49); +#51=IFCCARTESIANPOINT((0.,0.)); +#52=IFCDIRECTION((1.,0.)); +#53=IFCAXIS2PLACEMENT2D(#51,#52); +#54=IFCCIRCLE(#53,304.8); +#55=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#50,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(584.978933611456),#54); +#56=IFCCARTESIANPOINT((1115.70375380811,625.065837937277)); +#57=IFCALIGNMENTHORIZONTALSEGMENT($,$,#56,1.34433500821182,0.,0.,575.126530840636,$,.LINE.); +#58=IFCALIGNMENTSEGMENT('1y1cFxO7DCO8ifhYDB3kg5',$,'H3',$,$,#217,#223,#57); +#59=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#60=IFCAXIS2PLACEMENT2D(#56,#59); +#61=IFCCARTESIANPOINT((0.,0.)); +#62=IFCDIRECTION((1.,0.)); +#63=IFCVECTOR(#62,1.); +#64=IFCLINE(#61,#63); +#65=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#60,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(575.126530840636),#64); +#66=IFCCARTESIANPOINT((1244.83726354192,1185.50768428765)); +#67=IFCALIGNMENTHORIZONTALSEGMENT($,$,#66,1.34433500821182,-381.,-381.,563.305699668461,$,.CIRCULARARC.); +#68=IFCALIGNMENTSEGMENT('2ZhQROlxz9yvU3hgu8kF3y',$,'H4',$,$,#217,#225,#67); +#69=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#70=IFCAXIS2PLACEMENT2D(#66,#69); +#71=IFCCARTESIANPOINT((0.,0.)); +#72=IFCDIRECTION((1.,0.)); +#73=IFCAXIS2PLACEMENT2D(#71,#72); +#74=IFCCIRCLE(#73,381.); +#75=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#70,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-563.305699668461),#74); +#76=IFCCARTESIANPOINT((1667.0700765915,1477.5379910302)); +#77=IFCALIGNMENTHORIZONTALSEGMENT($,$,#76,6.14902766534295,0.,0.,476.89956141461,$,.LINE.); +#78=IFCALIGNMENTSEGMENT('1XuHWXwT969Q35ImfH0Ogg',$,'H5',$,$,#217,#227,#77); +#79=IFCDIRECTION((0.99101435288277,-0.133755569530191)); +#80=IFCAXIS2PLACEMENT2D(#76,#79); +#81=IFCCARTESIANPOINT((0.,0.)); +#82=IFCDIRECTION((1.,0.)); +#83=IFCVECTOR(#82,1.); +#84=IFCLINE(#81,#83); +#85=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#80,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(476.89956141461),#84); +#86=IFCCARTESIANPOINT((2139.68438683688,1413.75001858449)); +#87=IFCALIGNMENTHORIZONTALSEGMENT($,$,#86,6.14902766534296,-289.56,-289.56,319.772021994801,$,.CIRCULARARC.); +#88=IFCALIGNMENTSEGMENT('1WyDRQrLf4Pfa7hc66x7z4',$,'H6',$,$,#217,#229,#87); +#89=IFCDIRECTION((0.99101435288277,-0.13375556953019)); +#90=IFCAXIS2PLACEMENT2D(#86,#89); +#91=IFCCARTESIANPOINT((0.,0.)); +#92=IFCDIRECTION((1.,0.)); +#93=IFCAXIS2PLACEMENT2D(#91,#92); +#94=IFCCIRCLE(#93,289.56); +#95=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#90,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-319.772021994801),#94); +#96=IFCCARTESIANPOINT((2374.67351814968,1221.25187786577)); +#97=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); +#98=IFCALIGNMENTSEGMENT('2Gm5hd_S9FihJigptQqiqo',$,'H7',$,$,#217,#231,#97); +#99=IFCDIRECTION((0.447213595499958,-0.894427190999916)); +#100=IFCAXIS2PLACEMENT2D(#96,#99); +#101=IFCCARTESIANPOINT((0.,0.)); +#102=IFCDIRECTION((1.,0.)); +#103=IFCVECTOR(#102,1.); +#104=IFCLINE(#101,#103); +#105=IFCCURVESEGMENT(.DISCONTINUOUS.,#100,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#104); +#106=IFCALIGNMENTHORIZONTAL('2xHGSjSTHDOuz10zo9imZ$',$,'Horizontal Alignment',$,$,$,$); +#107=IFCRELNESTS('3mBmExvib60u04Ek8FIcUL',$,$,'Nests horizontal alignment segments with horizontal alignment',#106,(#38,#48,#58,#68,#78,#88,#98)); +#108=IFCCOMPOSITECURVE((#45,#55,#65,#75,#85,#95,#105),.F.); +#109=IFCALIGNMENTVERTICALSEGMENT($,$,0.,365.76,30.48,0.0175,0.0175,200.,.CONSTANTGRADIENT.); +#110=IFCALIGNMENTSEGMENT('0wiwmz1qT5CguAmO4rZfuD',$,'V1',$,$,#217,#233,#109); +#111=IFCCARTESIANPOINT((0.,30.48)); +#112=IFCDIRECTION((0.999846863274572,0.0175)); +#113=IFCAXIS2PLACEMENT2D(#111,#112); +#114=IFCCARTESIANPOINT((0.,0.)); +#115=IFCDIRECTION((1.,0.)); +#116=IFCVECTOR(#115,1.); +#117=IFCLINE(#114,#116); +#118=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#113,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#117); +#119=IFCALIGNMENTVERTICALSEGMENT($,$,365.76,487.68,36.8808,0.0175,-0.01,-17733.81818,.PARABOLICARC.); +#120=IFCALIGNMENTSEGMENT('0GMpbyK7LAOhZ3MKPhlSDJ',$,'V2',$,$,#217,#235,#119); +#121=IFCCARTESIANPOINT((365.76,36.8808)); +#122=IFCDIRECTION((0.999846863274572,0.0175)); +#123=IFCAXIS2PLACEMENT2D(#121,#122); +#124=IFCCARTESIANPOINT((0.,0.)); +#125=IFCDIRECTION((1.,0.)); +#126=IFCAXIS2PLACEMENT2D(#124,#125); +#127=IFCPOLYNOMIALCURVE(#126,(0.,1.),(36.8808,0.0175,-2.8194717847769E-05),$); +#128=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#123,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.68),#127); +#129=IFCALIGNMENTVERTICALSEGMENT($,$,853.440000000001,487.679999999999,38.7096,-0.01,-0.01,$,.CONSTANTGRADIENT.); +#130=IFCALIGNMENTSEGMENT('3WSKXiwfv2AhAYT1b$NDBj',$,'V3',$,$,#217,#237,#129); +#131=IFCCARTESIANPOINT((853.440000000001,38.7096)); +#132=IFCDIRECTION((0.999949998749938,-0.01)); +#133=IFCAXIS2PLACEMENT2D(#131,#132); +#134=IFCCARTESIANPOINT((0.,0.)); +#135=IFCDIRECTION((1.,0.)); +#136=IFCVECTOR(#135,1.); +#137=IFCLINE(#134,#136); +#138=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#133,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.679999999999),#137); +#139=IFCALIGNMENTVERTICALSEGMENT($,$,1341.12,365.76,33.8328,-0.01,0.02,12192.,.PARABOLICARC.); +#140=IFCALIGNMENTSEGMENT('0f3kcHMir0A9axLpYF$KeL',$,'V4',$,$,#217,#239,#139); +#141=IFCCARTESIANPOINT((1341.12,33.8328)); +#142=IFCDIRECTION((0.999949998749938,-0.01)); +#143=IFCAXIS2PLACEMENT2D(#141,#142); +#144=IFCCARTESIANPOINT((0.,0.)); +#145=IFCDIRECTION((1.,0.)); +#146=IFCAXIS2PLACEMENT2D(#144,#145); +#147=IFCPOLYNOMIALCURVE(#146,(0.,1.),(33.8328,-0.01,4.1010498687664E-05),$); +#148=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#143,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#147); +#149=IFCALIGNMENTVERTICALSEGMENT($,$,1706.88,243.84,35.6616,0.02,0.02,$,.CONSTANTGRADIENT.); +#150=IFCALIGNMENTSEGMENT('1oYMRqw$r2aO6hIvJEhzgO',$,'V5',$,$,#217,#241,#149); +#151=IFCCARTESIANPOINT((1706.88,35.6616)); +#152=IFCDIRECTION((0.999799979995999,0.02)); +#153=IFCAXIS2PLACEMENT2D(#151,#152); +#154=IFCCARTESIANPOINT((0.,0.)); +#155=IFCDIRECTION((1.,0.)); +#156=IFCVECTOR(#155,1.); +#157=IFCLINE(#154,#156); +#158=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#153,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#157); +#159=IFCALIGNMENTVERTICALSEGMENT($,$,1950.72,609.6,40.5384,0.02,-0.02,-15240.,.PARABOLICARC.); +#160=IFCALIGNMENTSEGMENT('2rmRh3RID4Dx1Xv2vdnAcV',$,'V6',$,$,#217,#243,#159); +#161=IFCCARTESIANPOINT((1950.72,40.5384)); +#162=IFCDIRECTION((0.999799979995999,0.02)); +#163=IFCAXIS2PLACEMENT2D(#161,#162); +#164=IFCCARTESIANPOINT((0.,0.)); +#165=IFCDIRECTION((1.,0.)); +#166=IFCAXIS2PLACEMENT2D(#164,#165); +#167=IFCPOLYNOMIALCURVE(#166,(0.,1.),(40.5384,0.02,-3.28083989501312E-05),$); +#168=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#163,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(609.6),#167); +#169=IFCALIGNMENTVERTICALSEGMENT($,$,2560.32,304.799999999999,40.5384,-0.02,-0.02,$,.CONSTANTGRADIENT.); +#170=IFCALIGNMENTSEGMENT('2kGQnCzmbB1hLZpc8B8fx7',$,'V7',$,$,#217,#245,#169); +#171=IFCCARTESIANPOINT((2560.32,40.5384)); +#172=IFCDIRECTION((0.999799979995999,-0.02)); +#173=IFCAXIS2PLACEMENT2D(#171,#172); +#174=IFCCARTESIANPOINT((0.,0.)); +#175=IFCDIRECTION((1.,0.)); +#176=IFCVECTOR(#175,1.); +#177=IFCLINE(#174,#176); +#178=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#173,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(304.799999999999),#177); +#179=IFCALIGNMENTVERTICALSEGMENT($,$,2865.12,243.84,34.4424,-0.02,-0.005,16256.,.PARABOLICARC.); +#180=IFCALIGNMENTSEGMENT('3hljyR0Hr0$hbnPws3P554',$,'V8',$,$,#217,#247,#179); +#181=IFCCARTESIANPOINT((2865.12,34.4424)); +#182=IFCDIRECTION((0.999799979995999,-0.02)); +#183=IFCAXIS2PLACEMENT2D(#181,#182); +#184=IFCCARTESIANPOINT((0.,0.)); +#185=IFCDIRECTION((1.,0.)); +#186=IFCAXIS2PLACEMENT2D(#184,#185); +#187=IFCPOLYNOMIALCURVE(#186,(0.,1.),(34.4424,-0.02,3.0757874015748E-05),$); +#188=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#183,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#187); +#189=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,7.55055747737515,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.); +#190=IFCALIGNMENTSEGMENT('0Yj$$A801BgAySuKuq8FH1',$,'V9',$,$,#217,#249,#189); +#191=IFCCARTESIANPOINT((3108.96,31.3944)); +#192=IFCDIRECTION((0.999987499921874,-0.005)); +#193=IFCAXIS2PLACEMENT2D(#191,#192); +#194=IFCCARTESIANPOINT((0.,0.)); +#195=IFCDIRECTION((1.,0.)); +#196=IFCVECTOR(#195,1.); +#197=IFCLINE(#194,#196); +#198=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#193,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(7.55055747737515),#197); +#199=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,0.,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.); +#200=IFCALIGNMENTSEGMENT('0FSjBm0hj8PwKhufHaF1ZA',$,'V10',$,$,#217,#251,#199); +#201=IFCCARTESIANPOINT((3108.96,31.3944)); +#202=IFCDIRECTION((0.999987499921874,-0.005)); +#203=IFCAXIS2PLACEMENT2D(#201,#202); +#204=IFCCARTESIANPOINT((0.,0.)); +#205=IFCDIRECTION((1.,0.)); +#206=IFCVECTOR(#205,1.); +#207=IFCLINE(#204,#206); +#208=IFCCURVESEGMENT(.DISCONTINUOUS.,#203,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#207); +#209=IFCALIGNMENTVERTICAL('2nEoeLO$jCAgLWqX3ZS4ZL',$,'Vertical Alignment',$,$,#15,$); +#210=IFCRELNESTS('1Zi6YpAun30A67NCfsmR6h',$,$,'Nests vertical alignment segments with vertical alignment',#209,(#110,#120,#130,#140,#150,#160,#170,#180,#190,#200)); +#211=IFCGRADIENTCURVE((#118,#128,#138,#148,#158,#168,#178,#188,#198,#208),.F.,#108,$); +#212=IFCSHAPEREPRESENTATION(#35,'Axis','Curve3D',(#211)); +#213=IFCDIRECTION((1.,0.,0.)); +#214=IFCDIRECTION((0.,0.,1.)); +#215=IFCCARTESIANPOINT((0.,0.,0.)); +#216=IFCAXIS2PLACEMENT3D(#215,#214,#213); +#217=IFCLOCALPLACEMENT($,#216); +#218=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#45)); +#219=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#218)); +#220=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#55)); +#221=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#220)); +#222=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#65)); +#223=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#222)); +#224=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#75)); +#225=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#224)); +#226=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#85)); +#227=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#226)); +#228=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#95)); +#229=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#228)); +#230=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#105)); +#231=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#230)); +#232=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#118)); +#233=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#232)); +#234=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#128)); +#235=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#234)); +#236=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#138)); +#237=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#236)); +#238=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#148)); +#239=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#238)); +#240=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#158)); +#241=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#240)); +#242=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#168)); +#243=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#242)); +#244=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#178)); +#245=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#244)); +#246=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#188)); +#247=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#246)); +#248=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#198)); +#249=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#248)); +#250=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#208)); +#251=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#250)); +#252=IFCPRODUCTDEFINITIONSHAPE('Alignment Product Definition Shape',$,(#212)); +#253=IFCALIGNMENT('0qKahqjPjBeuEjpOKkk23s',$,'Unnamed alignment',$,$,#15,#252,$); +#254=IFCRELNESTS('3p2wDzu0r4qBoQ$kirOpI9',$,'Nest horizontal and vertical alignment layouts with the alignment',$,#253,(#106,#209)); +#255=IFCRELAGGREGATES('1K9FW2VIP3Uf303$idpLPY',$,'Alignments in project',$,#10,(#253)); +#256=IFCRELREFERENCEDINSPATIALSTRUCTURE('10jns2II51eA4MvJstMUh6',$,$,$,(#253),#16); +#257=IFCPROPERTYSINGLEVALUE('Station',$,IFCLENGTHMEASURE(3048.),$); +#258=IFCPROPERTYSET('0ykDGVR8D9JvgG2BE$m9Y0',$,'Pset_Stationing',$,(#257)); +#259=IFCPOINTBYDISTANCEEXPRESSION(IFCLENGTHMEASURE(0.),$,$,$,#211); +#260=IFCAXIS2PLACEMENTLINEAR(#259,$,$); +#261=IFCLINEARPLACEMENT($,#260,$); +#262=IFCREFERENT('2MIQXRsdHE1ehEM_GIWxfu',$,'Start of alignment station',$,$,#261,$,.STATION.); +#263=IFCRELNESTS('0UMvxWgzT2mO2ObhWRe5TZ',$,'Nests Referents with station information with alignment',$,#253,(#262)); +#264=IFCRELDEFINESBYPROPERTIES('3SkNbYBX97uBNi5kNrE0qi',$,'Relates station properties to referent',$,(#262),#258); +ENDSEC; +END-ISO-10303-21; diff --git a/test/files/alb012/pass-alb012-correct_radius_parabolic_curve_type.ifc b/test/files/alb012/pass-alb012-correct_radius_parabolic_curve_type.ifc index 020d0ae7..2dfe0da9 100644 --- a/test/files/alb012/pass-alb012-correct_radius_parabolic_curve_type.ifc +++ b/test/files/alb012/pass-alb012-correct_radius_parabolic_curve_type.ifc @@ -1,7 +1,7 @@ ISO-10303-21; HEADER; FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); -FILE_NAME('pass-alb011-correct_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_NAME('pass-alb012-correct_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); FILE_SCHEMA(('IFC4X3_ADD2')); ENDSEC; DATA; From f5f6237736bc70af45944e6f792faf0cc2be7688 Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Fri, 11 Oct 2024 08:12:24 -0400 Subject: [PATCH 09/17] Update feature file per review comments Co-authored-by: Thomas Krijnen --- ...LB012_Alignment-vertical-segment-radius-of-curvature.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature index 547e8cbf..9382df97 100644 --- a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature +++ b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature @@ -17,4 +17,4 @@ Feature: ALB012 - Alignment vertical segment radius of curvature Scenario: Validating the radius of curvature for parabolic segments Given PredefinedType = 'PARABOLICARC' - Then RadiusOfCurvature value must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) + Then The value of attribute RadiusOfCurvature must be equal to the expression: HorizontalLength / ( EndGradient - StartGradient ) From 3b6122abae6e08b3d757680e6eada3168408f418 Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Sat, 12 Oct 2024 07:49:22 -0400 Subject: [PATCH 10/17] (WIP) addresses most of the ALB012 review comments - adds a Given statement for proper entity type of DesignParameters - adds `na` unit test file to confirm this new Given statement - adds `na` unit test file to confirm rule is not activated for alignment with horizontal layout only (IVS-137) --- ...rtical-segment-radius-of-curvature.feature | 3 +- features/steps/thens/attributes.py | 315 +++++++----------- ...ct_type_for_DesignParameters_attribute.ifc | 303 +++++++++++++++++ .../alb012/na-alb012-no_vertical_layout.ifc | 153 +++++++++ 4 files changed, 576 insertions(+), 198 deletions(-) create mode 100644 test/files/alb012/na-alb012-incorrect_type_for_DesignParameters_attribute.ifc create mode 100644 test/files/alb012/na-alb012-no_vertical_layout.ifc diff --git a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature index 9382df97..55e396fa 100644 --- a/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature +++ b/features/ALB012_Alignment-vertical-segment-radius-of-curvature.feature @@ -10,8 +10,9 @@ Feature: ALB012 - Alignment vertical segment radius of curvature Given An IfcAlignmentVertical Given A relationship IfcRelNests from IfcAlignmentVertical to IfcAlignmentSegment and following that Given Its attribute DesignParameters + Given Its entity type is 'IfcAlignmentVerticalSegment' - Scenario: Validating the absence of curvature radius for constant gradient vertical segment + Scenario: Validating the absence of curvature radius for specific predefined types of vertical segment Given PredefinedType != 'ARC' or 'PARABOLICARC' Then The value of attribute RadiusOfCurvature must be empty diff --git a/features/steps/thens/attributes.py b/features/steps/thens/attributes.py index 97ca5bc1..adf6bdf1 100644 --- a/features/steps/thens/attributes.py +++ b/features/steps/thens/attributes.py @@ -60,37 +60,124 @@ def accumulate_errors(i): yield from errors -@gherkin_ifc.step('The value of attribute {attribute} must be {value}') -@gherkin_ifc.step('The value of attribute {attribute} must be {value} {display_entity:display_entity}') -def step_impl(context, inst, attribute, value, display_entity=0): - # @todo the horror and inconsistency.. should we use - # ast here as well to differentiate between types? - pred = operator.eq - if value == 'empty': - value = () - elif value == 'not empty': - value = () - pred = operator.ne - elif 'or' in value: - opts = value.split(' or ') - value = tuple(opts) - pred = misc.reverse_operands(operator.contains) - - if isinstance(inst, (tuple, list)): - inst = inst[0] - attribute_value = getattr(inst, attribute, 'Attribute not found') - if attribute_value is None: - attribute_value = () - if inst is None: - # nothing was activated by the Given criteria - yield ValidationOutcome(inst=inst, severity=OutcomeSeverity.EXECUTED) - elif not pred(attribute_value, value): - yield ValidationOutcome( - inst=inst, - expected=None if not value else value, - observed=misc.recursive_unpack_value(attribute_value), - severity=OutcomeSeverity.ERROR - ) +@gherkin_ifc.step('The value of attribute {attribute} must be {value_or_comparison_op}') +@gherkin_ifc.step('The value of attribute {attribute} must be {value_or_comparison_op} {display_entity:display_entity}') +@gherkin_ifc.step('The value of attribute {attribute} must be {value_or_comparison_op} the expression: {expression}') +def step_impl(context, inst, attribute:str, value_or_comparison_op:str, expression:str=None, display_entity=0): + """ + Compare an attribute to an expression based on attributes. + + The {comparison_op} operator can be 'equal to', 'not equal to', 'greater than', 'less than', 'greater than or equal to', and 'less than or equal to'. + + The {expression} should be composed by attribute values, and use the following operators: + + : addition; + - : subtraction; + * : multiplication; + / : division; + % : modulus; + ** : exponentiation. + """ + + operators = { + '+' : operator.add, + '-' : operator.sub, + '*' : operator.mul, + '/' : operator.truediv, + '%' : operator.mod, + '**' : operator.pow, + 'equal to' : operator.eq, + 'not equal to' : operator.ne, + 'greater than' : operator.gt, + 'less than' : operator.gt, + 'greater than or equal to' : operator.ge, + 'less than or equal to' : operator.le, + } + + if expression is not None: + # Get compared attribute value + + attr_compared_value = getattr(inst, attribute, 'Compared attribute not found') + if isinstance(attr_compared_value, ifcopenshell.entity_instance): + raise Exception('Compared attribute value is an IFC entity') + + # Replace attribute names with attribute values in the expression + for string_content in expression.split(): + # Checks if the string is not a operator neither parenthesis + if string_content not in [*operators, '(', ')']: + if hasattr(inst, string_content): + if not isinstance(getattr(inst, string_content), ifcopenshell.entity_instance): + expression = expression.replace(string_content, str(getattr(inst, string_content))) + else: + raise Exception('Expression attribute value is an IFC entity') + else: + raise Exception('Expression attribute not found') + + # Evaluate the string expression using eval + try: + expression_value = eval(expression) + except Exception as e: + raise ValueError(f"Error evaluating expression: {e}") + + # Compare the attribute with the expression value, considering the precision + entity_contexts = geometry.recurrently_get_entity_attr(context, inst, 'IfcRepresentation', 'ContextOfItems') + precision = geometry.get_precision_from_contexts(entity_contexts) + + try: + result = geometry.compare_with_precision( + attr_compared_value, expression_value, precision, value_or_comparison_op + ) + if result: + yield ValidationOutcome( + inst=inst, + expected=f"A value {value_or_comparison_op} {expression_value} with precision {precision}", + observed={attr_compared_value}, + severity=OutcomeSeverity.PASSED, + ) + else: + yield ValidationOutcome( + inst=inst, + expected=f"A value {value_or_comparison_op} {expression_value}", + observed={attr_compared_value}, + severity=OutcomeSeverity.ERROR, + ) + except ValueError as e: + yield ValidationOutcome( + inst=inst, + expected=f"A value {value_or_comparison_op} {expression_value}", + observed=f"Error during comparison: {e}", + severity=OutcomeSeverity.ERROR, + ) + + + else: + # @todo the horror and inconsistency.. should we use + # ast here as well to differentiate between types? + pred = operator.eq + if value_or_comparison_op == 'empty': + value_or_comparison_op = () + elif value_or_comparison_op == 'not empty': + value_or_comparison_op = () + pred = operator.ne + elif 'or' in value_or_comparison_op: + opts = value_or_comparison_op.split(' or ') + value_or_comparison_op = tuple(opts) + pred = misc.reverse_operands(operator.contains) + + if isinstance(inst, (tuple, list)): + inst = inst[0] + attribute_value = getattr(inst, attribute, 'Attribute not found') + if attribute_value is None: + attribute_value = () + if inst is None: + # nothing was activated by the Given criteria + yield ValidationOutcome(inst=inst, severity=OutcomeSeverity.EXECUTED) + elif not pred(attribute_value, value_or_comparison_op): + yield ValidationOutcome( + inst=inst, + expected=None if not value_or_comparison_op else value_or_comparison_op, + observed=misc.recursive_unpack_value(attribute_value), + severity=OutcomeSeverity.ERROR + ) @gherkin_ifc.step('The {field} of the {file_or_model} must be "{values}"') def step_impl(context, inst, field, file_or_model, values): @@ -143,169 +230,3 @@ def step_impl(context, inst): invalid_guid_chars = [char for char in inst if char not in valid_chars] if invalid_guid_chars: yield ValidationOutcome(inst=inst, expected="^[0-9A-Za-z_$]+$", observed=invalid_guid_chars, severity=OutcomeSeverity.ERROR) - - -@gherkin_ifc.step('{attribute_compared} value must be {comparison_op} the expression: {expression}') -def step_impl(context, inst, attribute_compared:str, comparison_op:str, expression:str): - ''' - Compare a attribute to a expression based on attributes. - - The {comparison_op} operator can be 'equal to', 'not equal to', 'greater than', 'less than', 'greater than or equal to', and 'less than or equal to'. - - The {expression} should be composed by attribute values, and use the following operators: - + : addition; - - : subtraction; - * : multiplication; - / : division; - % : modulus; - ** : exponentiation.''' - - operators = { - '+' : operator.add, - '-' : operator.sub, - '*' : operator.mul, - '/' : operator.truediv, - '%' : operator.mod, - '**' : operator.pow, - 'equal to' : operator.eq, - 'not equal to' : operator.ne, - 'greater than' : operator.gt, - 'less than' : operator.gt, - 'greater than or equal to' : operator.ge, - 'less than or equal to' : operator.le, - } - - # Get compared attribute value - - attr_compared_value = getattr(inst, attribute_compared, 'Compared attribute not found') - if isinstance(attr_compared_value, ifcopenshell.entity_instance): - raise Exception('Compared attribute value is an IFC entity') - - # Replace attribute names with attribute values in the expression - for string in expression.split(): - # Checks if the string is not a operator neither parenthesis - if string not in [*operators, '(', ')']: - if hasattr(inst, string): - if not isinstance(getattr(inst, string), ifcopenshell.entity_instance): - expression = expression.replace(string, str(getattr(inst, string))) - else: - raise Exception('Expression attribute value is an IFC entity') - else: - raise Exception('Expression attribute not found') - - # Evaluate the string expression using eval - try: - expression_value = eval(expression) - except Exception as e: - raise ValueError(f"Error evaluating expression: {e}") - - # Compare the attribute with the expression value, considering the precision - entity_contexts = geometry.recurrently_get_entity_attr(context, inst, 'IfcRepresentation', 'ContextOfItems') - precision = geometry.get_precision_from_contexts(entity_contexts) - - try: - result = geometry.compare_with_precision(attr_compared_value, expression_value, precision, comparison_op) - if result: - yield ValidationOutcome( - inst=inst, - expected=f"A value {comparison_op} {expression_value} with precision {precision}", - observed={attr_compared_value}, - severity=OutcomeSeverity.PASSED, - ) - else: - yield ValidationOutcome( - inst=inst, - expected=f"A value {comparison_op} {expression_value}", - observed={attr_compared_value}, - severity=OutcomeSeverity.ERROR, - ) - except ValueError as e: - raise ValueError(f"Error during comparison: {e}") - -@gherkin_ifc.step('First instance {first_expression} value must be {comparison_op} the second instance {second_expression}') -@gherkin_ifc.step('First instance {first_expression} value must be {comparison_op} the second instance {second_expression} at depth 1') -def step_impl(context, inst, first_expression:str, comparison_op:str, second_expression:str): - ''' - Compare expressions based on attributes from two different instances. - - The {comparison_op} operator can be 'equal to', 'not equal to', 'greater than', 'less than', 'greater than or equal to', and 'less than or equal to'. - - The {expression} should be composed by attribute values, and use the following operators: - + : addition; - - : subtraction; - * : multiplication; - / : division; - % : modulus; - ** : exponentiation.''' - - operators = { - '+' : operator.add, - '-' : operator.sub, - '*' : operator.mul, - '/' : operator.truediv, - '%' : operator.mod, - '**' : operator.pow, - 'equal to' : operator.eq, - 'not equal to' : operator.ne, - 'greater than' : operator.gt, - 'less than' : operator.gt, - 'greater than or equal to' : operator.ge, - 'less than or equal to' : operator.le, - } - - # Get both instances - first_instance, second_instance = inst[0], inst[1] - - # Replace attribute names with attribute values in the expression of the first instance - for string in first_expression.split(): - # Checks if the string is not a operator neither parenthesis - if string not in [*operators, '(', ')']: - if hasattr(first_instance, string): - if not isinstance(getattr(first_instance, string), ifcopenshell.entity_instance): - first_expression = first_expression.replace(string, str(getattr(first_instance, string))) - else: - raise Exception('Expression attribute value is an IFC entity') - else: - raise Exception('Expression attribute not found') - - # Replace attribute names with attribute values in the expression of the second instance - for string in second_expression.split(): - # Checks if the string is not a operator neither parenthesis - if string not in [*operators, '(', ')']: - if hasattr(second_instance, string): - if not isinstance(getattr(second_instance, string), ifcopenshell.entity_instance): - second_expression = second_expression.replace(string, str(getattr(second_instance, string))) - else: - raise Exception('Expression attribute value is an IFC entity') - else: - raise Exception('Expression attribute not found') - - # Evaluate the string expressions using eval - try: - first_expression_value = eval(first_expression) - second_expression_value = eval(second_expression) - except Exception as e: - raise ValueError(f"Error evaluating expression: {e}") - - # Compare the attribute with the expression value, considering the precision - entity_contexts = geometry.recurrently_get_entity_attr(context, inst, 'IfcRepresentation', 'ContextOfItems') - precision = geometry.get_precision_from_contexts(entity_contexts) - - try: - result = geometry.compare_with_precision(first_expression_value, second_expression_value, precision, comparison_op) - if result: - yield ValidationOutcome( - inst=inst, - expected=f"A value {comparison_op} {second_expression_value} with precision {precision}", - observed=first_expression_value, - severity=OutcomeSeverity.PASSED, - ) - else: - yield ValidationOutcome( - inst=inst, - expected=f"A value {comparison_op} {second_expression_value}", - observed={first_expression_value}, - severity=OutcomeSeverity.ERROR, - ) - except ValueError as e: - raise ValueError(f"Error during comparison: {e}") \ No newline at end of file diff --git a/test/files/alb012/na-alb012-incorrect_type_for_DesignParameters_attribute.ifc b/test/files/alb012/na-alb012-incorrect_type_for_DesignParameters_attribute.ifc new file mode 100644 index 00000000..6570eda2 --- /dev/null +++ b/test/files/alb012/na-alb012-incorrect_type_for_DesignParameters_attribute.ifc @@ -0,0 +1,303 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); +FILE_NAME('na-alb012-incorrect_type_for_DesignParameters_attribute.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_SCHEMA(('IFC4X3_ADD2')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,'',$,$,$,$,$); +#2=IFCORGANIZATION('redacted','redacted',$,(#18),$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +#4=IFCAPPLICATION(#2,'redacted','redacted','redacted'); +#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,1721342253,#3,#4,1721342253); +#6=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#7=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#8=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#9=IFCUNITASSIGNMENT((#7,#8)); +#10=IFCPROJECT('2NKwV2qd55_Ou$L3sGEcJ5',#5,'Unnamed Bridge Project',$,$,$,$,(#34),#9); +#11=IFCDIRECTION((1.,0.,0.)); +#12=IFCDIRECTION((0.,0.,1.)); +#13=IFCCARTESIANPOINT((0.,0.,0.)); +#14=IFCAXIS2PLACEMENT3D(#13,#12,#11); +#15=IFCLOCALPLACEMENT($,#14); +#16=IFCSITE('1bkdwWptL9p8EOgG7oGLm8',#5,'Site of Unnamed Bridge',$,$,#15,$,$,.ELEMENT.,$,$,$,$,$); +#17=IFCRELAGGREGATES('2OyduV47v3MfrT$j43zMqR',#5,$,$,#10,(#16)); +#18=IFCACTORROLE(.CIVILENGINEER.,$,$); +#19=IFCPROPERTYENUMERATION('PEnum_ProjectType',(IFCLABEL('MODIFICATION'),IFCLABEL('NEWBUILD'),IFCLABEL('OPERATIONMAINTENANCE'),IFCLABEL('RENOVATION'),IFCLABEL('REPAIR')),$); +#20=IFCPROPERTYENUMERATEDVALUE('ProjectType',$,(IFCLABEL('NEWBUILD')),#19); +#21=IFCPROPERTYSET('20vQbRVmnED8iLLqekYzX1',$,'Pset_ProjectCommon',$,(#20)); +#22=IFCRELDEFINESBYPROPERTIES('1U4REvlNHDgv01F5_XE5w9',$,$,$,(#10),#21); +#23=IFCPROPERTYSINGLEVALUE('ContractNumber',$,IFCLABEL('Unknown'),$); +#24=IFCPROPERTYSINGLEVALUE('DesignNumber',$,IFCLABEL('Unknown'),$); +#25=IFCPROPERTYSINGLEVALUE('ProjectNumber',$,IFCLABEL('Unknown'),$); +#26=IFCPROPERTYSINGLEVALUE('ProjectWebsite',$,IFCLABEL('Unknown'),$); +#27=IFCPROPERTYSET('38HZ$LnA18KP01_4uL6vpy',$,'AASHTO_ProjectCommon',$,(#23,#24,#25,#26)); +#28=IFCRELDEFINESBYPROPERTIES('0SVmDQPaH0v993Ve$aV21O',$,$,$,(#10),#27); +#29=IFCDIRECTION((0.,1.)); +#30=IFCDIRECTION((1.,0.,0.)); +#31=IFCDIRECTION((0.,0.,1.)); +#32=IFCCARTESIANPOINT((0.,0.,0.)); +#33=IFCAXIS2PLACEMENT3D(#32,#31,#30); +#34=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#33,#29); +#35=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#34,$,.MODEL_VIEW.,$); +#36=IFCCARTESIANPOINT((152.4,762.)); +#37=IFCALIGNMENTHORIZONTALSEGMENT($,$,#36,5.70829809225671,0.,0.,596.427809947411,$,.LINE.); +#38=IFCALIGNMENTSEGMENT('1yKEFhEET3lxaALz5ILLKJ',$,'H1',$,$,#217,#219,#37); +#39=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#40=IFCAXIS2PLACEMENT2D(#36,#39); +#41=IFCCARTESIANPOINT((0.,0.)); +#42=IFCDIRECTION((1.,0.)); +#43=IFCVECTOR(#42,1.); +#44=IFCLINE(#41,#43); +#45=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#40,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(596.427809947411),#44); +#46=IFCCARTESIANPOINT((652.954206637821,437.698259801391)); +#47=IFCALIGNMENTHORIZONTALSEGMENT($,$,#46,5.70829809225671,304.8,304.8,584.978933611456,$,.CIRCULARARC.); +#48=IFCALIGNMENTSEGMENT('3bkfv7AiX7u8eHZy2v00yU',$,'H2',$,$,#217,#221,#47); +#49=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#50=IFCAXIS2PLACEMENT2D(#46,#49); +#51=IFCCARTESIANPOINT((0.,0.)); +#52=IFCDIRECTION((1.,0.)); +#53=IFCAXIS2PLACEMENT2D(#51,#52); +#54=IFCCIRCLE(#53,304.8); +#55=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#50,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(584.978933611456),#54); +#56=IFCCARTESIANPOINT((1115.70375380811,625.065837937277)); +#57=IFCALIGNMENTHORIZONTALSEGMENT($,$,#56,1.34433500821182,0.,0.,575.126530840636,$,.LINE.); +#58=IFCALIGNMENTSEGMENT('1y1cFxO7DCO8ifhYDB3kg5',$,'H3',$,$,#217,#223,#57); +#59=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#60=IFCAXIS2PLACEMENT2D(#56,#59); +#61=IFCCARTESIANPOINT((0.,0.)); +#62=IFCDIRECTION((1.,0.)); +#63=IFCVECTOR(#62,1.); +#64=IFCLINE(#61,#63); +#65=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#60,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(575.126530840636),#64); +#66=IFCCARTESIANPOINT((1244.83726354192,1185.50768428765)); +#67=IFCALIGNMENTHORIZONTALSEGMENT($,$,#66,1.34433500821182,-381.,-381.,563.305699668461,$,.CIRCULARARC.); +#68=IFCALIGNMENTSEGMENT('2ZhQROlxz9yvU3hgu8kF3y',$,'H4',$,$,#217,#225,#67); +#69=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#70=IFCAXIS2PLACEMENT2D(#66,#69); +#71=IFCCARTESIANPOINT((0.,0.)); +#72=IFCDIRECTION((1.,0.)); +#73=IFCAXIS2PLACEMENT2D(#71,#72); +#74=IFCCIRCLE(#73,381.); +#75=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#70,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-563.305699668461),#74); +#76=IFCCARTESIANPOINT((1667.0700765915,1477.5379910302)); +#77=IFCALIGNMENTHORIZONTALSEGMENT($,$,#76,6.14902766534295,0.,0.,476.89956141461,$,.LINE.); +#78=IFCALIGNMENTSEGMENT('1XuHWXwT969Q35ImfH0Ogg',$,'H5',$,$,#217,#227,#77); +#79=IFCDIRECTION((0.99101435288277,-0.133755569530191)); +#80=IFCAXIS2PLACEMENT2D(#76,#79); +#81=IFCCARTESIANPOINT((0.,0.)); +#82=IFCDIRECTION((1.,0.)); +#83=IFCVECTOR(#82,1.); +#84=IFCLINE(#81,#83); +#85=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#80,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(476.89956141461),#84); +#86=IFCCARTESIANPOINT((2139.68438683688,1413.75001858449)); +#87=IFCALIGNMENTHORIZONTALSEGMENT($,$,#86,6.14902766534296,-289.56,-289.56,319.772021994801,$,.CIRCULARARC.); +#88=IFCALIGNMENTSEGMENT('1WyDRQrLf4Pfa7hc66x7z4',$,'H6',$,$,#217,#229,#87); +#89=IFCDIRECTION((0.99101435288277,-0.13375556953019)); +#90=IFCAXIS2PLACEMENT2D(#86,#89); +#91=IFCCARTESIANPOINT((0.,0.)); +#92=IFCDIRECTION((1.,0.)); +#93=IFCAXIS2PLACEMENT2D(#91,#92); +#94=IFCCIRCLE(#93,289.56); +#95=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#90,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-319.772021994801),#94); +#96=IFCCARTESIANPOINT((2374.67351814968,1221.25187786577)); +#97=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); +#98=IFCALIGNMENTSEGMENT('2Gm5hd_S9FihJigptQqiqo',$,'H7',$,$,#217,#231,#97); +#99=IFCDIRECTION((0.447213595499958,-0.894427190999916)); +#100=IFCAXIS2PLACEMENT2D(#96,#99); +#101=IFCCARTESIANPOINT((0.,0.)); +#102=IFCDIRECTION((1.,0.)); +#103=IFCVECTOR(#102,1.); +#104=IFCLINE(#101,#103); +#105=IFCCURVESEGMENT(.DISCONTINUOUS.,#100,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#104); +#106=IFCALIGNMENTHORIZONTAL('2xHGSjSTHDOuz10zo9imZ$',$,'Horizontal Alignment',$,$,$,$); +#107=IFCRELNESTS('3mBmExvib60u04Ek8FIcUL',$,$,'Nests horizontal alignment segments with horizontal alignment',#106,(#38,#48,#58,#68,#78,#88,#98)); +#108=IFCCOMPOSITECURVE((#45,#55,#65,#75,#85,#95,#105),.F.); + +/* #109=IFCALIGNMENTVERTICALSEGMENT($,$,0.,365.76,30.48,0.0175,0.0175,$,.CONSTANTGRADIENT.); */ +#109=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#110=IFCALIGNMENTSEGMENT('0wiwmz1qT5CguAmO4rZfuD',$,'V1',$,$,#217,#233,#109); +#111=IFCCARTESIANPOINT((0.,30.48)); +#112=IFCDIRECTION((0.999846863274572,0.0175)); +#113=IFCAXIS2PLACEMENT2D(#111,#112); +#114=IFCCARTESIANPOINT((0.,0.)); +#115=IFCDIRECTION((1.,0.)); +#116=IFCVECTOR(#115,1.); +#117=IFCLINE(#114,#116); +#118=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#113,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#117); + +/* #119=IFCALIGNMENTVERTICALSEGMENT($,$,365.76,487.68,36.8808,0.0175,-0.01,-17733.81818,.PARABOLICARC.); */ +#119=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#120=IFCALIGNMENTSEGMENT('0GMpbyK7LAOhZ3MKPhlSDJ',$,'V2',$,$,#217,#235,#119); +#121=IFCCARTESIANPOINT((365.76,36.8808)); +#122=IFCDIRECTION((0.999846863274572,0.0175)); +#123=IFCAXIS2PLACEMENT2D(#121,#122); +#124=IFCCARTESIANPOINT((0.,0.)); +#125=IFCDIRECTION((1.,0.)); +#126=IFCAXIS2PLACEMENT2D(#124,#125); +#127=IFCPOLYNOMIALCURVE(#126,(0.,1.),(36.8808,0.0175,-2.8194717847769E-05),$); +#128=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#123,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.68),#127); + +/*#129=IFCALIGNMENTVERTICALSEGMENT($,$,853.440000000001,487.679999999999,38.7096,-0.01,-0.01,$,.CONSTANTGRADIENT.);*/ +#129=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#130=IFCALIGNMENTSEGMENT('3WSKXiwfv2AhAYT1b$NDBj',$,'V3',$,$,#217,#237,#129); +#131=IFCCARTESIANPOINT((853.440000000001,38.7096)); +#132=IFCDIRECTION((0.999949998749938,-0.01)); +#133=IFCAXIS2PLACEMENT2D(#131,#132); +#134=IFCCARTESIANPOINT((0.,0.)); +#135=IFCDIRECTION((1.,0.)); +#136=IFCVECTOR(#135,1.); +#137=IFCLINE(#134,#136); +#138=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#133,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.679999999999),#137); + +/*#139=IFCALIGNMENTVERTICALSEGMENT($,$,1341.12,365.76,33.8328,-0.01,0.02,12192.,.PARABOLICARC.);*/ +#139=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#140=IFCALIGNMENTSEGMENT('0f3kcHMir0A9axLpYF$KeL',$,'V4',$,$,#217,#239,#139); +#141=IFCCARTESIANPOINT((1341.12,33.8328)); +#142=IFCDIRECTION((0.999949998749938,-0.01)); +#143=IFCAXIS2PLACEMENT2D(#141,#142); +#144=IFCCARTESIANPOINT((0.,0.)); +#145=IFCDIRECTION((1.,0.)); +#146=IFCAXIS2PLACEMENT2D(#144,#145); +#147=IFCPOLYNOMIALCURVE(#146,(0.,1.),(33.8328,-0.01,4.1010498687664E-05),$); +#148=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#143,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#147); + +/*#149=IFCALIGNMENTVERTICALSEGMENT($,$,1706.88,243.84,35.6616,0.02,0.02,$,.CONSTANTGRADIENT.);*/ +#149=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#150=IFCALIGNMENTSEGMENT('1oYMRqw$r2aO6hIvJEhzgO',$,'V5',$,$,#217,#241,#149); +#151=IFCCARTESIANPOINT((1706.88,35.6616)); +#152=IFCDIRECTION((0.999799979995999,0.02)); +#153=IFCAXIS2PLACEMENT2D(#151,#152); +#154=IFCCARTESIANPOINT((0.,0.)); +#155=IFCDIRECTION((1.,0.)); +#156=IFCVECTOR(#155,1.); +#157=IFCLINE(#154,#156); +#158=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#153,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#157); + +/*#159=IFCALIGNMENTVERTICALSEGMENT($,$,1950.72,609.6,40.5384,0.02,-0.02,-15240.,.PARABOLICARC.);*/ +#159=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#160=IFCALIGNMENTSEGMENT('2rmRh3RID4Dx1Xv2vdnAcV',$,'V6',$,$,#217,#243,#159); +#161=IFCCARTESIANPOINT((1950.72,40.5384)); +#162=IFCDIRECTION((0.999799979995999,0.02)); +#163=IFCAXIS2PLACEMENT2D(#161,#162); +#164=IFCCARTESIANPOINT((0.,0.)); +#165=IFCDIRECTION((1.,0.)); +#166=IFCAXIS2PLACEMENT2D(#164,#165); +#167=IFCPOLYNOMIALCURVE(#166,(0.,1.),(40.5384,0.02,-3.28083989501312E-05),$); +#168=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#163,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(609.6),#167); + +/*#169=IFCALIGNMENTVERTICALSEGMENT($,$,2560.32,304.799999999999,40.5384,-0.02,-0.02,$,.CONSTANTGRADIENT.);*/ +#169=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#170=IFCALIGNMENTSEGMENT('2kGQnCzmbB1hLZpc8B8fx7',$,'V7',$,$,#217,#245,#169); +#171=IFCCARTESIANPOINT((2560.32,40.5384)); +#172=IFCDIRECTION((0.999799979995999,-0.02)); +#173=IFCAXIS2PLACEMENT2D(#171,#172); +#174=IFCCARTESIANPOINT((0.,0.)); +#175=IFCDIRECTION((1.,0.)); +#176=IFCVECTOR(#175,1.); +#177=IFCLINE(#174,#176); +#178=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#173,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(304.799999999999),#177); + +/*#179=IFCALIGNMENTVERTICALSEGMENT($,$,2865.12,243.84,34.4424,-0.02,-0.005,16256.,.PARABOLICARC.);*/ +#179=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#180=IFCALIGNMENTSEGMENT('3hljyR0Hr0$hbnPws3P554',$,'V8',$,$,#217,#247,#179); +#181=IFCCARTESIANPOINT((2865.12,34.4424)); +#182=IFCDIRECTION((0.999799979995999,-0.02)); +#183=IFCAXIS2PLACEMENT2D(#181,#182); +#184=IFCCARTESIANPOINT((0.,0.)); +#185=IFCDIRECTION((1.,0.)); +#186=IFCAXIS2PLACEMENT2D(#184,#185); +#187=IFCPOLYNOMIALCURVE(#186,(0.,1.),(34.4424,-0.02,3.0757874015748E-05),$); +#188=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#183,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#187); + +/*#189=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,7.55055747737515,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.);*/ +#189=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#190=IFCALIGNMENTSEGMENT('0Yj$$A801BgAySuKuq8FH1',$,'V9',$,$,#217,#249,#189); +#191=IFCCARTESIANPOINT((3108.96,31.3944)); +#192=IFCDIRECTION((0.999987499921874,-0.005)); +#193=IFCAXIS2PLACEMENT2D(#191,#192); +#194=IFCCARTESIANPOINT((0.,0.)); +#195=IFCDIRECTION((1.,0.)); +#196=IFCVECTOR(#195,1.); +#197=IFCLINE(#194,#196); +#198=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#193,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(7.55055747737515),#197); + +/*#199=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,0.,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.);*/ +#199=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); + +#200=IFCALIGNMENTSEGMENT('0FSjBm0hj8PwKhufHaF1ZA',$,'V10',$,$,#217,#251,#199); +#201=IFCCARTESIANPOINT((3108.96,31.3944)); +#202=IFCDIRECTION((0.999987499921874,-0.005)); +#203=IFCAXIS2PLACEMENT2D(#201,#202); +#204=IFCCARTESIANPOINT((0.,0.)); +#205=IFCDIRECTION((1.,0.)); +#206=IFCVECTOR(#205,1.); +#207=IFCLINE(#204,#206); +#208=IFCCURVESEGMENT(.DISCONTINUOUS.,#203,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#207); +#209=IFCALIGNMENTVERTICAL('2nEoeLO$jCAgLWqX3ZS4ZL',$,'Vertical Alignment',$,$,#15,$); +#210=IFCRELNESTS('1Zi6YpAun30A67NCfsmR6h',$,$,'Nests vertical alignment segments with vertical alignment',#209,(#110,#120,#130,#140,#150,#160,#170,#180,#190,#200)); +#211=IFCGRADIENTCURVE((#118,#128,#138,#148,#158,#168,#178,#188,#198,#208),.F.,#108,$); +#212=IFCSHAPEREPRESENTATION(#35,'Axis','Curve3D',(#211)); +#213=IFCDIRECTION((1.,0.,0.)); +#214=IFCDIRECTION((0.,0.,1.)); +#215=IFCCARTESIANPOINT((0.,0.,0.)); +#216=IFCAXIS2PLACEMENT3D(#215,#214,#213); +#217=IFCLOCALPLACEMENT($,#216); +#218=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#45)); +#219=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#218)); +#220=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#55)); +#221=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#220)); +#222=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#65)); +#223=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#222)); +#224=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#75)); +#225=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#224)); +#226=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#85)); +#227=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#226)); +#228=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#95)); +#229=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#228)); +#230=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#105)); +#231=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#230)); +#232=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#118)); +#233=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#232)); +#234=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#128)); +#235=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#234)); +#236=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#138)); +#237=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#236)); +#238=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#148)); +#239=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#238)); +#240=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#158)); +#241=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#240)); +#242=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#168)); +#243=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#242)); +#244=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#178)); +#245=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#244)); +#246=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#188)); +#247=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#246)); +#248=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#198)); +#249=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#248)); +#250=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#208)); +#251=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#250)); +#252=IFCPRODUCTDEFINITIONSHAPE('Alignment Product Definition Shape',$,(#212)); +#253=IFCALIGNMENT('0qKahqjPjBeuEjpOKkk23s',$,'Unnamed alignment',$,$,#15,#252,$); +#254=IFCRELNESTS('3p2wDzu0r4qBoQ$kirOpI9',$,'Nest horizontal and vertical alignment layouts with the alignment',$,#253,(#106,#209)); +#255=IFCRELAGGREGATES('1K9FW2VIP3Uf303$idpLPY',$,'Alignments in project',$,#10,(#253)); +#256=IFCRELREFERENCEDINSPATIALSTRUCTURE('10jns2II51eA4MvJstMUh6',$,$,$,(#253),#16); +#257=IFCPROPERTYSINGLEVALUE('Station',$,IFCLENGTHMEASURE(3048.),$); +#258=IFCPROPERTYSET('0ykDGVR8D9JvgG2BE$m9Y0',$,'Pset_Stationing',$,(#257)); +#259=IFCPOINTBYDISTANCEEXPRESSION(IFCLENGTHMEASURE(0.),$,$,$,#211); +#260=IFCAXIS2PLACEMENTLINEAR(#259,$,$); +#261=IFCLINEARPLACEMENT($,#260,$); +#262=IFCREFERENT('2MIQXRsdHE1ehEM_GIWxfu',$,'Start of alignment station',$,$,#261,$,.STATION.); +#263=IFCRELNESTS('0UMvxWgzT2mO2ObhWRe5TZ',$,'Nests Referents with station information with alignment',$,#253,(#262)); +#264=IFCRELDEFINESBYPROPERTIES('3SkNbYBX97uBNi5kNrE0qi',$,'Relates station properties to referent',$,(#262),#258); +ENDSEC; +END-ISO-10303-21; diff --git a/test/files/alb012/na-alb012-no_vertical_layout.ifc b/test/files/alb012/na-alb012-no_vertical_layout.ifc new file mode 100644 index 00000000..19bb8bd7 --- /dev/null +++ b/test/files/alb012/na-alb012-no_vertical_layout.ifc @@ -0,0 +1,153 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); +FILE_NAME('na-alb012-no_vertical_layout.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_SCHEMA(('IFC4X3_ADD2')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,'',$,$,$,$,$); +#2=IFCORGANIZATION('redacted','redacted',$,(#18),$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +#4=IFCAPPLICATION(#2,'redacted','redacted','redacted'); +#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,1721342253,#3,#4,1721342253); +#6=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#7=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#8=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#9=IFCUNITASSIGNMENT((#7,#8)); +#10=IFCPROJECT('2NKwV2qd55_Ou$L3sGEcJ5',#5,'Unnamed Bridge Project',$,$,$,$,(#34),#9); +#11=IFCDIRECTION((1.,0.,0.)); +#12=IFCDIRECTION((0.,0.,1.)); +#13=IFCCARTESIANPOINT((0.,0.,0.)); +#14=IFCAXIS2PLACEMENT3D(#13,#12,#11); +#15=IFCLOCALPLACEMENT($,#14); +#16=IFCSITE('1bkdwWptL9p8EOgG7oGLm8',#5,'Site of Unnamed Bridge',$,$,#15,$,$,.ELEMENT.,$,$,$,$,$); +#17=IFCRELAGGREGATES('2OyduV47v3MfrT$j43zMqR',#5,$,$,#10,(#16)); +#18=IFCACTORROLE(.CIVILENGINEER.,$,$); +#19=IFCPROPERTYENUMERATION('PEnum_ProjectType',(IFCLABEL('MODIFICATION'),IFCLABEL('NEWBUILD'),IFCLABEL('OPERATIONMAINTENANCE'),IFCLABEL('RENOVATION'),IFCLABEL('REPAIR')),$); +#20=IFCPROPERTYENUMERATEDVALUE('ProjectType',$,(IFCLABEL('NEWBUILD')),#19); +#21=IFCPROPERTYSET('20vQbRVmnED8iLLqekYzX1',$,'Pset_ProjectCommon',$,(#20)); +#22=IFCRELDEFINESBYPROPERTIES('1U4REvlNHDgv01F5_XE5w9',$,$,$,(#10),#21); +#23=IFCPROPERTYSINGLEVALUE('ContractNumber',$,IFCLABEL('Unknown'),$); +#24=IFCPROPERTYSINGLEVALUE('DesignNumber',$,IFCLABEL('Unknown'),$); +#25=IFCPROPERTYSINGLEVALUE('ProjectNumber',$,IFCLABEL('Unknown'),$); +#26=IFCPROPERTYSINGLEVALUE('ProjectWebsite',$,IFCLABEL('Unknown'),$); +#27=IFCPROPERTYSET('38HZ$LnA18KP01_4uL6vpy',$,'AASHTO_ProjectCommon',$,(#23,#24,#25,#26)); +#28=IFCRELDEFINESBYPROPERTIES('0SVmDQPaH0v993Ve$aV21O',$,$,$,(#10),#27); +#29=IFCDIRECTION((0.,1.)); +#30=IFCDIRECTION((1.,0.,0.)); +#31=IFCDIRECTION((0.,0.,1.)); +#32=IFCCARTESIANPOINT((0.,0.,0.)); +#33=IFCAXIS2PLACEMENT3D(#32,#31,#30); +#34=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#33,#29); +#35=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#34,$,.MODEL_VIEW.,$); +#36=IFCCARTESIANPOINT((152.4,762.)); +#37=IFCALIGNMENTHORIZONTALSEGMENT($,$,#36,5.70829809225671,0.,0.,596.427809947411,$,.LINE.); +#38=IFCALIGNMENTSEGMENT('1yKEFhEET3lxaALz5ILLKJ',$,'H1',$,$,#217,#219,#37); +#39=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#40=IFCAXIS2PLACEMENT2D(#36,#39); +#41=IFCCARTESIANPOINT((0.,0.)); +#42=IFCDIRECTION((1.,0.)); +#43=IFCVECTOR(#42,1.); +#44=IFCLINE(#41,#43); +#45=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#40,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(596.427809947411),#44); +#46=IFCCARTESIANPOINT((652.954206637821,437.698259801391)); +#47=IFCALIGNMENTHORIZONTALSEGMENT($,$,#46,5.70829809225671,304.8,304.8,584.978933611456,$,.CIRCULARARC.); +#48=IFCALIGNMENTSEGMENT('3bkfv7AiX7u8eHZy2v00yU',$,'H2',$,$,#217,#221,#47); +#49=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#50=IFCAXIS2PLACEMENT2D(#46,#49); +#51=IFCCARTESIANPOINT((0.,0.)); +#52=IFCDIRECTION((1.,0.)); +#53=IFCAXIS2PLACEMENT2D(#51,#52); +#54=IFCCIRCLE(#53,304.8); +#55=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#50,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(584.978933611456),#54); +#56=IFCCARTESIANPOINT((1115.70375380811,625.065837937277)); +#57=IFCALIGNMENTHORIZONTALSEGMENT($,$,#56,1.34433500821182,0.,0.,575.126530840636,$,.LINE.); +#58=IFCALIGNMENTSEGMENT('1y1cFxO7DCO8ifhYDB3kg5',$,'H3',$,$,#217,#223,#57); +#59=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#60=IFCAXIS2PLACEMENT2D(#56,#59); +#61=IFCCARTESIANPOINT((0.,0.)); +#62=IFCDIRECTION((1.,0.)); +#63=IFCVECTOR(#62,1.); +#64=IFCLINE(#61,#63); +#65=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#60,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(575.126530840636),#64); +#66=IFCCARTESIANPOINT((1244.83726354192,1185.50768428765)); +#67=IFCALIGNMENTHORIZONTALSEGMENT($,$,#66,1.34433500821182,-381.,-381.,563.305699668461,$,.CIRCULARARC.); +#68=IFCALIGNMENTSEGMENT('2ZhQROlxz9yvU3hgu8kF3y',$,'H4',$,$,#217,#225,#67); +#69=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#70=IFCAXIS2PLACEMENT2D(#66,#69); +#71=IFCCARTESIANPOINT((0.,0.)); +#72=IFCDIRECTION((1.,0.)); +#73=IFCAXIS2PLACEMENT2D(#71,#72); +#74=IFCCIRCLE(#73,381.); +#75=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#70,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-563.305699668461),#74); +#76=IFCCARTESIANPOINT((1667.0700765915,1477.5379910302)); +#77=IFCALIGNMENTHORIZONTALSEGMENT($,$,#76,6.14902766534295,0.,0.,476.89956141461,$,.LINE.); +#78=IFCALIGNMENTSEGMENT('1XuHWXwT969Q35ImfH0Ogg',$,'H5',$,$,#217,#227,#77); +#79=IFCDIRECTION((0.99101435288277,-0.133755569530191)); +#80=IFCAXIS2PLACEMENT2D(#76,#79); +#81=IFCCARTESIANPOINT((0.,0.)); +#82=IFCDIRECTION((1.,0.)); +#83=IFCVECTOR(#82,1.); +#84=IFCLINE(#81,#83); +#85=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#80,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(476.89956141461),#84); +#86=IFCCARTESIANPOINT((2139.68438683688,1413.75001858449)); +#87=IFCALIGNMENTHORIZONTALSEGMENT($,$,#86,6.14902766534296,-289.56,-289.56,319.772021994801,$,.CIRCULARARC.); +#88=IFCALIGNMENTSEGMENT('1WyDRQrLf4Pfa7hc66x7z4',$,'H6',$,$,#217,#229,#87); +#89=IFCDIRECTION((0.99101435288277,-0.13375556953019)); +#90=IFCAXIS2PLACEMENT2D(#86,#89); +#91=IFCCARTESIANPOINT((0.,0.)); +#92=IFCDIRECTION((1.,0.)); +#93=IFCAXIS2PLACEMENT2D(#91,#92); +#94=IFCCIRCLE(#93,289.56); +#95=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#90,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-319.772021994801),#94); +#96=IFCCARTESIANPOINT((2374.67351814968,1221.25187786577)); +#97=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); +#98=IFCALIGNMENTSEGMENT('2Gm5hd_S9FihJigptQqiqo',$,'H7',$,$,#217,#231,#97); +#99=IFCDIRECTION((0.447213595499958,-0.894427190999916)); +#100=IFCAXIS2PLACEMENT2D(#96,#99); +#101=IFCCARTESIANPOINT((0.,0.)); +#102=IFCDIRECTION((1.,0.)); +#103=IFCVECTOR(#102,1.); +#104=IFCLINE(#101,#103); +#105=IFCCURVESEGMENT(.DISCONTINUOUS.,#100,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#104); +#106=IFCALIGNMENTHORIZONTAL('2xHGSjSTHDOuz10zo9imZ$',$,'Horizontal Alignment',$,$,$,$); +#107=IFCRELNESTS('3mBmExvib60u04Ek8FIcUL',$,$,'Nests horizontal alignment segments with horizontal alignment',#106,(#38,#48,#58,#68,#78,#88,#98)); +#108=IFCCOMPOSITECURVE((#45,#55,#65,#75,#85,#95,#105),.F.); + +#212=IFCSHAPEREPRESENTATION(#35,'FootPrint','Curve2D',(#108)); +#213=IFCDIRECTION((1.,0.,0.)); +#214=IFCDIRECTION((0.,0.,1.)); +#215=IFCCARTESIANPOINT((0.,0.,0.)); +#216=IFCAXIS2PLACEMENT3D(#215,#214,#213); +#217=IFCLOCALPLACEMENT($,#216); +#218=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#45)); +#219=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#218)); +#220=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#55)); +#221=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#220)); +#222=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#65)); +#223=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#222)); +#224=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#75)); +#225=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#224)); +#226=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#85)); +#227=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#226)); +#228=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#95)); +#229=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#228)); +#230=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#105)); +#231=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#230)); + +#252=IFCPRODUCTDEFINITIONSHAPE('Alignment Product Definition Shape',$,(#212)); +#253=IFCALIGNMENT('0qKahqjPjBeuEjpOKkk23s',$,'Unnamed alignment',$,$,#15,#252,$); +#254=IFCRELNESTS('3p2wDzu0r4qBoQ$kirOpI9',$,'Nest horizontal alignment layout with the alignment',$,#253,(#106)); + +#255=IFCRELAGGREGATES('1K9FW2VIP3Uf303$idpLPY',$,'Alignments in project',$,#10,(#253)); +#256=IFCRELREFERENCEDINSPATIALSTRUCTURE('10jns2II51eA4MvJstMUh6',$,$,$,(#253),#16); +#257=IFCPROPERTYSINGLEVALUE('Station',$,IFCLENGTHMEASURE(3048.),$); +#258=IFCPROPERTYSET('0ykDGVR8D9JvgG2BE$m9Y0',$,'Pset_Stationing',$,(#257)); +#259=IFCPOINTBYDISTANCEEXPRESSION(IFCLENGTHMEASURE(0.),$,$,$,#108); +#260=IFCAXIS2PLACEMENTLINEAR(#259,$,$); +#261=IFCLINEARPLACEMENT($,#260,$); +#262=IFCREFERENT('2MIQXRsdHE1ehEM_GIWxfu',$,'Start of alignment station',$,$,#261,$,.STATION.); +#263=IFCRELNESTS('0UMvxWgzT2mO2ObhWRe5TZ',$,'Nests Referents with station information with alignment',$,#253,(#262)); +#264=IFCRELDEFINESBYPROPERTIES('3SkNbYBX97uBNi5kNrE0qi',$,'Relates station properties to referent',$,(#262),#258); +ENDSEC; +END-ISO-10303-21; From 515cc490c25ee619937491a4ba1ed0b76103f20c Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Sat, 12 Oct 2024 10:48:21 -0400 Subject: [PATCH 11/17] add explicit relative tolerance for value comparisons (IVS-137) --- features/steps/utils/geometry.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/features/steps/utils/geometry.py b/features/steps/utils/geometry.py index f1621912..2fc265bb 100644 --- a/features/steps/utils/geometry.py +++ b/features/steps/utils/geometry.py @@ -224,8 +224,9 @@ def alignment_segment_angular_difference( return delta -def compare_with_precision(value_1, value_2, precision, comparison_operator): - '''Compare the value_1 with value_2 according to a comparison operator, considering a precision tolerance. +def compare_with_precision(value_1: float, value_2: float, precision: float, comparison_operator: str) -> bool: + """ + Compare the value_1 with value_2 according to a comparison operator, considering a precision tolerance. The valid comparison operators are: 'equal to'; @@ -234,18 +235,18 @@ def compare_with_precision(value_1, value_2, precision, comparison_operator): 'less than'; 'greater than or equal to'; 'less than or equal to'. - ''' + """ if comparison_operator == 'equal to': - return math.isclose(value_1, value_2, abs_tol=precision) + return math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) elif comparison_operator == 'not equal to': - return not math.isclose(value_1, value_2, abs_tol=precision) + return not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) elif comparison_operator == 'greater than': - return value_1 > value_2 and not math.isclose(value_1, value_2, abs_tol=precision) + return value_1 > value_2 and not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) elif comparison_operator == 'less than': - return value_1 < value_2 and not math.isclose(value_1, value_2, abs_tol=precision) + return value_1 < value_2 and not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) elif comparison_operator == 'greater than or equal to': - return value_1 > value_2 or math.isclose(value_1, value_2, abs_tol=precision) + return value_1 > value_2 or math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) elif comparison_operator == 'less than or equal to': - return value_1 < value_2 or math.isclose(value_1, value_2, abs_tol=precision) + return value_1 < value_2 or math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) else: raise ValueError(f"Invalid comparison operator: {comparison_operator}") \ No newline at end of file From 42959f2d1b1d4defcd6fa8ec592eddb4a4f63977 Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Sat, 12 Oct 2024 11:18:24 -0400 Subject: [PATCH 12/17] add unit test file that raises ZeroDivisionError (IVS-137) --- ...2-equal_gradients_parabolic_curve_type.ifc | 273 ++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 test/files/alb012/pass-alb012-equal_gradients_parabolic_curve_type.ifc diff --git a/test/files/alb012/pass-alb012-equal_gradients_parabolic_curve_type.ifc b/test/files/alb012/pass-alb012-equal_gradients_parabolic_curve_type.ifc new file mode 100644 index 00000000..b7c20bdf --- /dev/null +++ b/test/files/alb012/pass-alb012-equal_gradients_parabolic_curve_type.ifc @@ -0,0 +1,273 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[Alignment-basedReferenceView]'),'2;1'); +FILE_NAME('pass-alb012-correct_radius_parabolic_curve_type.ifc','2024-07-18T15:37:33',('redacted'),('redacted'),'redacted','redacted',''); +FILE_SCHEMA(('IFC4X3_ADD2')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,'',$,$,$,$,$); +#2=IFCORGANIZATION('redacted','redacted',$,(#18),$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +#4=IFCAPPLICATION(#2,'redacted','redacted','redacted'); +#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,1721342253,#3,#4,1721342253); +#6=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#7=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.); +#8=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); +#9=IFCUNITASSIGNMENT((#7,#8)); +#10=IFCPROJECT('2NKwV2qd55_Ou$L3sGEcJ5',#5,'Unnamed Bridge Project',$,$,$,$,(#34),#9); +#11=IFCDIRECTION((1.,0.,0.)); +#12=IFCDIRECTION((0.,0.,1.)); +#13=IFCCARTESIANPOINT((0.,0.,0.)); +#14=IFCAXIS2PLACEMENT3D(#13,#12,#11); +#15=IFCLOCALPLACEMENT($,#14); +#16=IFCSITE('1bkdwWptL9p8EOgG7oGLm8',#5,'Site of Unnamed Bridge',$,$,#15,$,$,.ELEMENT.,$,$,$,$,$); +#17=IFCRELAGGREGATES('2OyduV47v3MfrT$j43zMqR',#5,$,$,#10,(#16)); +#18=IFCACTORROLE(.CIVILENGINEER.,$,$); +#19=IFCPROPERTYENUMERATION('PEnum_ProjectType',(IFCLABEL('MODIFICATION'),IFCLABEL('NEWBUILD'),IFCLABEL('OPERATIONMAINTENANCE'),IFCLABEL('RENOVATION'),IFCLABEL('REPAIR')),$); +#20=IFCPROPERTYENUMERATEDVALUE('ProjectType',$,(IFCLABEL('NEWBUILD')),#19); +#21=IFCPROPERTYSET('20vQbRVmnED8iLLqekYzX1',$,'Pset_ProjectCommon',$,(#20)); +#22=IFCRELDEFINESBYPROPERTIES('1U4REvlNHDgv01F5_XE5w9',$,$,$,(#10),#21); +#23=IFCPROPERTYSINGLEVALUE('ContractNumber',$,IFCLABEL('Unknown'),$); +#24=IFCPROPERTYSINGLEVALUE('DesignNumber',$,IFCLABEL('Unknown'),$); +#25=IFCPROPERTYSINGLEVALUE('ProjectNumber',$,IFCLABEL('Unknown'),$); +#26=IFCPROPERTYSINGLEVALUE('ProjectWebsite',$,IFCLABEL('Unknown'),$); +#27=IFCPROPERTYSET('38HZ$LnA18KP01_4uL6vpy',$,'AASHTO_ProjectCommon',$,(#23,#24,#25,#26)); +#28=IFCRELDEFINESBYPROPERTIES('0SVmDQPaH0v993Ve$aV21O',$,$,$,(#10),#27); +#29=IFCDIRECTION((0.,1.)); +#30=IFCDIRECTION((1.,0.,0.)); +#31=IFCDIRECTION((0.,0.,1.)); +#32=IFCCARTESIANPOINT((0.,0.,0.)); +#33=IFCAXIS2PLACEMENT3D(#32,#31,#30); +#34=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#33,#29); +#35=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#34,$,.MODEL_VIEW.,$); +#36=IFCCARTESIANPOINT((152.4,762.)); +#37=IFCALIGNMENTHORIZONTALSEGMENT($,$,#36,5.70829809225671,0.,0.,596.427809947411,$,.LINE.); +#38=IFCALIGNMENTSEGMENT('1yKEFhEET3lxaALz5ILLKJ',$,'H1',$,$,#217,#219,#37); +#39=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#40=IFCAXIS2PLACEMENT2D(#36,#39); +#41=IFCCARTESIANPOINT((0.,0.)); +#42=IFCDIRECTION((1.,0.)); +#43=IFCVECTOR(#42,1.); +#44=IFCLINE(#41,#43); +#45=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#40,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(596.427809947411),#44); +#46=IFCCARTESIANPOINT((652.954206637821,437.698259801391)); +#47=IFCALIGNMENTHORIZONTALSEGMENT($,$,#46,5.70829809225671,304.8,304.8,584.978933611456,$,.CIRCULARARC.); +#48=IFCALIGNMENTSEGMENT('3bkfv7AiX7u8eHZy2v00yU',$,'H2',$,$,#217,#221,#47); +#49=IFCDIRECTION((0.839253633531872,-0.543740138856375)); +#50=IFCAXIS2PLACEMENT2D(#46,#49); +#51=IFCCARTESIANPOINT((0.,0.)); +#52=IFCDIRECTION((1.,0.)); +#53=IFCAXIS2PLACEMENT2D(#51,#52); +#54=IFCCIRCLE(#53,304.8); +#55=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#50,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(584.978933611456),#54); +#56=IFCCARTESIANPOINT((1115.70375380811,625.065837937277)); +#57=IFCALIGNMENTHORIZONTALSEGMENT($,$,#56,1.34433500821182,0.,0.,575.126530840636,$,.LINE.); +#58=IFCALIGNMENTSEGMENT('1y1cFxO7DCO8ifhYDB3kg5',$,'H3',$,$,#217,#223,#57); +#59=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#60=IFCAXIS2PLACEMENT2D(#56,#59); +#61=IFCCARTESIANPOINT((0.,0.)); +#62=IFCDIRECTION((1.,0.)); +#63=IFCVECTOR(#62,1.); +#64=IFCLINE(#61,#63); +#65=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#60,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(575.126530840636),#64); +#66=IFCCARTESIANPOINT((1244.83726354192,1185.50768428765)); +#67=IFCALIGNMENTHORIZONTALSEGMENT($,$,#66,1.34433500821182,-381.,-381.,563.305699668461,$,.CIRCULARARC.); +#68=IFCALIGNMENTSEGMENT('2ZhQROlxz9yvU3hgu8kF3y',$,'H4',$,$,#217,#225,#67); +#69=IFCDIRECTION((0.22453060815167,0.974467036899166)); +#70=IFCAXIS2PLACEMENT2D(#66,#69); +#71=IFCCARTESIANPOINT((0.,0.)); +#72=IFCDIRECTION((1.,0.)); +#73=IFCAXIS2PLACEMENT2D(#71,#72); +#74=IFCCIRCLE(#73,381.); +#75=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#70,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-563.305699668461),#74); +#76=IFCCARTESIANPOINT((1667.0700765915,1477.5379910302)); +#77=IFCALIGNMENTHORIZONTALSEGMENT($,$,#76,6.14902766534295,0.,0.,476.89956141461,$,.LINE.); +#78=IFCALIGNMENTSEGMENT('1XuHWXwT969Q35ImfH0Ogg',$,'H5',$,$,#217,#227,#77); +#79=IFCDIRECTION((0.99101435288277,-0.133755569530191)); +#80=IFCAXIS2PLACEMENT2D(#76,#79); +#81=IFCCARTESIANPOINT((0.,0.)); +#82=IFCDIRECTION((1.,0.)); +#83=IFCVECTOR(#82,1.); +#84=IFCLINE(#81,#83); +#85=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#80,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(476.89956141461),#84); +#86=IFCCARTESIANPOINT((2139.68438683688,1413.75001858449)); +#87=IFCALIGNMENTHORIZONTALSEGMENT($,$,#86,6.14902766534296,-289.56,-289.56,319.772021994801,$,.CIRCULARARC.); +#88=IFCALIGNMENTSEGMENT('1WyDRQrLf4Pfa7hc66x7z4',$,'H6',$,$,#217,#229,#87); +#89=IFCDIRECTION((0.99101435288277,-0.13375556953019)); +#90=IFCAXIS2PLACEMENT2D(#86,#89); +#91=IFCCARTESIANPOINT((0.,0.)); +#92=IFCDIRECTION((1.,0.)); +#93=IFCAXIS2PLACEMENT2D(#91,#92); +#94=IFCCIRCLE(#93,289.56); +#95=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#90,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-319.772021994801),#94); +#96=IFCCARTESIANPOINT((2374.67351814968,1221.25187786577)); +#97=IFCALIGNMENTHORIZONTALSEGMENT($,$,#96,5.1760365893855,0.,0.,0.,$,.LINE.); +#98=IFCALIGNMENTSEGMENT('2Gm5hd_S9FihJigptQqiqo',$,'H7',$,$,#217,#231,#97); +#99=IFCDIRECTION((0.447213595499958,-0.894427190999916)); +#100=IFCAXIS2PLACEMENT2D(#96,#99); +#101=IFCCARTESIANPOINT((0.,0.)); +#102=IFCDIRECTION((1.,0.)); +#103=IFCVECTOR(#102,1.); +#104=IFCLINE(#101,#103); +#105=IFCCURVESEGMENT(.DISCONTINUOUS.,#100,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#104); +#106=IFCALIGNMENTHORIZONTAL('2xHGSjSTHDOuz10zo9imZ$',$,'Horizontal Alignment',$,$,$,$); +#107=IFCRELNESTS('3mBmExvib60u04Ek8FIcUL',$,$,'Nests horizontal alignment segments with horizontal alignment',#106,(#38,#48,#58,#68,#78,#88,#98)); +#108=IFCCOMPOSITECURVE((#45,#55,#65,#75,#85,#95,#105),.F.); +#109=IFCALIGNMENTVERTICALSEGMENT($,$,0.,365.76,30.48,0.0175,0.0175,$,.CONSTANTGRADIENT.); +#110=IFCALIGNMENTSEGMENT('0wiwmz1qT5CguAmO4rZfuD',$,'V1',$,$,#217,#233,#109); +#111=IFCCARTESIANPOINT((0.,30.48)); +#112=IFCDIRECTION((0.999846863274572,0.0175)); +#113=IFCAXIS2PLACEMENT2D(#111,#112); +#114=IFCCARTESIANPOINT((0.,0.)); +#115=IFCDIRECTION((1.,0.)); +#116=IFCVECTOR(#115,1.); +#117=IFCLINE(#114,#116); +#118=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#113,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#117); +#119=IFCALIGNMENTVERTICALSEGMENT($,$,365.76,487.68,36.8808,-0.01,-0.01,-17733.81818,.PARABOLICARC.); +#120=IFCALIGNMENTSEGMENT('0GMpbyK7LAOhZ3MKPhlSDJ',$,'V2',$,$,#217,#235,#119); +#121=IFCCARTESIANPOINT((365.76,36.8808)); +#122=IFCDIRECTION((0.999846863274572,0.0175)); +#123=IFCAXIS2PLACEMENT2D(#121,#122); +#124=IFCCARTESIANPOINT((0.,0.)); +#125=IFCDIRECTION((1.,0.)); +#126=IFCAXIS2PLACEMENT2D(#124,#125); +#127=IFCPOLYNOMIALCURVE(#126,(0.,1.),(36.8808,0.0175,-2.8194717847769E-05),$); +#128=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#123,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.68),#127); +#129=IFCALIGNMENTVERTICALSEGMENT($,$,853.440000000001,487.679999999999,38.7096,-0.01,-0.01,$,.CONSTANTGRADIENT.); +#130=IFCALIGNMENTSEGMENT('3WSKXiwfv2AhAYT1b$NDBj',$,'V3',$,$,#217,#237,#129); +#131=IFCCARTESIANPOINT((853.440000000001,38.7096)); +#132=IFCDIRECTION((0.999949998749938,-0.01)); +#133=IFCAXIS2PLACEMENT2D(#131,#132); +#134=IFCCARTESIANPOINT((0.,0.)); +#135=IFCDIRECTION((1.,0.)); +#136=IFCVECTOR(#135,1.); +#137=IFCLINE(#134,#136); +#138=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#133,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(487.679999999999),#137); +#139=IFCALIGNMENTVERTICALSEGMENT($,$,1341.12,365.76,33.8328,0.02,0.02,12192.,.PARABOLICARC.); +#140=IFCALIGNMENTSEGMENT('0f3kcHMir0A9axLpYF$KeL',$,'V4',$,$,#217,#239,#139); +#141=IFCCARTESIANPOINT((1341.12,33.8328)); +#142=IFCDIRECTION((0.999949998749938,-0.01)); +#143=IFCAXIS2PLACEMENT2D(#141,#142); +#144=IFCCARTESIANPOINT((0.,0.)); +#145=IFCDIRECTION((1.,0.)); +#146=IFCAXIS2PLACEMENT2D(#144,#145); +#147=IFCPOLYNOMIALCURVE(#146,(0.,1.),(33.8328,-0.01,4.1010498687664E-05),$); +#148=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#143,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(365.76),#147); +#149=IFCALIGNMENTVERTICALSEGMENT($,$,1706.88,243.84,35.6616,0.02,0.02,$,.CONSTANTGRADIENT.); +#150=IFCALIGNMENTSEGMENT('1oYMRqw$r2aO6hIvJEhzgO',$,'V5',$,$,#217,#241,#149); +#151=IFCCARTESIANPOINT((1706.88,35.6616)); +#152=IFCDIRECTION((0.999799979995999,0.02)); +#153=IFCAXIS2PLACEMENT2D(#151,#152); +#154=IFCCARTESIANPOINT((0.,0.)); +#155=IFCDIRECTION((1.,0.)); +#156=IFCVECTOR(#155,1.); +#157=IFCLINE(#154,#156); +#158=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#153,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#157); +#159=IFCALIGNMENTVERTICALSEGMENT($,$,1950.72,609.6,40.5384,-0.02,-0.02,-15240.,.PARABOLICARC.); +#160=IFCALIGNMENTSEGMENT('2rmRh3RID4Dx1Xv2vdnAcV',$,'V6',$,$,#217,#243,#159); +#161=IFCCARTESIANPOINT((1950.72,40.5384)); +#162=IFCDIRECTION((0.999799979995999,0.02)); +#163=IFCAXIS2PLACEMENT2D(#161,#162); +#164=IFCCARTESIANPOINT((0.,0.)); +#165=IFCDIRECTION((1.,0.)); +#166=IFCAXIS2PLACEMENT2D(#164,#165); +#167=IFCPOLYNOMIALCURVE(#166,(0.,1.),(40.5384,0.02,-3.28083989501312E-05),$); +#168=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#163,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(609.6),#167); +#169=IFCALIGNMENTVERTICALSEGMENT($,$,2560.32,304.799999999999,40.5384,-0.02,-0.02,$,.CONSTANTGRADIENT.); +#170=IFCALIGNMENTSEGMENT('2kGQnCzmbB1hLZpc8B8fx7',$,'V7',$,$,#217,#245,#169); +#171=IFCCARTESIANPOINT((2560.32,40.5384)); +#172=IFCDIRECTION((0.999799979995999,-0.02)); +#173=IFCAXIS2PLACEMENT2D(#171,#172); +#174=IFCCARTESIANPOINT((0.,0.)); +#175=IFCDIRECTION((1.,0.)); +#176=IFCVECTOR(#175,1.); +#177=IFCLINE(#174,#176); +#178=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#173,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(304.799999999999),#177); +#179=IFCALIGNMENTVERTICALSEGMENT($,$,2865.12,243.84,34.4424,-0.005,-0.005,16256.,.PARABOLICARC.); +#180=IFCALIGNMENTSEGMENT('3hljyR0Hr0$hbnPws3P554',$,'V8',$,$,#217,#247,#179); +#181=IFCCARTESIANPOINT((2865.12,34.4424)); +#182=IFCDIRECTION((0.999799979995999,-0.02)); +#183=IFCAXIS2PLACEMENT2D(#181,#182); +#184=IFCCARTESIANPOINT((0.,0.)); +#185=IFCDIRECTION((1.,0.)); +#186=IFCAXIS2PLACEMENT2D(#184,#185); +#187=IFCPOLYNOMIALCURVE(#186,(0.,1.),(34.4424,-0.02,3.0757874015748E-05),$); +#188=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#183,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(243.84),#187); +#189=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,7.55055747737515,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.); +#190=IFCALIGNMENTSEGMENT('0Yj$$A801BgAySuKuq8FH1',$,'V9',$,$,#217,#249,#189); +#191=IFCCARTESIANPOINT((3108.96,31.3944)); +#192=IFCDIRECTION((0.999987499921874,-0.005)); +#193=IFCAXIS2PLACEMENT2D(#191,#192); +#194=IFCCARTESIANPOINT((0.,0.)); +#195=IFCDIRECTION((1.,0.)); +#196=IFCVECTOR(#195,1.); +#197=IFCLINE(#194,#196); +#198=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#193,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(7.55055747737515),#197); +#199=IFCALIGNMENTVERTICALSEGMENT($,$,3108.96,0.,31.3944,-0.005,-0.005,$,.CONSTANTGRADIENT.); +#200=IFCALIGNMENTSEGMENT('0FSjBm0hj8PwKhufHaF1ZA',$,'V10',$,$,#217,#251,#199); +#201=IFCCARTESIANPOINT((3108.96,31.3944)); +#202=IFCDIRECTION((0.999987499921874,-0.005)); +#203=IFCAXIS2PLACEMENT2D(#201,#202); +#204=IFCCARTESIANPOINT((0.,0.)); +#205=IFCDIRECTION((1.,0.)); +#206=IFCVECTOR(#205,1.); +#207=IFCLINE(#204,#206); +#208=IFCCURVESEGMENT(.DISCONTINUOUS.,#203,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#207); +#209=IFCALIGNMENTVERTICAL('2nEoeLO$jCAgLWqX3ZS4ZL',$,'Vertical Alignment',$,$,#15,$); +#210=IFCRELNESTS('1Zi6YpAun30A67NCfsmR6h',$,$,'Nests vertical alignment segments with vertical alignment',#209,(#110,#120,#130,#140,#150,#160,#170,#180,#190,#200)); +#211=IFCGRADIENTCURVE((#118,#128,#138,#148,#158,#168,#178,#188,#198,#208),.F.,#108,$); +#212=IFCSHAPEREPRESENTATION(#35,'Axis','Curve3D',(#211)); +#213=IFCDIRECTION((1.,0.,0.)); +#214=IFCDIRECTION((0.,0.,1.)); +#215=IFCCARTESIANPOINT((0.,0.,0.)); +#216=IFCAXIS2PLACEMENT3D(#215,#214,#213); +#217=IFCLOCALPLACEMENT($,#216); +#218=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#45)); +#219=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#218)); +#220=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#55)); +#221=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#220)); +#222=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#65)); +#223=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#222)); +#224=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#75)); +#225=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#224)); +#226=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#85)); +#227=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#226)); +#228=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#95)); +#229=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#228)); +#230=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#105)); +#231=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#230)); +#232=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#118)); +#233=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#232)); +#234=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#128)); +#235=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#234)); +#236=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#138)); +#237=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#236)); +#238=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#148)); +#239=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#238)); +#240=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#158)); +#241=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#240)); +#242=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#168)); +#243=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#242)); +#244=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#178)); +#245=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#244)); +#246=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#188)); +#247=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#246)); +#248=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#198)); +#249=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#248)); +#250=IFCSHAPEREPRESENTATION(#35,'Axis','Segment',(#208)); +#251=IFCPRODUCTDEFINITIONSHAPE('Product Definition of a Segment',$,(#250)); +#252=IFCPRODUCTDEFINITIONSHAPE('Alignment Product Definition Shape',$,(#212)); +#253=IFCALIGNMENT('0qKahqjPjBeuEjpOKkk23s',$,'Unnamed alignment',$,$,#15,#252,$); +#254=IFCRELNESTS('3p2wDzu0r4qBoQ$kirOpI9',$,'Nest horizontal and vertical alignment layouts with the alignment',$,#253,(#106,#209)); +#255=IFCRELAGGREGATES('1K9FW2VIP3Uf303$idpLPY',$,'Alignments in project',$,#10,(#253)); +#256=IFCRELREFERENCEDINSPATIALSTRUCTURE('10jns2II51eA4MvJstMUh6',$,$,$,(#253),#16); +#257=IFCPROPERTYSINGLEVALUE('Station',$,IFCLENGTHMEASURE(3048.),$); +#258=IFCPROPERTYSET('0ykDGVR8D9JvgG2BE$m9Y0',$,'Pset_Stationing',$,(#257)); +#259=IFCPOINTBYDISTANCEEXPRESSION(IFCLENGTHMEASURE(0.),$,$,$,#211); +#260=IFCAXIS2PLACEMENTLINEAR(#259,$,$); +#261=IFCLINEARPLACEMENT($,#260,$); +#262=IFCREFERENT('2MIQXRsdHE1ehEM_GIWxfu',$,'Start of alignment station',$,$,#261,$,.STATION.); +#263=IFCRELNESTS('0UMvxWgzT2mO2ObhWRe5TZ',$,'Nests Referents with station information with alignment',$,#253,(#262)); +#264=IFCRELDEFINESBYPROPERTIES('3SkNbYBX97uBNi5kNrE0qi',$,'Relates station properties to referent',$,(#262),#258); +ENDSEC; +END-ISO-10303-21; From d4779904b60e8fc4e84d466a027aa507e0fede6c Mon Sep 17 00:00:00 2001 From: Geert Hesselink Date: Tue, 22 Oct 2024 21:46:45 +0200 Subject: [PATCH 13/17] IVS-181 Fix/Custom Error Handling --- features/environment.py | 15 ++++++-- features/exception_logger.py | 51 +++++++++++++++++++++++++++ features/steps/validation_handling.py | 2 +- main.py | 24 ++++++------- test/test_main.py | 28 +++++++++++++-- 5 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 features/exception_logger.py diff --git a/features/environment.py b/features/environment.py index 9701b120..aa95391f 100644 --- a/features/environment.py +++ b/features/environment.py @@ -3,12 +3,12 @@ from collections import Counter import os from rule_creation_protocol import protocol +from features.exception_logger import ExceptionSummary import json from validation_results import ValidationOutcome, ValidationOutcomeCode, OutcomeSeverity from main import ExecutionMode - model_cache = {} def read_model(fn): if cached := model_cache.get(fn): @@ -27,7 +27,7 @@ def before_feature(context, feature): context.validation_task_id = None Scenario.continue_after_failed_step = False - context.protocol_errors = [] + context.protocol_errors, context.caught_exceptions = [], [] if context.config.userdata.get('execution_mode') and eval(context.config.userdata.get('execution_mode')) == ExecutionMode.TESTING: ifc_filename_incl_path = context.config.userdata.get('input') convention_attrs = { @@ -59,6 +59,11 @@ def get_validation_outcome_hash(obj): def after_scenario(context, scenario): # Given steps may introduce an arbitrary amount of stackframes. # we need to clean them up before behave starts appending new ones. + + if context.failed: + if not 'Behave errors' in context.step.error_message: #exclude behave output from exception logging + context.caught_exceptions.append(ExceptionSummary.from_context(context)) + old_outcomes = getattr(context, 'gherkin_outcomes', []) while context._stack[0].get('@layer') == 'attribute': context._pop() @@ -126,4 +131,8 @@ def get_or_create_instance_when_set(spf_id): # embed protocol errors protocol_errors_bytes = json.dumps(context.protocol_errors).encode("utf-8") - formatter.embedding(mime_type="application/json", data=protocol_errors_bytes, target='feature', attribute_name='protocol_errors') \ No newline at end of file + formatter.embedding(mime_type="application/json", data=protocol_errors_bytes, target='feature', attribute_name='protocol_errors') + + # embed catched exceptions + caught_exceptions_bytes = json.dumps([exc.to_dict() for exc in context.caught_exceptions]).encode("utf-8") + formatter.embedding(mime_type="application/json", data=caught_exceptions_bytes, target='feature', attribute_name='caught_exceptions') \ No newline at end of file diff --git a/features/exception_logger.py b/features/exception_logger.py new file mode 100644 index 00000000..a178df0e --- /dev/null +++ b/features/exception_logger.py @@ -0,0 +1,51 @@ +import os +from dataclasses import dataclass, asdict +import json + +@dataclass +class ExceptionSummary: + """ + Custom exception for summarizing internal errors during feature validation. + The exception is forwarded to the JSON output and later evaluated after the Behave run using pytest. + Errors occurring at any stage of the step implementation or while running the custom decorator are captured by this exception. + """ + feature: str + step: str + error_type: str + location: str + + @staticmethod + def extract_traceback_summary(exc_traceback): + trace = {} + + current_tb = exc_traceback + while current_tb is not None: + filename = os.path.basename(current_tb.tb_frame.f_code.co_filename) + line_number = current_tb.tb_lineno + + if filename not in trace: + trace[filename] = [line_number] + elif line_number not in trace[filename]: + trace[filename].append(line_number) + + current_tb = current_tb.tb_next + + trace_list = [] + for filename in reversed(trace): + line_numbers = ", ".join(f"#{ln}" for ln in trace[filename]) + trace_list.append(f"{filename}(l{line_numbers})") + + + return ", ".join(trace_list) + + @classmethod + def from_context(cls, context): + feature_name = context.feature.name + step_name = context.step.name + error_type = str(context.step.exception.__class__.__name__) + location = cls.extract_traceback_summary(context.step.exc_traceback) + + return cls(feature=feature_name, step=step_name, error_type=error_type, location=location) + + def to_dict(self): + return asdict(self) \ No newline at end of file diff --git a/features/steps/validation_handling.py b/features/steps/validation_handling.py index cde012b7..678d73c1 100644 --- a/features/steps/validation_handling.py +++ b/features/steps/validation_handling.py @@ -68,7 +68,7 @@ def generate_error_message(context, errors): Function to trigger the behave error mechanism so that the JSON output is generated correctly. Miscellaneous errors also are also printed to the console this way. """ - assert not errors, "Errors occured:\n{}".format([str(error) for error in errors]) + assert not errors, "Behave errors occured:\n{}".format([str(error) for error in errors]) """ diff --git a/main.py b/main.py index 8164db7d..33a9a57d 100644 --- a/main.py +++ b/main.py @@ -38,15 +38,6 @@ def get_commits(cwd, feature_file): return subprocess.check_output(['git', 'log', '--pretty=format:%h', feature_file], cwd=cwd).decode('ascii').split('\n') -def do_try(fn, default=None): - try: - return fn() - except: - import traceback - traceback.print_exc() - return default - - def run(filename, rule_type=RuleType.ALL, with_console_output=False, execution_mode = ExecutionMode.PRODUCTION, task_id = None): cwd = os.path.dirname(__file__) @@ -128,11 +119,12 @@ def run(filename, rule_type=RuleType.ALL, with_console_output=False, execution_m except KeyError: el_list = [] for el in el_list: - protocol_errors = json.loads(base64.b64decode(el.get('protocol_errors', [{}])[0].get('data', '')).decode('utf-8')) if el.get('protocol_errors') else [] - if protocol_errors: - yield { - 'protocol_errors': protocol_errors, - } + + for key in ['protocol_errors', 'caught_exceptions']: + data = decode_and_load_data(el, key) + if data: + yield {key: data} + scenario_validation_outcomes = json.loads(base64.b64decode(el.get('validation_outcomes', [{}])[0].get('data', '')).decode('utf-8')) if el.get('validation_outcomes') else [] scenario_info = { 'scenario_name': el['name'], @@ -142,3 +134,7 @@ def run(filename, rule_type=RuleType.ALL, with_console_output=False, execution_m yield validation_outcome | scenario_info os.close(fd) os.unlink(jsonfn) + +def decode_and_load_data(element, key): + """" Decode base64 encoded data and load it as json """ + return json.loads(base64.b64decode(element.get(key, [{}])[0].get('data', '')).decode('utf-8')) if element.get(key) else [] diff --git a/test/test_main.py b/test/test_main.py index f05ff59c..af592fc8 100644 --- a/test/test_main.py +++ b/test/test_main.py @@ -50,9 +50,12 @@ def test_invocation(filename): print('The Gherkin tests did not run for the specified test file, and the JSON report is empty. Please review the test file for any errors.') rule_is_disabled = feature_info['rule_is_disabled'] - protocol_errors = next((d for d in gherkin_results if 'protocol_errors' in d), None) - validation_outcomes = [d for d in gherkin_results[1:] if 'protocol_errors' not in d] + ci_cd_checks = {'protocol_errors': [], 'caught_exceptions': []} + for i in ci_cd_checks.keys(): + ci_cd_checks[i] = next((d[i] for d in gherkin_results if i in d), None) + + validation_outcomes = [d for d in gherkin_results[1:] if all(key not in d for key in ci_cd_checks.keys())] error_outcomes = [outcome for outcome in validation_outcomes if outcome['severity'] in ['Error', 'Warning']] activating_outcomes = [outcome for outcome in validation_outcomes if outcome['severity'] == 'Executed'] @@ -79,13 +82,32 @@ def test_invocation(filename): # did not result in an actionable set of instances at the time of the first then step. #first, check if there are no protocol errors + protocol_errors = ci_cd_checks['protocol_errors'] if protocol_errors: red_text = "\033[91m" reset_text = "\033[0m" print(f'{red_text}\n\nWARNING: The following protocol errors have been found:{reset_text}') - print(tabulate.tabulate([[error] for error in protocol_errors['protocol_errors']], headers=['Details'], tablefmt='fancy_grid')) + print(tabulate.tabulate([[error] for error in protocol_errors], headers=['Details'], tablefmt='fancy_grid')) assert False # table should be printed before the assertion + caught_exceptions = ci_cd_checks['caught_exceptions'] + if caught_exceptions: + red_text = "\033[91m" + reset_text = "\033[0m" + print(f'{red_text}\n\nWARNING: The following caught exceptions have been found:{reset_text}') + + def wrap_text(text, width): + return '\n'.join(text[i:i+width] for i in range(0, len(text), width)) + + table_data = [ + [wrap_text(exc['feature'], 40), wrap_text(exc['step'], 40), exc['error_type'], wrap_text(exc['location'], 60)] + for exc in caught_exceptions + ] + + + headers = ['Feature', 'Step', 'Error Type', 'Location'] + print(tabulate.tabulate(table_data, headers=headers, tablefmt='fancy_grid')) + assert False if base.startswith('fail'): assert len(error_outcomes) > 0 From 21a5c6f8aef7bc8ac0b36a95db4248ad95c91e79 Mon Sep 17 00:00:00 2001 From: Geert Hesselink <54070862+Ghesselink@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:33:52 +0200 Subject: [PATCH 14/17] Update wording --- test/test_main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_main.py b/test/test_main.py index af592fc8..e7ee5465 100644 --- a/test/test_main.py +++ b/test/test_main.py @@ -86,7 +86,7 @@ def test_invocation(filename): if protocol_errors: red_text = "\033[91m" reset_text = "\033[0m" - print(f'{red_text}\n\nWARNING: The following protocol errors have been found:{reset_text}') + print(f'{red_text}\n\nWARNING: The following protocol errors were caught:{reset_text}') print(tabulate.tabulate([[error] for error in protocol_errors], headers=['Details'], tablefmt='fancy_grid')) assert False # table should be printed before the assertion @@ -94,7 +94,7 @@ def test_invocation(filename): if caught_exceptions: red_text = "\033[91m" reset_text = "\033[0m" - print(f'{red_text}\n\nWARNING: The following caught exceptions have been found:{reset_text}') + print(f'{red_text}\n\nWARNING: The following exceptions were caught:{reset_text}') def wrap_text(text, width): return '\n'.join(text[i:i+width] for i in range(0, len(text), width)) From 3de923b8a82ec98d916e6823fe1598b05eed001d Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Wed, 23 Oct 2024 22:29:16 -0400 Subject: [PATCH 15/17] rename test file for ALB012 The test file that raises an exception should start with 'fail'. (IVS-137) --- features/rule_creation_protocol/protocol.py | 4 ++-- ...12-scenario02-equal_gradients_parabolic_curve_type.ifc} | 0 test/test_main.py | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) rename test/files/alb012/{pass-alb012-equal_gradients_parabolic_curve_type.ifc => fail-alb012-scenario02-equal_gradients_parabolic_curve_type.ifc} (100%) diff --git a/features/rule_creation_protocol/protocol.py b/features/rule_creation_protocol/protocol.py index bfe4968b..3a875ce8 100644 --- a/features/rule_creation_protocol/protocol.py +++ b/features/rule_creation_protocol/protocol.py @@ -283,11 +283,11 @@ def validate_test_filename(cls, value): - """Check if test file start with pass or fail""" + """Check if test file start with a valid prefix""" if result not in ('pass', 'fail', 'na'): raise ProtocolError( value=value, - message=f"Name of the result file must start with 'pass', 'fail' or 'na'. In that case name starts with: {result}" + message=f"Name of the test file must start with 'pass', 'fail', or 'na'. This file name starts with: {result}" ) """Check if a second part of the test file is a rule code""" diff --git a/test/files/alb012/pass-alb012-equal_gradients_parabolic_curve_type.ifc b/test/files/alb012/fail-alb012-scenario02-equal_gradients_parabolic_curve_type.ifc similarity index 100% rename from test/files/alb012/pass-alb012-equal_gradients_parabolic_curve_type.ifc rename to test/files/alb012/fail-alb012-scenario02-equal_gradients_parabolic_curve_type.ifc diff --git a/test/test_main.py b/test/test_main.py index e7ee5465..ca60ccb3 100644 --- a/test/test_main.py +++ b/test/test_main.py @@ -107,15 +107,14 @@ def wrap_text(text, width): headers = ['Feature', 'Step', 'Error Type', 'Location'] print(tabulate.tabulate(table_data, headers=headers, tablefmt='fancy_grid')) - assert False - + if base.startswith('fail'): - assert len(error_outcomes) > 0 + assert len(error_outcomes) > 0 or caught_exceptions elif base.startswith('pass'): assert len(error_outcomes) == 0 and len(activating_outcomes) > 0 elif base.startswith('na'): assert len(error_outcomes) == 0 and len(activating_outcomes) == 0 - + if error_outcomes: tabulate_results = [ ( From c382fe798c9db4c5b1b68dc8f04868db0662c46a Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Wed, 23 Oct 2024 23:54:52 -0400 Subject: [PATCH 16/17] avoid NoneTypeError when processing outcomes (IVS-137) --- features/environment.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/features/environment.py b/features/environment.py index faed1d41..c2c78e12 100644 --- a/features/environment.py +++ b/features/environment.py @@ -133,9 +133,10 @@ def get_or_create_instance_when_set(spf_id): outcomes = [outcome.to_dict() for outcome in context.gherkin_outcomes] for idx, outcome in enumerate(outcomes): sls = find_scenario_for_outcome(context, idx + 1) - outcome['scenario'] = sls['scenario'] - outcome['last_step'] = sls['last_step'].name - outcome['instance_id'] = context.instance_outcome_state.get(idx+1, '') + if sls is not None: + outcome['scenario'] = sls['scenario'] + outcome['last_step'] = sls['last_step'].name + outcome['instance_id'] = context.instance_outcome_state.get(idx + 1, '') outcomes_json_str = json.dumps(outcomes) #ncodes to utf-8 outcomes_bytes = outcomes_json_str.encode("utf-8") for formatter in filter(lambda f: hasattr(f, "embedding"), context._runner.formatters): From f6fc490ea19d5296869596bde6fc1743d5234faf Mon Sep 17 00:00:00 2001 From: Scott Lecher Date: Thu, 24 Oct 2024 11:18:42 -0400 Subject: [PATCH 17/17] refactor `compare_with_precision()` to use pattern matching (IVS-137) --- features/steps/utils/geometry.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/features/steps/utils/geometry.py b/features/steps/utils/geometry.py index ad372c0f..2296d313 100644 --- a/features/steps/utils/geometry.py +++ b/features/steps/utils/geometry.py @@ -260,17 +260,18 @@ def compare_with_precision(value_1: float, value_2: float, precision: float, com 'greater than or equal to'; 'less than or equal to'. """ - if comparison_operator == 'equal to': - return math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) - elif comparison_operator == 'not equal to': - return not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) - elif comparison_operator == 'greater than': - return value_1 > value_2 and not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) - elif comparison_operator == 'less than': - return value_1 < value_2 and not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) - elif comparison_operator == 'greater than or equal to': - return value_1 > value_2 or math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) - elif comparison_operator == 'less than or equal to': - return value_1 < value_2 or math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) - else: - raise ValueError(f"Invalid comparison operator: {comparison_operator}") + match comparison_operator: + case 'equal to': + return math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) + case 'not equal to': + return not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) + case 'greater than': + return value_1 > value_2 and not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) + case 'less than': + return value_1 < value_2 and not math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) + case 'greater than or equal to': + return value_1 > value_2 or math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) + case 'less than or equal to': + return value_1 < value_2 or math.isclose(value_1, value_2, rel_tol=0., abs_tol=precision) + case _: + raise ValueError(f"Invalid comparison operator: {comparison_operator}")