|
37 | 37 | import ifcopenshell.util.representation |
38 | 38 | from typing import cast |
39 | 39 | import ifcplus.util.geometry |
| 40 | +import ifcplus.util.project |
40 | 41 |
|
41 | 42 | BUILT_ELEMENT_FRAME_MEMBER = Literal["IfcBeam", "IfcColumn", "IfcMember"] |
42 | 43 |
|
@@ -357,127 +358,250 @@ def create_2pt_wall( |
357 | 358 | return wall |
358 | 359 |
|
359 | 360 |
|
360 | | -# def create_curved_wall( |
361 | | -# point_of_curvature_2d: tuple[float, float], |
362 | | -# point_on_center_of_curvature_side_2d: tuple[float, float], |
363 | | -# point_of_tangency_2d: tuple[float, float], |
364 | | -# elevation: float, |
365 | | -# height: float, |
366 | | -# materials: list[ifcopenshell.entity_instance], |
367 | | -# thicknesses: list[float], |
368 | | -# wall: ifcopenshell.entity_instance | None = None, |
369 | | -# name: str | None = None, |
370 | | -# parent: ifcopenshell.entity_instance | None = None, |
371 | | -# place_object_relative_to_parent: bool = False, |
372 | | -# ): |
373 | | -# """Add straight IfcWall with IfcMaterialLayerSetUsage based on two points in |
374 | | -# XY space.""" |
375 | | - |
376 | | -# ifc4_file = materials[0].file |
377 | | - |
378 | | -# material_layer_set = ifcplus.api.material.add_material_layer_set( |
379 | | -# materials=materials, |
380 | | -# thicknesses=thicknesses, |
381 | | -# name=None, |
382 | | -# check_for_duplicate=True, |
383 | | -# ) |
384 | | - |
385 | | -# wall_type = ifcplus.api.element_type.add_element_type_for_material_layer_set( |
386 | | -# ifc_class="IfcWallType", |
387 | | -# material_layer_set=material_layer_set, |
388 | | -# name=material_layer_set.LayerSetName, |
389 | | -# check_for_duplicate=True, |
390 | | -# ) |
391 | | - |
392 | | -# if wall is None: |
393 | | -# wall = ifcopenshell.api.root.create_entity( |
394 | | -# file=ifc4_file, |
395 | | -# ifc_class="IfcWall", |
396 | | -# name=name, |
397 | | -# predefined_type="NOTDEFINED", |
398 | | -# ) |
399 | | - |
400 | | -# ifcopenshell.api.type.assign_type( |
401 | | -# file=ifc4_file, |
402 | | -# related_objects=[wall], |
403 | | -# relating_type=wall_type, |
404 | | -# ) |
405 | | - |
406 | | -# total_thickness = 0.0 |
407 | | -# for material_layer in material_layer_set.MaterialLayers: |
408 | | -# total_thickness += material_layer.LayerThickness |
409 | | - |
410 | | -# rel_associates_material = ifcopenshell.api.material.assign_material( |
411 | | -# file=ifc4_file, |
412 | | -# products=[wall], |
413 | | -# type="IfcMaterialLayerSetUsage", |
414 | | -# material=None, # inferred from assigned IfcElementType |
415 | | -# ) |
416 | | -# material_layer_set_usage = cast( |
417 | | -# ifcopenshell.entity_instance, rel_associates_material |
418 | | -# ).RelatingMaterial |
419 | | -# material_layer_set_usage.OffsetFromReferenceLine = -total_thickness / 2 |
420 | | - |
421 | | -# point_of_curvature_3d = (start_point_2d[0], start_point_2d[1], elevation) |
422 | | -# end_point_3d = (end_point_2d[0], end_point_2d[1], elevation) |
423 | | -# vector_from_start_point_to_end_point = np.array(end_point_3d) - np.array( |
424 | | -# start_point_3d |
425 | | -# ) |
426 | | -# length = float(np.linalg.norm(vector_from_start_point_to_end_point)) |
427 | | - |
428 | | -# representation_item = ifcplus.api.geometry.add_extruded_area_solid( |
429 | | -# ifc4_file=ifc4_file, |
430 | | -# profile=ifcplus.api.profile.add_arbitrary_profile_with_or_without_voids( |
431 | | -# file=ifc4_file, |
432 | | -# outer_profile=[ |
433 | | -# (0.0, 0.0 - total_thickness / 2), |
434 | | -# (0.0 + length, 0.0 - total_thickness / 2), |
435 | | -# (0.0 + length, 0.0 + total_thickness - total_thickness / 2), |
436 | | -# (0.0 + length - length, 0.0 + total_thickness - total_thickness / 2), |
437 | | -# (0.0, 0.0 - total_thickness / 2), |
438 | | -# ], |
439 | | -# inner_profiles=[], |
440 | | -# name=None, |
441 | | -# ), |
442 | | -# extrusion_depth=height, |
443 | | -# ) |
444 | | - |
445 | | -# representation_type = ifcopenshell.util.representation.guess_type( |
446 | | -# items=[representation_item] |
447 | | -# ) |
448 | | - |
449 | | -# shape_model = ifcplus.api.geometry.add_shape_model( |
450 | | -# ifc4_file=ifc4_file, |
451 | | -# shape_model_class="IfcShapeRepresentation", |
452 | | -# representation_identifier="Body", |
453 | | -# representation_type=cast(str, representation_type), # SweptSolid |
454 | | -# context_type="Model", |
455 | | -# target_view="MODEL_VIEW", |
456 | | -# items=[representation_item], |
457 | | -# ) |
458 | | - |
459 | | -# ifcopenshell.api.geometry.assign_representation( |
460 | | -# file=ifc4_file, |
461 | | -# product=wall, |
462 | | -# representation=shape_model, |
463 | | -# ) |
464 | | - |
465 | | -# if isinstance(parent, ifcopenshell.entity_instance): |
466 | | -# ifcopenshell.api.spatial.assign_container( |
467 | | -# file=ifc4_file, |
468 | | -# products=[wall], |
469 | | -# relating_structure=parent, |
470 | | -# ) |
471 | | - |
472 | | -# ifcplus.api.placement.edit_object_placement( |
473 | | -# product=wall, |
474 | | -# repositioned_origin=start_point_3d, |
475 | | -# repositioned_x_axis=tuple(vector_from_start_point_to_end_point.tolist()), |
476 | | -# repositioned_z_axis=(0.0, 0.0, 1.0), |
477 | | -# place_object_relative_to_parent=place_object_relative_to_parent, |
478 | | -# ) |
479 | | - |
480 | | -# return wall |
| 361 | +def create_curved_wall( |
| 362 | + point_of_curvature_2d: tuple[float, float], |
| 363 | + point_on_center_of_curvature_side_2d: tuple[float, float], |
| 364 | + point_of_tangency_2d: tuple[float, float], |
| 365 | + radius_of_curvature: float, |
| 366 | + elevation: float, |
| 367 | + height: float, |
| 368 | + materials: list[ifcopenshell.entity_instance], |
| 369 | + thicknesses: list[float], |
| 370 | + wall: ifcopenshell.entity_instance | None = None, |
| 371 | + name: str | None = None, |
| 372 | + parent: ifcopenshell.entity_instance | None = None, |
| 373 | + place_object_relative_to_parent: bool = False, |
| 374 | +): |
| 375 | + """Add straight IfcWall with IfcMaterialLayerSetUsage based on two points in |
| 376 | + XY space.""" |
| 377 | + |
| 378 | + ifc4_file = materials[0].file |
| 379 | + |
| 380 | + numeric_scale = ifcplus.util.project.get_numeric_scale_of_project( |
| 381 | + ifc4_file=ifc4_file, |
| 382 | + ) |
| 383 | + |
| 384 | + material_layer_set = ifcplus.api.material.add_material_layer_set( |
| 385 | + materials=materials, |
| 386 | + thicknesses=thicknesses, |
| 387 | + name=None, |
| 388 | + check_for_duplicate=True, |
| 389 | + ) |
| 390 | + |
| 391 | + wall_type = ifcplus.api.element_type.add_element_type_for_material_layer_set( |
| 392 | + ifc_class="IfcWallType", |
| 393 | + material_layer_set=material_layer_set, |
| 394 | + name=material_layer_set.LayerSetName, |
| 395 | + check_for_duplicate=True, |
| 396 | + ) |
| 397 | + |
| 398 | + if wall is None: |
| 399 | + wall = ifcopenshell.api.root.create_entity( |
| 400 | + file=ifc4_file, |
| 401 | + ifc_class="IfcWall", |
| 402 | + name=name, |
| 403 | + predefined_type="NOTDEFINED", |
| 404 | + ) |
| 405 | + |
| 406 | + ifcopenshell.api.type.assign_type( |
| 407 | + file=ifc4_file, |
| 408 | + related_objects=[wall], |
| 409 | + relating_type=wall_type, |
| 410 | + ) |
| 411 | + |
| 412 | + total_thickness = 0.0 |
| 413 | + for material_layer in material_layer_set.MaterialLayers: |
| 414 | + total_thickness += material_layer.LayerThickness |
| 415 | + |
| 416 | + rel_associates_material = ifcopenshell.api.material.assign_material( |
| 417 | + file=ifc4_file, |
| 418 | + products=[wall], |
| 419 | + type="IfcMaterialLayerSetUsage", |
| 420 | + material=None, # inferred from assigned IfcElementType |
| 421 | + ) |
| 422 | + material_layer_set_usage = cast( |
| 423 | + ifcopenshell.entity_instance, rel_associates_material |
| 424 | + ).RelatingMaterial |
| 425 | + material_layer_set_usage.OffsetFromReferenceLine = -total_thickness / 2 |
| 426 | + |
| 427 | + radius_of_curvature_for_middle_curve = radius_of_curvature |
| 428 | + point_of_curvature_3d_for_middle_curve = ( |
| 429 | + point_of_curvature_2d[0], |
| 430 | + point_of_curvature_2d[1], |
| 431 | + elevation, |
| 432 | + ) |
| 433 | + point_of_tangency_3d_for_middle_curve = ( |
| 434 | + point_of_tangency_2d[0], |
| 435 | + point_of_tangency_2d[1], |
| 436 | + elevation, |
| 437 | + ) |
| 438 | + point_on_center_of_curvature_side_3d_for_middle_curve = ( |
| 439 | + point_on_center_of_curvature_side_2d[0], |
| 440 | + point_on_center_of_curvature_side_2d[1], |
| 441 | + elevation, |
| 442 | + ) |
| 443 | + |
| 444 | + middle_horizontal_curve = ifcplus.util.geometry.HorizontalCurve.from_PC_and_PT_and_CC( |
| 445 | + point_of_curvature=point_of_curvature_3d_for_middle_curve, |
| 446 | + point_on_center_of_curvature_side=point_on_center_of_curvature_side_3d_for_middle_curve, |
| 447 | + point_of_tangency=point_of_tangency_3d_for_middle_curve, |
| 448 | + radius_of_curvature=radius_of_curvature_for_middle_curve, |
| 449 | + ) |
| 450 | + |
| 451 | + point_of_center_of_curvature_3d_for_all_curves = ( |
| 452 | + middle_horizontal_curve.center_of_curvature |
| 453 | + ) |
| 454 | + |
| 455 | + unit_vector_from_CC_to_PC = ( |
| 456 | + ifcplus.util.geometry.calculate_unit_direction_vector_between_two_points( |
| 457 | + p1=point_of_center_of_curvature_3d_for_all_curves, |
| 458 | + p2=point_of_curvature_3d_for_middle_curve, |
| 459 | + ) |
| 460 | + ) |
| 461 | + unit_vector_from_CC_to_PT = ( |
| 462 | + ifcplus.util.geometry.calculate_unit_direction_vector_between_two_points( |
| 463 | + p1=point_of_center_of_curvature_3d_for_all_curves, |
| 464 | + p2=point_of_tangency_3d_for_middle_curve, |
| 465 | + ) |
| 466 | + ) |
| 467 | + |
| 468 | + radius_of_curvature_for_inner_curve = ( |
| 469 | + radius_of_curvature_for_middle_curve - total_thickness / 2.0 |
| 470 | + ) |
| 471 | + point_of_curvature_3d_for_inner_curve = tuple( |
| 472 | + ( |
| 473 | + np.array(point_of_center_of_curvature_3d_for_all_curves) |
| 474 | + + np.array(unit_vector_from_CC_to_PC) * radius_of_curvature_for_inner_curve |
| 475 | + ).tolist() |
| 476 | + ) |
| 477 | + point_of_tangency_3d_for_inner_curve = tuple( |
| 478 | + ( |
| 479 | + np.array(point_of_center_of_curvature_3d_for_all_curves) |
| 480 | + + np.array(unit_vector_from_CC_to_PT) * radius_of_curvature_for_inner_curve |
| 481 | + ).tolist() |
| 482 | + ) |
| 483 | + inner_horizontal_curve = ifcplus.util.geometry.HorizontalCurve.from_PC_and_PT_and_CC( |
| 484 | + point_of_curvature=point_of_curvature_3d_for_inner_curve, |
| 485 | + point_on_center_of_curvature_side=point_of_center_of_curvature_3d_for_all_curves, |
| 486 | + point_of_tangency=point_of_tangency_3d_for_inner_curve, |
| 487 | + radius_of_curvature=radius_of_curvature_for_inner_curve, |
| 488 | + ) |
| 489 | + |
| 490 | + radius_of_curvature_for_outer_curve = ( |
| 491 | + radius_of_curvature_for_middle_curve + total_thickness / 2.0 |
| 492 | + ) |
| 493 | + point_of_curvature_3d_for_outer_curve = tuple( |
| 494 | + ( |
| 495 | + np.array(point_of_center_of_curvature_3d_for_all_curves) |
| 496 | + + np.array(unit_vector_from_CC_to_PC) * radius_of_curvature_for_outer_curve |
| 497 | + ).tolist() |
| 498 | + ) |
| 499 | + point_of_tangency_3d_for_outer_curve = tuple( |
| 500 | + ( |
| 501 | + np.array(point_of_center_of_curvature_3d_for_all_curves) |
| 502 | + + np.array(unit_vector_from_CC_to_PT) * radius_of_curvature_for_outer_curve |
| 503 | + ).tolist() |
| 504 | + ) |
| 505 | + outer_horizontal_curve = ifcplus.util.geometry.HorizontalCurve.from_PC_and_PT_and_CC( |
| 506 | + point_of_curvature=point_of_curvature_3d_for_outer_curve, |
| 507 | + point_on_center_of_curvature_side=point_of_center_of_curvature_3d_for_all_curves, |
| 508 | + point_of_tangency=point_of_tangency_3d_for_outer_curve, |
| 509 | + radius_of_curvature=radius_of_curvature_for_outer_curve, |
| 510 | + ) |
| 511 | + |
| 512 | + points_list_3d = [ |
| 513 | + inner_horizontal_curve.point_of_curvature, |
| 514 | + outer_horizontal_curve.point_of_curvature, |
| 515 | + outer_horizontal_curve.point_at_midpoint_of_curve, |
| 516 | + outer_horizontal_curve.point_of_tangency, |
| 517 | + inner_horizontal_curve.point_of_tangency, |
| 518 | + inner_horizontal_curve.point_at_midpoint_of_curve, |
| 519 | + ] |
| 520 | + |
| 521 | + points_list_2d = [] |
| 522 | + for point_3d in points_list_3d: |
| 523 | + point_3d_relative_to_PC_of_middle_curve = tuple( |
| 524 | + np.round( |
| 525 | + ( |
| 526 | + np.array(point_3d) |
| 527 | + - np.array(middle_horizontal_curve.point_of_curvature) |
| 528 | + ), |
| 529 | + numeric_scale, |
| 530 | + ).tolist() |
| 531 | + ) |
| 532 | + points_list_2d.append(point_3d_relative_to_PC_of_middle_curve[0:2]) |
| 533 | + |
| 534 | + cartesian_point_list = ifc4_file.create_entity( |
| 535 | + type="IfcCartesianPointList2D", |
| 536 | + CoordList=points_list_2d, |
| 537 | + ) |
| 538 | + |
| 539 | + indexed_polycurve = ifc4_file.create_entity( |
| 540 | + type="IfcIndexedPolyCurve", |
| 541 | + Points=cartesian_point_list, |
| 542 | + Segments=[ |
| 543 | + ifc4_file.create_entity("IfcLineIndex", [1, 2]), |
| 544 | + ifc4_file.create_entity("IfcArcIndex", [2, 3, 4]), |
| 545 | + ifc4_file.create_entity("IfcLineIndex", [4, 5]), |
| 546 | + ifc4_file.create_entity("IfcArcIndex", [5, 6, 1]), |
| 547 | + ], |
| 548 | + SelfIntersect=False, |
| 549 | + ) |
| 550 | + |
| 551 | + arbitrary_closed_profile_def = ifc4_file.create_entity( |
| 552 | + type="IfcArbitraryClosedProfileDef", |
| 553 | + ProfileType="AREA", |
| 554 | + ProfileName=name, |
| 555 | + OuterCurve=indexed_polycurve, |
| 556 | + ) |
| 557 | + |
| 558 | + extruded_area_solid = ifcplus.api.geometry.add_extruded_area_solid( |
| 559 | + ifc4_file=ifc4_file, |
| 560 | + profile=arbitrary_closed_profile_def, |
| 561 | + extrusion_depth=height, |
| 562 | + ) |
| 563 | + |
| 564 | + shape_representation = ifcplus.api.geometry.add_shape_model( |
| 565 | + ifc4_file=ifc4_file, |
| 566 | + shape_model_class="IfcShapeRepresentation", |
| 567 | + representation_identifier="Body", |
| 568 | + representation_type=cast( |
| 569 | + str, |
| 570 | + ifcopenshell.util.representation.guess_type(items=[extruded_area_solid]), |
| 571 | + ), # SweptSolid |
| 572 | + context_type="Model", |
| 573 | + target_view="MODEL_VIEW", |
| 574 | + items=[extruded_area_solid], |
| 575 | + ) |
| 576 | + |
| 577 | + ifcopenshell.api.geometry.assign_representation( |
| 578 | + file=ifc4_file, |
| 579 | + product=wall, |
| 580 | + representation=shape_representation, |
| 581 | + ) |
| 582 | + |
| 583 | + if isinstance(parent, ifcopenshell.entity_instance): |
| 584 | + ifcopenshell.api.spatial.assign_container( |
| 585 | + file=ifc4_file, |
| 586 | + products=[wall], |
| 587 | + relating_structure=parent, |
| 588 | + ) |
| 589 | + |
| 590 | + unit_vector_from_PC_to_PI = ( |
| 591 | + ifcplus.util.geometry.calculate_unit_direction_vector_between_two_points( |
| 592 | + p1=middle_horizontal_curve.point_of_curvature, |
| 593 | + p2=middle_horizontal_curve.point_of_intersection, |
| 594 | + ) |
| 595 | + ) |
| 596 | + ifcplus.api.placement.edit_object_placement( |
| 597 | + product=wall, |
| 598 | + repositioned_origin=middle_horizontal_curve.point_of_curvature, |
| 599 | + repositioned_x_axis=unit_vector_from_PC_to_PI, |
| 600 | + repositioned_z_axis=(0.0, 0.0, 1.0), |
| 601 | + place_object_relative_to_parent=place_object_relative_to_parent, |
| 602 | + ) |
| 603 | + |
| 604 | + return wall |
481 | 605 |
|
482 | 606 |
|
483 | 607 | def create_npt_slab( |
|
0 commit comments