Refactor test_sweeps.py: remove _is_swept_shape, restructure test directories, update test fixtures, and adjust assertions for geometry validation. Extend sweep_along_curve constructor to support fixed reference direction.

This commit is contained in:
krande
2025-08-27 19:37:47 +02:00
parent 9dd7b488d6
commit 1cd32be2fc
7 changed files with 168 additions and 268 deletions
-119
View File
@@ -1,119 +0,0 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
FILE_NAME('','2025-02-14T16:16:53',(''),(''),'IfcOpenShell 0.8.1-c49ca69','IfcOpenShell 0.8.1-c49ca69','');
FILE_SCHEMA(('IFC4X3_ADD2'));
ENDSEC;
DATA;
#1=IFCPERSON($,$,'Pravin.Muthukrishnan',$,$,$,$,$);
#2=IFCORGANIZATION($,'BG&E Pty Ltd','BG&E Pty Ltd',$,$);
#3=IFCPERSONANDORGANIZATION(#1,#2,$);
#4=IFCAPPLICATION(#2,'15.0C1n','12d Model','12d Model');
#5=IFCOWNERHISTORY(#3,#4,$,.NOCHANGE.,$,$,$,1739508662);
#6=IFCCARTESIANPOINT((0.,0.,0.));
#7=IFCDIRECTION((0.,0.,1.));
#8=IFCDIRECTION((1.,0.,0.));
#9=IFCAXIS2PLACEMENT3D(#6,#7,#8);
#10=IFCDIRECTION((0.,1.,0.));
#11=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-06,#9,#10);
#12=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#13=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#14=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
#15=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#16=IFCUNITASSIGNMENT((#12,#13,#14,#15));
#17=IFCPROJECT('3f4tUCcZz5OBp_RAlF3Yjd',#5,'DRAINAGE DESIGN','No description set',$,$,$,(#11),#16);
#18=IFCPERSON($,$,'Pravin.Muthukrishnan',$,$,$,$,$);
#19=IFCORGANIZATION($,'BG&E Pty Ltd','BG&E Pty Ltd',$,$);
#20=IFCPERSONANDORGANIZATION(#18,#19,$);
#21=IFCAPPLICATION(#19,'15.0C1n','12d Model','12d Model');
#22=IFCOWNERHISTORY(#20,#21,$,.NOCHANGE.,$,$,$,1739508662);
#30=IFCCARTESIANPOINT((0.,0.));
#31=IFCAXIS2PLACEMENT2D(#30,$);
#32=IFCCIRCLEPROFILEDEF(.AREA.,$,#31,0.179);
#33=IFCCARTESIANPOINT((289080.818499209,5822851.36621952,118.886));
#34=IFCCARTESIANPOINT((289081.570466963,5822857.54453541,118.886));
#35=IFCPOLYLINE((#33,#34));
#36=IFCDIRECTION((1.,0.,0.));
#37=IFCFIXEDREFERENCESWEPTAREASOLID(#32,$,#35,$,$,#36);
#38=IFCSHAPEREPRESENTATION(#11,'Body','AdvancedSweptSolid',(#37));
#39=IFCPRODUCTDEFINITIONSHAPE($,$,(#38));
#40=IFCFLOWSEGMENT('1iJOpv7cX1SBoQLaHDDolV',#108,'5','5-1 to 1-1','EXISTING (RETAINED)',#103,#39,$);
#41=IFCRELDEFINESBYPROPERTIES('10rIwnj8r8RR3PKc1TXqSB',#22,'12d Model','Attributes',(#40),#94);
#42=IFCPROPERTYSINGLEVALUE('calculated critical cover chainage',$,IFCREAL(2.24873590275508),$);
#43=IFCPROPERTYSINGLEVALUE('nominal diameter',$,IFCREAL(0.3),$);
#44=IFCPROPERTYSINGLEVALUE('pipe id',$,IFCINTEGER(35),$);
#45=IFCPROPERTYSINGLEVALUE('colour',$,IFCLABEL('orange'),$);
#46=IFCPROPERTYSINGLEVALUE('group',$,IFCLABEL('EX'),$);
#47=IFCCOMPLEXPROPERTY('pipe sched','12d_attribute_group',$,(#46));
#48=IFCPROPERTYSINGLEVALUE('name',$,IFCLABEL('EX'),$);
#49=IFCCOMPLEXPROPERTY('lplot','12d_attribute_group',$,(#48));
#50=IFCPROPERTYSINGLEVALUE('pipe name',$,IFCLABEL('5-1 to 1-1'),$);
#51=IFCPROPERTYSINGLEVALUE('calculated direct pipe flow total minor',$,IFCREAL(0.),$);
#52=IFCPROPERTYSINGLEVALUE('calculated direct pipe flow total major',$,IFCREAL(0.),$);
#53=IFCPROPERTYSINGLEVALUE('calculated direct pit and pipe flow total minor',$,IFCREAL(0.),$);
#54=IFCPROPERTYSINGLEVALUE('calculated direct pit and pipe flow total major',$,IFCREAL(0.),$);
#55=IFCPROPERTYSINGLEVALUE('pipe type',$,IFCLABEL('EXISTING (RETAINED)'),$);
#56=IFCPROPERTYSINGLEVALUE('roughness text',$,IFCLABEL('n=0.013'),$);
#57=IFCPROPERTYSINGLEVALUE('calculated design grade minimum',$,IFCREAL(1.),$);
#58=IFCPROPERTYSINGLEVALUE('calculated pipe length',$,IFCREAL(7.19890895752825),$);
#59=IFCPROPERTYSINGLEVALUE('invert us',$,IFCREAL(118.736),$);
#60=IFCPROPERTYSINGLEVALUE('invert ds',$,IFCREAL(118.736),$);
#61=IFCPROPERTYSINGLEVALUE('calculated pipe grade',$,IFCREAL(-0.),$);
#62=IFCPROPERTYSINGLEVALUE('calculated pipe vert angle',$,IFCREAL(0.),$);
#63=IFCPROPERTYSINGLEVALUE('calculated pipe grade 1 in',$,IFCREAL(1000000.),$);
#64=IFCPROPERTYSINGLEVALUE('pipe size',$,IFCLABEL('300'),$);
#65=IFCPROPERTYSINGLEVALUE('diameter',$,IFCREAL(0.3),$);
#66=IFCPROPERTYSINGLEVALUE('nominal pipe size',$,IFCLABEL('300'),$);
#67=IFCPROPERTYSINGLEVALUE('calculated us deflection',$,IFCREAL(0.),$);
#68=IFCPROPERTYSINGLEVALUE('calculated ds deflection',$,IFCREAL(89.4496469263205),$);
#69=IFCPROPERTYSINGLEVALUE('calculated design drop',$,IFCREAL(0.02),$);
#70=IFCPROPERTYSINGLEVALUE('calculated drop',$,IFCREAL(0.),$);
#71=IFCPROPERTYSINGLEVALUE('calculated pipe vert ds deflection angle',$,IFCREAL(-4.09980829540645),$);
#72=IFCPROPERTYSINGLEVALUE('calculated design cover',$,IFCREAL(1.1),$);
#73=IFCPROPERTYSINGLEVALUE('minimum cover',$,IFCREAL(1.67561504823626),$);
#74=IFCPROPERTYSINGLEVALUE('pipe colour',$,IFCINTEGER(8),$);
#75=IFCPROPERTYSINGLEVALUE('conduit shape',$,IFCLABEL('Circular'),$);
#76=IFCPROPERTYSINGLEVALUE('calculated invert us',$,IFCREAL(118.736),$);
#77=IFCPROPERTYSINGLEVALUE('calculated invert ds',$,IFCREAL(118.736),$);
#78=IFCPROPERTYSINGLEVALUE('calculated hgl us',$,IFCREAL(118.736),$);
#79=IFCPROPERTYSINGLEVALUE('calculated hgl ds',$,IFCREAL(118.736),$);
#80=IFCPROPERTYSINGLEVALUE('lock us il',$,IFCINTEGER(1),$);
#81=IFCPROPERTYSINGLEVALUE('lock ds il',$,IFCINTEGER(1),$);
#82=IFCPROPERTYSINGLEVALUE('critical barrel',$,IFCINTEGER(0),$);
#83=IFCPROPERTYSINGLEVALUE('critical side',$,IFCINTEGER(0),$);
#84=IFCPROPERTYSINGLEVALUE('Pipe Name',$,IFCLABEL('5-1 to 1-1'),$);
#85=IFCPROPERTYSINGLEVALUE('Pipe Type',$,IFCLABEL('EXISTING (RETAINED)'),$);
#86=IFCPROPERTYSINGLEVALUE('Justification',$,IFCLABEL('Invert'),$);
#87=IFCPROPERTYSINGLEVALUE('Start x',$,IFCREAL(289080.818499209),$);
#88=IFCPROPERTYSINGLEVALUE('Start y',$,IFCREAL(5822851.36621952),$);
#89=IFCPROPERTYSINGLEVALUE('Start z',$,IFCREAL(118.736),$);
#90=IFCPROPERTYSINGLEVALUE('End x',$,IFCREAL(289081.570466963),$);
#91=IFCPROPERTYSINGLEVALUE('End y',$,IFCREAL(5822857.54453541),$);
#92=IFCPROPERTYSINGLEVALUE('End z',$,IFCREAL(118.736),$);
#93=IFCCOMPLEXPROPERTY('Geometry','12d_attribute_group',$,(#86,#87,#88,#89,#90,#91,#92));
#94=IFCPROPERTYSET('0pqqHlNsb54w9VRYcNog0C',#22,'12d Model',$,(#42,#43,#44,#45,#47,#49,#50,#51,#52,#53,#54,#55,#56,#57,#58,#59,#60,#61,#62,#63,#64,#65,#66,#67,#68,#69,#70,#71,#72,#73,#74,#75,#76,#77,#78,#79,#80,#81,#82,#83,#84,#85,#93));
#95=IFCSTYLEDITEM(#37,(#98),$);
#96=IFCCOLOURRGB('orange',1.,0.647058823529412,0.);
#97=IFCSURFACESTYLERENDERING(#96,$,$,$,$,$,IFCNORMALISEDRATIOMEASURE(0.00390625),IFCSPECULAREXPONENT(10.),.NOTDEFINED.);
#98=IFCSURFACESTYLE($,.POSITIVE.,(#97));
#99=IFCCARTESIANPOINT((0.,0.,0.));
#100=IFCDIRECTION((0.,0.,1.));
#101=IFCDIRECTION((1.,0.,0.));
#102=IFCAXIS2PLACEMENT3D(#99,#100,#101);
#103=IFCLOCALPLACEMENT($,#102);
#104=IFCACTORROLE(.USERDEFINED.,'CONTRIBUTOR',$);
#105=IFCTELECOMADDRESS(.USERDEFINED.,$,'WEBPAGE',$,$,$,$,'https://ifcopenshell.org',$);
#106=IFCORGANIZATION('IfcOpenShell','IfcOpenShell','IfcOpenShell is an open source software library that helps users and software developers to work with IFC data.',(#104),(#105));
#107=IFCAPPLICATION(#106,'0.8.1-alpha250208-3832077','Bonsai','Bonsai');
#108=IFCOWNERHISTORY(#20,#21,$,.MODIFIED.,1739510213,#3,#107,1739508662);
#114=IFCSITE('2CTfxIYCTCsRAvUEqFZoH3',#120,'Default Site','Description of Default Site',$,#119,$,$,.ELEMENT.,$,$,$,$,$);
#115=IFCCARTESIANPOINT((0.,0.,0.));
#116=IFCDIRECTION((0.,0.,1.));
#117=IFCDIRECTION((1.,0.,0.));
#118=IFCAXIS2PLACEMENT3D(#115,#116,#117);
#119=IFCLOCALPLACEMENT($,#118);
#120=IFCOWNERHISTORY(#20,#21,$,.MODIFIED.,1739510213,#3,#107,1739508662);
#121=IFCRELCONTAINEDINSPATIALSTRUCTURE('05AVd4pPf1jeS4OU20v7N9',#5,$,$,(#40),#114);
#122=IFCRELAGGREGATES('3PxVuUIG14dQdQEHf8wUca',#5,$,$,#17,(#114));
ENDSEC;
END-ISO-10303-21;
-74
View File
@@ -1,74 +0,0 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
FILE_NAME('/dev/null','2025-08-26T16:01:38+02:00',('AdaUser'),('AdaOrg'),'IfcOpenShell 0.8.2','IfcOpenShell 0.8.2','Nobody');
FILE_SCHEMA(('IFC4X3_ADD2'));
ENDSEC;
DATA;
#1=IFCPROJECT('1TMwI763XBx9E7h3kqXonB',$,'AdaProject',$,$,$,$,(#11),#6);
#2=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#3=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#4=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
#5=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#6=IFCUNITASSIGNMENT((#5,#3,#4,#2));
#7=IFCCARTESIANPOINT((0.,0.,0.));
#8=IFCDIRECTION((0.,0.,1.));
#9=IFCDIRECTION((1.,0.,0.));
#10=IFCAXIS2PLACEMENT3D(#7,#8,#9);
#11=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#10,$);
#12=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#11,$,.MODEL_VIEW.,$);
#13=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#11,$,.GRAPH_VIEW.,$);
#14=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Box','Model',*,*,*,*,#11,$,.MODEL_VIEW.,$);
#15=IFCACTORROLE(.ENGINEER.,$,$);
#16=IFCPERSON('AdaUser',$,$,$,$,$,(#15),$);
#17=IFCORGANIZATION('ADA','Assembly For Design and Analysis',$,$,$);
#18=IFCPERSONANDORGANIZATION(#16,#17,$);
#19=IFCAPPLICATION(#17,'XXX','ADA','ADA');
#20=IFCOWNERHISTORY(#18,#19,.READWRITE.,$,$,#18,#19,1756216898);
#21=IFCDIRECTION((0.,0.,1.));
#22=IFCDIRECTION((1.,0.,0.));
#23=IFCCARTESIANPOINT((0.,0.,0.));
#24=IFCAXIS2PLACEMENT3D(#23,#21,#22);
#25=IFCLOCALPLACEMENT($,#24);
#26=IFCSITE('301mrn5JHCxRMMvjp9uGM1',#20,'Ada',$,$,#25,$,$,.ELEMENT.,$,$,$,$,$);
#27=IFCRELAGGREGATES('0RnSPGnurA1RhM0uNbRZ8k',#20,'Project Container',$,#1,(#26));
#28=IFCPROPERTYSINGLEVALUE('project',$,IFCTEXT('AdaProject'),$);
#29=IFCPROPERTYSINGLEVALUE('schema',$,IFCTEXT('IFC4X3_add2'),$);
#30=IFCPROPERTYSET('1Yj9$v$uH0ZQk9AOoWx4hD',#20,'Properties',$,(#28,#29));
#31=IFCRELDEFINESBYPROPERTIES('2zKQjOOuP0VwvxPEpnJusI',#20,'Properties',$,(#26),#30);
#32=IFCMATERIAL('S355',$,'Steel');
#33=IFCPROPERTYSINGLEVALUE('Grade',$,IFCTEXT('S355'),$);
#34=IFCPROPERTYSINGLEVALUE('YieldStress',$,IFCPRESSUREMEASURE(355000000.),$);
#35=IFCPROPERTYSINGLEVALUE('YoungModulus',$,IFCMODULUSOFELASTICITYMEASURE(210000000000.),$);
#36=IFCPROPERTYSINGLEVALUE('PoissonRatio',$,IFCPOSITIVERATIOMEASURE(0.3),$);
#37=IFCPROPERTYSINGLEVALUE('ThermalExpansionCoefficient',$,IFCTHERMALEXPANSIONCOEFFICIENTMEASURE(1.2E-05),$);
#38=IFCPROPERTYSINGLEVALUE('SpecificHeatCapacity',$,IFCSPECIFICHEATCAPACITYMEASURE(0.03),$);
#39=IFCPROPERTYSINGLEVALUE('MassDensity',$,IFCMASSDENSITYMEASURE(7850.),$);
#40=IFCMATERIALPROPERTIES('MaterialMechanical','A Material property description',(#33,#34,#35,#36,#37,#38,#39),#32);
#41=IFCRELASSOCIATESMATERIAL('13SLSaNyz4PwOBYuDhXcWi',#20,'S355','Objects related to S355',(#64),#32);
#42=IFCDIRECTION((0.,0.,1.));
#43=IFCDIRECTION((1.,0.,0.));
#44=IFCCARTESIANPOINT((0.,0.,0.));
#45=IFCAXIS2PLACEMENT3D(#44,#42,#43);
#46=IFCLOCALPLACEMENT(#25,#45);
#47=IFCCARTESIANPOINTLIST2D(((0.,0.),(0.,0.1),(0.1,0.),(0.1,0.1)),$);
#48=IFCINDEXEDPOLYCURVE(#47,(IFCLINEINDEX((3,1)),IFCLINEINDEX((1,2)),IFCLINEINDEX((2,4)),IFCLINEINDEX((4,3))),$);
#49=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#48);
#50=IFCCARTESIANPOINTLIST3D(((-1.,0.,0.8),(-0.14253,0.,0.542759),(-0.039541321421393,0.,0.470579850861542),(0.,0.,0.),(0.,0.,0.351194)),$);
#51=IFCINDEXEDPOLYCURVE(#50,(IFCLINEINDEX((4,5)),IFCARCINDEX((5,3,2)),IFCLINEINDEX((2,1))),$);
#52=IFCDIRECTION((-0.,1.,0.));
#53=IFCCARTESIANPOINT((0.,0.,0.));
#54=IFCDIRECTION((1.,0.,0.));
#55=IFCDIRECTION((0.,0.,-1.));
#56=IFCAXIS2PLACEMENT3D(#53,#54,#55);
#57=IFCFIXEDREFERENCESWEPTAREASOLID(#49,#56,#51,$,$,#52);
#58=IFCSHAPEREPRESENTATION(#12,'Body','AdvancedSweptSolid',(#57));
#59=IFCPRODUCTDEFINITIONSHAPE($,$,(#58));
#60=IFCCOLOURRGB('Color1',0.8,0.8,0.8);
#61=IFCSURFACESTYLESHADING(#60,0.);
#62=IFCSURFACESTYLE('Color1',.BOTH.,(#61));
#63=IFCSTYLEDITEM(#57,(#62),'Color1');
#64=IFCBUILDINGELEMENTPROXY('1R8AUxDeX02RhatZPFgzSt',#20,'sweep1',$,$,#46,#59,$,$);
#65=IFCRELCONTAINEDINSPATIALSTRUCTURE('0HNU_Fs7r0SRBiQ9Xqgv$k',#20,'Physical model',$,(#64),#26);
ENDSEC;
END-ISO-10303-21;
-74
View File
@@ -1,74 +0,0 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
FILE_NAME('/dev/null','2025-08-27T11:12:44+02:00',('AdaUser'),('AdaOrg'),'IfcOpenShell 0.8.2','IfcOpenShell 0.8.2','Nobody');
FILE_SCHEMA(('IFC4X3_ADD2'));
ENDSEC;
DATA;
#1=IFCPROJECT('0bfgwqvaX7Vvg12DS5E4TH',$,'AdaProject',$,$,$,$,(#11),#6);
#2=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
#3=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#4=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
#5=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#6=IFCUNITASSIGNMENT((#4,#2,#5,#3));
#7=IFCCARTESIANPOINT((0.,0.,0.));
#8=IFCDIRECTION((0.,0.,1.));
#9=IFCDIRECTION((1.,0.,0.));
#10=IFCAXIS2PLACEMENT3D(#7,#8,#9);
#11=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#10,$);
#12=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#11,$,.MODEL_VIEW.,$);
#13=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#11,$,.GRAPH_VIEW.,$);
#14=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Box','Model',*,*,*,*,#11,$,.MODEL_VIEW.,$);
#15=IFCACTORROLE(.ENGINEER.,$,$);
#16=IFCPERSON('AdaUser',$,$,$,$,$,(#15),$);
#17=IFCORGANIZATION('ADA','Assembly For Design and Analysis',$,$,$);
#18=IFCPERSONANDORGANIZATION(#16,#17,$);
#19=IFCAPPLICATION(#17,'XXX','ADA','ADA');
#20=IFCOWNERHISTORY(#18,#19,.READWRITE.,$,$,#18,#19,1756285964);
#21=IFCDIRECTION((0.,0.,1.));
#22=IFCDIRECTION((1.,0.,0.));
#23=IFCCARTESIANPOINT((0.,0.,0.));
#24=IFCAXIS2PLACEMENT3D(#23,#21,#22);
#25=IFCLOCALPLACEMENT($,#24);
#26=IFCSITE('1GDQO$O1L1QOKEaI81COHL',#20,'Ada',$,$,#25,$,$,.ELEMENT.,$,$,$,$,$);
#27=IFCRELAGGREGATES('34vxVzLRfCB8P7OThopnom',#20,'Project Container',$,#1,(#26));
#28=IFCPROPERTYSINGLEVALUE('project',$,IFCTEXT('AdaProject'),$);
#29=IFCPROPERTYSINGLEVALUE('schema',$,IFCTEXT('IFC4X3_add2'),$);
#30=IFCPROPERTYSET('2hTgvJbh1B7RR4nwsOfRDy',#20,'Properties',$,(#28,#29));
#31=IFCRELDEFINESBYPROPERTIES('2wzYfhPqT9hwqI5vOO4yex',#20,'Properties',$,(#26),#30);
#32=IFCMATERIAL('S355',$,'Steel');
#33=IFCPROPERTYSINGLEVALUE('Grade',$,IFCTEXT('S355'),$);
#34=IFCPROPERTYSINGLEVALUE('YieldStress',$,IFCPRESSUREMEASURE(355000000.),$);
#35=IFCPROPERTYSINGLEVALUE('YoungModulus',$,IFCMODULUSOFELASTICITYMEASURE(210000000000.),$);
#36=IFCPROPERTYSINGLEVALUE('PoissonRatio',$,IFCPOSITIVERATIOMEASURE(0.3),$);
#37=IFCPROPERTYSINGLEVALUE('ThermalExpansionCoefficient',$,IFCTHERMALEXPANSIONCOEFFICIENTMEASURE(1.2E-05),$);
#38=IFCPROPERTYSINGLEVALUE('SpecificHeatCapacity',$,IFCSPECIFICHEATCAPACITYMEASURE(0.03),$);
#39=IFCPROPERTYSINGLEVALUE('MassDensity',$,IFCMASSDENSITYMEASURE(7850.),$);
#40=IFCMATERIALPROPERTIES('MaterialMechanical','A Material property description',(#33,#34,#35,#36,#37,#38,#39),#32);
#41=IFCRELASSOCIATESMATERIAL('0vr_O6t$T7vPWIa1EqEt6b',#20,'S355','Objects related to S355',(#64),#32);
#42=IFCDIRECTION((0.,0.,1.));
#43=IFCDIRECTION((1.,0.,0.));
#44=IFCCARTESIANPOINT((0.,0.,0.));
#45=IFCAXIS2PLACEMENT3D(#44,#42,#43);
#46=IFCLOCALPLACEMENT(#25,#45);
#47=IFCCARTESIANPOINTLIST2D(((0.,0.),(0.,0.1),(0.1,0.),(0.1,0.1)),$);
#48=IFCINDEXEDPOLYCURVE(#47,(IFCLINEINDEX((3,1)),IFCLINEINDEX((1,2)),IFCLINEINDEX((2,4)),IFCLINEINDEX((4,3))),$);
#49=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#48);
#50=IFCCARTESIANPOINTLIST3D(((-100.,-50.,199.610854),(-100.,-50.,200.),(-99.974928791787,-49.9996866104928,199.513897412378),(-99.9060013418686,-49.998825019006,199.441251),(-99.3499585838692,-49.9918744730554,199.093724161494),(-99.2406758662487,-49.9607719931374,198.987781372709),(-99.2000000393918,-49.8803717417563,198.861230109006),(-99.2000000393918,-49.3859696738752,198.235404705615),(-99.1121322022443,-49.2544691526923,198.068948349419),(-98.9000000393918,-49.2000000638752,198.000000135615),(-98.3,-49.1999999172672,197.999999950035)),$);
#51=IFCINDEXEDPOLYCURVE(#50,(IFCLINEINDEX((2,1)),IFCARCINDEX((1,3,4)),IFCLINEINDEX((4,5)),IFCARCINDEX((5,6,7)),IFCLINEINDEX((7,8)),IFCARCINDEX((8,9,10)),IFCLINEINDEX((10,11))),$);
#52=IFCDIRECTION((1.,-0.,0.));
#53=IFCCARTESIANPOINT((0.,0.,0.));
#54=IFCDIRECTION((0.,0.,-1.));
#55=IFCDIRECTION((0.,1.,0.));
#56=IFCAXIS2PLACEMENT3D(#53,#54,#55);
#57=IFCFIXEDREFERENCESWEPTAREASOLID(#49,#56,#51,$,$,#52);
#58=IFCSHAPEREPRESENTATION(#12,'Body','AdvancedSweptSolid',(#57));
#59=IFCPRODUCTDEFINITIONSHAPE($,$,(#58));
#60=IFCCOLOURRGB('Color1',0.8,0.8,0.8);
#61=IFCSURFACESTYLESHADING(#60,0.);
#62=IFCSURFACESTYLE('Color1',.BOTH.,(#61));
#63=IFCSTYLEDITEM(#57,(#62),'Color1');
#64=IFCBUILDINGELEMENTPROXY('0pDZhwPyT3dRMnPGA47kAn',#20,'sweep1',$,$,#46,#59,$,$);
#65=IFCRELCONTAINEDINSPATIALSTRUCTURE('196Q7zPfr4LxqeArD0gmJa',#20,'Physical model',$,(#64),#26);
ENDSEC;
END-ISO-10303-21;
-235
View File
@@ -1,235 +0,0 @@
import pathlib
from typing import List, Sequence, Tuple
import ifcopenshell
import pytest
from OCC.Core.TopoDS import TopoDS_Shape, TopoDS_Compound
def _bbox_from_vertices(verts: List[Tuple[float, float, float]]):
if not verts:
return (0, 0, 0), (0, 0, 0)
xs = [v[0] for v in verts]
ys = [v[1] for v in verts]
zs = [v[2] for v in verts]
mn = (min(xs), min(ys), min(zs))
mx = (max(xs), max(ys), max(zs))
return mn, mx
def _size_from_bbox(mn, mx):
return (mx[0] - mn[0], mx[1] - mn[1], mx[2] - mn[2])
def _triples(flat: Sequence[float]) -> List[Tuple[float, float, float]]:
return [(float(flat[i]), float(flat[i + 1]), float(flat[i + 2])) for i in range(0, len(flat), 3)]
def _is_swept_shape(occ_shape: TopoDS_Shape) -> bool:
"""Analyze if the given OpenCASCADE shape represents a swept shape using topology exploration."""
try:
from OCC.Core.TopExp import TopExp_Explorer
from OCC.Core.TopAbs import TopAbs_FACE, TopAbs_EDGE, TopAbs_WIRE
from OCC.Core.BRep_Tool import BRep_Tool
from OCC.Core.GeomLProp_SLProps import GeomLProp_SLProps
from OCC.Core.BRepAdaptor_Surface import BRepAdaptor_Surface
from OCC.Core.GeomAbs import (
GeomAbs_Cylinder,
GeomAbs_Plane,
GeomAbs_SurfaceOfExtrusion,
GeomAbs_SurfaceOfRevolution,
)
from OCC.Core.gp import gp_Vec
import math
except ImportError as e:
raise RuntimeError("pythonocc-core not available for topology analysis") from e
if occ_shape.IsNull():
return False
# Explore faces to look for swept surface characteristics
face_explorer = TopExp_Explorer(occ_shape, TopAbs_FACE)
swept_indicators = 0
total_faces = 0
while face_explorer.More():
face = face_explorer.Current()
total_faces += 1
# Get the surface adaptor for this face
surface_adaptor = BRepAdaptor_Surface(face)
surface_type = surface_adaptor.GetType()
# Check for surface types that indicate swept geometry
if surface_type in [GeomAbs_Cylinder, GeomAbs_SurfaceOfExtrusion, GeomAbs_SurfaceOfRevolution]:
swept_indicators += 1
# For planar surfaces, check if they form a pattern consistent with swept geometry
elif surface_type == GeomAbs_Plane:
# Analyze if planar faces are arranged in a swept pattern
# This is a simplified check - could be enhanced further
if _has_parallel_opposite_faces(occ_shape, face):
swept_indicators += 0.5 # Partial indicator
face_explorer.Next()
# Additional check: analyze edge patterns for swept characteristics
edge_analysis = _analyze_edge_patterns(occ_shape)
# Determine if this is likely a swept shape
# If more than 50% of faces show swept characteristics, or we have strong edge patterns
swept_ratio = swept_indicators / max(total_faces, 1)
is_swept = swept_ratio > 0.5 or edge_analysis
if is_swept:
print(f"Swept shape analysis: {swept_indicators}/{total_faces} faces show swept characteristics")
if edge_analysis:
print("Edge pattern analysis also indicates swept geometry")
return is_swept
def _has_parallel_opposite_faces(shape: TopoDS_Shape, reference_face) -> bool:
"""Check if the shape has faces parallel to the reference face (indicating extrusion)."""
try:
from OCC.Core.TopExp import TopExp_Explorer
from OCC.Core.TopAbs import TopAbs_FACE
from OCC.Core.BRepAdaptor_Surface import BRepAdaptor_Surface
from OCC.Core.GeomAbs import GeomAbs_Plane
from OCC.Core.gp import gp_Vec
import math
ref_adaptor = BRepAdaptor_Surface(reference_face)
if ref_adaptor.GetType() != GeomAbs_Plane:
return False
ref_normal = ref_adaptor.Plane().Axis().Direction()
face_explorer = TopExp_Explorer(shape, TopAbs_FACE)
while face_explorer.More():
face = face_explorer.Current()
if not face.IsSame(reference_face):
face_adaptor = BRepAdaptor_Surface(face)
if face_adaptor.GetType() == GeomAbs_Plane:
face_normal = face_adaptor.Plane().Axis().Direction()
# Check if normals are parallel (dot product close to ±1)
dot_product = abs(ref_normal.Dot(face_normal))
if dot_product > 0.99: # Very close to parallel
return True
face_explorer.Next()
return False
except:
return False
def load_ifc_occ_shape(ifc_path: str) -> TopoDS_Shape:
try:
import ifcopenshell.geom as geom
except Exception as e:
raise RuntimeError("ifcopenshell.geom not available: cannot validate IFC geometry") from e
settings = geom.settings()
settings.set(settings.USE_WORLD_COORDS, True)
settings.set("use-python-opencascade", True)
# Open the IFC file
f = ifcopenshell.open(ifc_path)
# Find the first representable product (prefer IfcBuildingElementProxy, then any product with representation)
products = f.by_type("IfcProduct")
target = None
for p in products:
if p.is_a("IfcBuildingElementProxy") and getattr(p, "Representation", None):
target = p
break
if target is None:
for p in products:
if getattr(p, "Representation", None):
target = p
break
if target is None:
raise RuntimeError("No representable product found in IFC for shape extraction")
# Create the shape using ifcopenshell.geom with opencascade geometry library
shape_result = geom.create_shape(settings, target, geometry_library="opencascade")
# Extract the OpenCASCADE TopoDS_Shape from the result
# The create_shape function returns an object with an occ_shape attribute when using opencascade
if hasattr(shape_result, "geometry") and shape_result.geometry:
occ_shape = shape_result.geometry
if isinstance(occ_shape, TopoDS_Compound):
json_data = occ_shape.DumpJson()
print(json_data)
else:
raise NotImplemented(f"Unsupported shape type: {type(occ_shape)}")
return occ_shape
else:
raise RuntimeError("Failed to extract OpenCASCADE shape from IFC geometry")
def load_ifc_mesh_bbox(ifc_path: str):
"""Load first product's mesh from IFC using ifcopenshell.geom and return bbox and size."""
try:
import ifcopenshell.geom as geom
except Exception as e:
raise RuntimeError("ifcopenshell.geom not available: cannot validate IFC geometry") from e
settings = geom.settings()
settings.set(settings.USE_WORLD_COORDS, True)
f = ifcopenshell.open(ifc_path)
# Prefer the proxy we created, otherwise take any product with representation
products = f.by_type("IfcProduct")
target = None
for p in products:
if p.is_a("IfcBuildingElementProxy") and getattr(p, "Representation", None):
target = p
break
if target is None:
for p in products:
if getattr(p, "Representation", None):
target = p
break
if target is None:
raise RuntimeError("No representable product found in IFC for validation")
shape = geom.create_shape(settings, target)
verts = _triples(shape.geometry.verts)
mn, mx = _bbox_from_vertices(verts)
return mn, mx, _size_from_bbox(mn, mx)
@pytest.fixture
def test_dir():
return pathlib.Path(__file__).parent.resolve().absolute()
def test_simple_sweep_1(test_dir):
ifc_file_path = test_dir / "input_temp/simple_sweep_1.ifc"
ifc_mn, ifc_mx, ifc_sz = load_ifc_mesh_bbox(ifc_file_path)
occ_shape = load_ifc_occ_shape(ifc_file_path)
assert occ_shape is not None
assert ifc_sz == pytest.approx((1.1, 0.1, 0.89578254))
assert ifc_mn == pytest.approx((-1.0, -1.3877787807814457e-17, 0.0))
assert ifc_mx == pytest.approx((0.10000000000000002, 0.1, 0.8957825463853046))
def test_simple_sweep_2(test_dir):
ifc_file_path = test_dir / "input_temp/simple_sweep_2.ifc"
ifc_mn, ifc_mx, ifc_sz = load_ifc_mesh_bbox(ifc_file_path)
occ_shape = load_ifc_occ_shape(ifc_file_path)
assert occ_shape is not None
assert ifc_sz == pytest.approx((1.800000679914902, 0.9243618756667757, 2.0958492522636902))
assert ifc_mn == pytest.approx((-100.1, -50.0, 197.9041507477363))
assert ifc_mx == pytest.approx((-98.29999932008509, -49.075638124333224, 200.0))
def test_pipe_12d(test_dir):
ifc_file_path = test_dir / "input_temp/pipe.ifc"
ifc_mn, ifc_mx, ifc_sz = load_ifc_mesh_bbox(ifc_file_path)
occ_shape = load_ifc_occ_shape(ifc_file_path)
assert occ_shape is not None
assert ifc_sz == pytest.approx((1.1068712115520611, 6.2215114729478955, 0.35776115971654576))
assert ifc_mn == pytest.approx((289080.64128449163, 5822851.344592881, 118.70711942014172))
assert ifc_mx == pytest.approx((289081.7481557032, 5822857.566104354, 119.06488057985827))