structuralcodes 0.6.0__tar.gz → 0.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of structuralcodes might be problematic. Click here for more details.

Files changed (85) hide show
  1. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/PKG-INFO +1 -1
  2. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/__init__.py +1 -1
  3. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2004/shear.py +3 -2
  4. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/core/base.py +23 -8
  5. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/_geometry.py +98 -3
  6. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/__init__.py +14 -0
  7. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/_common_functions.py +114 -1
  8. structuralcodes-0.6.1/structuralcodes/geometry/profiles/_hd.py +374 -0
  9. structuralcodes-0.6.1/structuralcodes/geometry/profiles/_hp.py +319 -0
  10. structuralcodes-0.6.1/structuralcodes/geometry/profiles/_l.py +528 -0
  11. structuralcodes-0.6.1/structuralcodes/geometry/profiles/_li.py +217 -0
  12. structuralcodes-0.6.1/structuralcodes/geometry/profiles/_u.py +173 -0
  13. structuralcodes-0.6.1/structuralcodes/geometry/profiles/_ub.py +1356 -0
  14. structuralcodes-0.6.1/structuralcodes/geometry/profiles/_upe.py +133 -0
  15. structuralcodes-0.6.1/structuralcodes/geometry/profiles/_w.py +2157 -0
  16. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/concrete/_concreteEC2_2004.py +1 -1
  17. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/concrete/_concreteEC2_2023.py +1 -1
  18. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/concrete/_concreteMC2010.py +1 -1
  19. structuralcodes-0.6.0/structuralcodes/geometry/profiles/_ub.py +0 -264
  20. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/LICENSE +0 -0
  21. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/README.md +0 -0
  22. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/pyproject.toml +0 -0
  23. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/__init__.py +0 -0
  24. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2004/__init__.py +0 -0
  25. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2004/_concrete_creep_and_shrinkage.py +0 -0
  26. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2004/_concrete_material_properties.py +0 -0
  27. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2004/_reinforcement_material_properties.py +0 -0
  28. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py +0 -0
  29. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2023/__init__.py +0 -0
  30. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2023/_annexB_time_dependent.py +0 -0
  31. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2023/_section5_materials.py +0 -0
  32. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/ec2_2023/_section9_sls.py +0 -0
  33. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/__init__.py +0 -0
  34. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/_concrete_creep_and_shrinkage.py +0 -0
  35. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/_concrete_interface_different_casting_times.py +0 -0
  36. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/_concrete_material_properties.py +0 -0
  37. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/_concrete_punching.py +0 -0
  38. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/_concrete_shear.py +0 -0
  39. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/_concrete_torsion.py +0 -0
  40. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/_interface_concrete_steel_rebar.py +0 -0
  41. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2010/_reinforcement_material_properties.py +0 -0
  42. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/codes/mc2020/__init__.py +0 -0
  43. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/core/__init__.py +0 -0
  44. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/core/_marin_integration.py +0 -0
  45. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/core/_section_results.py +0 -0
  46. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/__init__.py +0 -0
  47. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/_circular.py +0 -0
  48. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/_rectangular.py +0 -0
  49. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/_reinforcement.py +0 -0
  50. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/_base_profile.py +0 -0
  51. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/_he.py +0 -0
  52. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/_ipe.py +0 -0
  53. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/_ipn.py +0 -0
  54. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/_ubp.py +0 -0
  55. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/_uc.py +0 -0
  56. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/geometry/profiles/_upn.py +0 -0
  57. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/__init__.py +0 -0
  58. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/basic/__init__.py +0 -0
  59. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/basic/_elastic.py +0 -0
  60. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/basic/_elasticplastic.py +0 -0
  61. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/basic/_generic.py +0 -0
  62. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/concrete/__init__.py +0 -0
  63. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/concrete/_concrete.py +0 -0
  64. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/__init__.py +0 -0
  65. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/_bilinearcompression.py +0 -0
  66. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/_elastic.py +0 -0
  67. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/_elasticplastic.py +0 -0
  68. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/_initial_strain.py +0 -0
  69. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/_parabolarectangle.py +0 -0
  70. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/_popovics.py +0 -0
  71. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/_sargin.py +0 -0
  72. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/constitutive_laws/_userdefined.py +0 -0
  73. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/reinforcement/__init__.py +0 -0
  74. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/reinforcement/_reinforcement.py +0 -0
  75. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/reinforcement/_reinforcementEC2_2004.py +0 -0
  76. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/reinforcement/_reinforcementEC2_2023.py +0 -0
  77. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/materials/reinforcement/_reinforcementMC2010.py +0 -0
  78. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/sections/__init__.py +0 -0
  79. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/sections/_generic.py +0 -0
  80. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/sections/_rc_utils.py +0 -0
  81. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/sections/section_integrators/__init__.py +0 -0
  82. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/sections/section_integrators/_factory.py +0 -0
  83. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/sections/section_integrators/_fiber_integrator.py +0 -0
  84. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/sections/section_integrators/_marin_integrator.py +0 -0
  85. {structuralcodes-0.6.0 → structuralcodes-0.6.1}/structuralcodes/sections/section_integrators/_section_integrator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structuralcodes
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: A Python package that contains models from structural design codes.
5
5
  Author-email: fib - International Federation for Structural Concrete <info@fib-international.org>
6
6
  Requires-Python: >=3.9
@@ -3,7 +3,7 @@
3
3
  from . import codes, core, geometry, materials, sections
4
4
  from .codes import get_design_codes, set_design_code, set_national_annex
5
5
 
6
- __version__ = '0.6.0'
6
+ __version__ = '0.6.1'
7
7
 
8
8
  __all__ = [
9
9
  'set_design_code',
@@ -203,14 +203,15 @@ def VRdc(
203
203
  float: The concrete shear resistance in MPa.
204
204
  """
205
205
  CRdc = CRdc or 0.18 / gamma_c
206
- return (
206
+ return max(
207
207
  max(
208
208
  CRdc * _k(d) * (100 * _rho_L(Asl, bw, d) * fck) ** (1.0 / 3.0)
209
209
  + k1 * _sigma_cp(NEd, Ac, fcd), # VRdc
210
210
  vmin(fck, d) + k1 * _sigma_cp(NEd, Ac, fcd), # VRdcmin
211
211
  )
212
212
  * bw
213
- * d
213
+ * d,
214
+ 0,
214
215
  )
215
216
 
216
217
 
@@ -287,14 +287,29 @@ class ConstitutiveLaw(abc.ABC):
287
287
  piecewise_law = self._discretize_law()
288
288
  return piecewise_law.__marin_tangent__(**kwargs)
289
289
 
290
- def get_secant(self, eps: float) -> float:
291
- """Method to return the
292
- secant at a given strain level.
293
- """
294
- if eps != 0:
295
- sig = self.get_stress(eps)
296
- return sig / eps
297
- return self.get_tangent(eps)
290
+ def get_secant(
291
+ self, eps: t.Union[float, ArrayLike]
292
+ ) -> t.Union[float, ArrayLike]:
293
+ """Method to return the secant at a given strain level."""
294
+ # Adjust eps if it is not scalar
295
+ eps = eps if np.isscalar(eps) else np.atleast_1d(eps)
296
+
297
+ # Calculate secant for scalar eps
298
+ if np.isscalar(eps):
299
+ if eps != 0:
300
+ sig = self.get_stress(eps)
301
+ return sig / eps
302
+ return self.get_tangent(eps)
303
+
304
+ # Calculate secant for array eps
305
+ secant = np.zeros_like(eps)
306
+ strain_is_zero = eps == 0
307
+ strain_is_nonzero = eps != 0
308
+ secant[strain_is_zero] = self.get_tangent(eps[strain_is_zero])
309
+ secant[strain_is_nonzero] = (
310
+ self.get_stress(eps[strain_is_nonzero]) / eps[strain_is_nonzero]
311
+ )
312
+ return secant
298
313
 
299
314
 
300
315
  class Section(abc.ABC):
@@ -4,6 +4,7 @@ from __future__ import annotations # To have clean hints of ArrayLike in docs
4
4
 
5
5
  import typing as t
6
6
  import warnings
7
+ from math import atan2
7
8
 
8
9
  import numpy as np
9
10
  from numpy.typing import ArrayLike
@@ -23,6 +24,39 @@ from structuralcodes.materials.basic import ElasticMaterial
23
24
  from structuralcodes.materials.concrete import Concrete
24
25
 
25
26
 
27
+ def _mirror_about_axis_matrix(axis: LineString) -> np.ndarray:
28
+ if not isinstance(axis, LineString):
29
+ raise TypeError('axis should be a shapely LineString object')
30
+
31
+ (x1, y1), (x2, y2) = axis.coords
32
+
33
+ # angle of the line with respect to the horizontal axis
34
+ dx, dy = x2 - x1, y2 - y1
35
+ theta = atan2(dy, dx)
36
+
37
+ # Translation matrix T (move line start to origin)
38
+ T = np.array([[1, 0, -x1], [0, 1, -y1], [0, 0, 1]])
39
+
40
+ # Rotation matrix R (align line with x-axis)
41
+ R = np.array(
42
+ [
43
+ [np.cos(theta), np.sin(theta), 0],
44
+ [-np.sin(theta), np.cos(theta), 0],
45
+ [0, 0, 1],
46
+ ]
47
+ )
48
+
49
+ # Mirror across x-axis
50
+ M = np.array([[1, 0, 0], [0, -1, 0], [0, 0, 1]])
51
+
52
+ # Inverses of T and R
53
+ T_inv = np.linalg.inv(T)
54
+ R_inv = np.linalg.inv(R)
55
+
56
+ # Final transformation matrix
57
+ return T_inv @ R_inv @ M @ R @ T
58
+
59
+
26
60
  class Geometry:
27
61
  """Base class for a geometry object."""
28
62
 
@@ -229,6 +263,31 @@ class PointGeometry(Geometry):
229
263
  group_label=self._group_label,
230
264
  )
231
265
 
266
+ def mirror(self, axis: LineString) -> PointGeometry:
267
+ """Returns a new PointGeometry that is mirrored with respect to the
268
+ axis.
269
+
270
+ Arguments:
271
+ axis (LineString): The axis to mirror about.
272
+
273
+ Returns:
274
+ PointGeometry: The mirrored PointGeometry.
275
+ """
276
+ if not isinstance(axis, LineString):
277
+ raise TypeError('axis should be a shapely LineString object')
278
+
279
+ # Build the transformation matrix
280
+ A = _mirror_about_axis_matrix(axis)
281
+ # Apply the transformation to the point
282
+ params = [A[0, 0], A[0, 1], A[1, 0], A[1, 1], A[0, 2], A[1, 2]]
283
+ return PointGeometry(
284
+ point=affinity.affine_transform(self._point, params),
285
+ diameter=self._diameter,
286
+ material=self._material,
287
+ name=self._name,
288
+ group_label=self._group_label,
289
+ )
290
+
232
291
  @staticmethod
233
292
  def from_geometry(
234
293
  geo: PointGeometry,
@@ -552,6 +611,28 @@ class SurfaceGeometry(Geometry):
552
611
  concrete=self.concrete,
553
612
  )
554
613
 
614
+ def mirror(self, axis: LineString) -> SurfaceGeometry:
615
+ """Returns a new SurfaceGeometry that is mirrored about the given axis.
616
+
617
+ Arguments:
618
+ axis (LineString): The axis to mirror about.
619
+
620
+ Returns:
621
+ SurfaceGeometry: The mirrored SurfaceGeometry.
622
+ """
623
+ if not isinstance(axis, LineString):
624
+ raise TypeError('axis should be a shapely LineString object')
625
+ # Build the transformation matrix
626
+ A = _mirror_about_axis_matrix(axis)
627
+ # Apply transformation matrix A
628
+ # Apply the transformation to the polygon
629
+ params = [A[0, 0], A[0, 1], A[1, 0], A[1, 1], A[0, 2], A[1, 2]]
630
+ return SurfaceGeometry(
631
+ poly=affinity.affine_transform(self.polygon, params),
632
+ material=self.material,
633
+ concrete=self.concrete,
634
+ )
635
+
555
636
  @staticmethod
556
637
  def from_geometry(
557
638
  geo: SurfaceGeometry,
@@ -595,9 +676,6 @@ class SurfaceGeometry(Geometry):
595
676
  # from_surface_geometry
596
677
  # from_dxf
597
678
  # from_ascii
598
- # ...
599
- # we could also add methods wrapping shapely function, like:
600
- # mirror, translation, rotation, etc.
601
679
 
602
680
 
603
681
  def _process_geometries_multipolygon(
@@ -789,6 +867,23 @@ class CompoundGeometry(Geometry):
789
867
  processed_geoms.append(pg.rotate(angle, point, use_radians))
790
868
  return CompoundGeometry(geometries=processed_geoms)
791
869
 
870
+ def mirror(self, axis: LineString) -> CompoundGeometry:
871
+ """Returns a new CompoundGeometry that is mirrored about the given
872
+ axis.
873
+
874
+ Arguments:
875
+ axis (LineString): The axis to mirror about.
876
+
877
+ Returns:
878
+ CompoundGeometry: The mirrored CompoundGeometry.
879
+ """
880
+ processed_geoms = []
881
+ for g in self.geometries:
882
+ processed_geoms.append(g.mirror(axis))
883
+ for pg in self.point_geometries:
884
+ processed_geoms.append(pg.mirror(axis))
885
+ return CompoundGeometry(geometries=processed_geoms)
886
+
792
887
  def __sub__(self, other: Geometry) -> CompoundGeometry:
793
888
  """Add operator "-" for geometries.
794
889
 
@@ -1,19 +1,33 @@
1
1
  """Main entry point for profiles."""
2
2
 
3
+ from ._hd import HD
3
4
  from ._he import HE
5
+ from ._hp import HP
4
6
  from ._ipe import IPE
5
7
  from ._ipn import IPN
8
+ from ._l import L
9
+ from ._li import LI
10
+ from ._u import U
6
11
  from ._ub import UB
7
12
  from ._ubp import UBP
8
13
  from ._uc import UC
14
+ from ._upe import UPE
9
15
  from ._upn import UPN
16
+ from ._w import W
10
17
 
11
18
  __all__ = [
12
19
  'HE',
20
+ 'HP',
21
+ 'HD',
13
22
  'IPE',
14
23
  'IPN',
15
24
  'UB',
16
25
  'UBP',
17
26
  'UC',
18
27
  'UPN',
28
+ 'UPE',
29
+ 'U',
30
+ 'W',
31
+ 'L',
32
+ 'LI',
19
33
  ]
@@ -1,5 +1,7 @@
1
1
  """Common functions for creating profiles."""
2
2
 
3
+ import math
4
+
3
5
  import numpy as np
4
6
  from shapely import (
5
7
  LineString,
@@ -59,9 +61,17 @@ def _create_I_section(h: float, b: float, tw: float, tf: float, r: float):
59
61
  fillet = translate(
60
62
  scale(fillet, 1, -1), xoff=0, yoff=h - 2 * tf - r
61
63
  ).union(fillet)
64
+
65
+ # Estimate grid_size value
66
+ # Tentative geometry (due to approximations can be a MultiPolygon)
67
+ geom_trial = unary_union([fillet, top_flange, bottom_flange, web])
68
+ # minx, miny, maxx, maxy
69
+ bounds = geom_trial.bounds
70
+ min_size = min(bounds[2] - bounds[0], bounds[3] - bounds[1])
71
+ grid_size = 10 ** int(math.floor(math.log10(abs(min_size)))) * 1e-12
62
72
  # Create the geometry
63
73
  geometries = [
64
- set_precision(geometry, grid_size=1e-13)
74
+ set_precision(geometry, grid_size=grid_size)
65
75
  for geometry in [fillet, top_flange, bottom_flange, web]
66
76
  ]
67
77
  return orient(unary_union(geometries), 1)
@@ -192,3 +202,106 @@ def _create_taper_U_section(
192
202
  return orient(
193
203
  translate(poly, xoff=-poly.centroid.x, yoff=-poly.centroid.y), 1
194
204
  )
205
+
206
+
207
+ def _create_parallel_U_section(
208
+ h: float,
209
+ b: float,
210
+ tw: float,
211
+ tf: float,
212
+ r: float,
213
+ ) -> Polygon:
214
+ """Returns a shapely polygon representing a Parallel Flange U Section."""
215
+ # top flange
216
+ top_flange = Polygon(
217
+ [
218
+ (0, h / 2 - tf),
219
+ (b, h / 2 - tf),
220
+ (b, h / 2),
221
+ (0, h / 2),
222
+ ]
223
+ )
224
+ # bottom flange
225
+ bottom_flange = translate(top_flange, xoff=0, yoff=-h + tf)
226
+ web = Polygon(
227
+ [
228
+ (0, -h / 2 + tf),
229
+ (tw, -h / 2 + tf),
230
+ (tw, h / 2 - tf),
231
+ (0, h / 2 - tf),
232
+ ]
233
+ )
234
+ # fillets
235
+ p = Point([tw + r, -h / 2 + tf + r]).buffer(r)
236
+ s = Polygon(
237
+ [
238
+ (tw, -h / 2 + tf),
239
+ (tw + r, -h / 2 + tf),
240
+ (tw + r, -h / 2 + tf + r),
241
+ (tw, -h / 2 + tf + r),
242
+ ]
243
+ )
244
+ fillet = s.difference(p)
245
+ fillet = translate(
246
+ scale(fillet, 1, -1), xoff=0, yoff=h - 2 * tf - r
247
+ ).union(fillet)
248
+ # Estimate grid_size value
249
+ # Tentative geometry (due to approximations can be a MultiPolygon)
250
+ geom_trial = unary_union([fillet, top_flange, bottom_flange, web])
251
+ # minx, miny, maxx, maxy
252
+ bounds = geom_trial.bounds
253
+ min_size = min(bounds[2] - bounds[0], bounds[3] - bounds[1])
254
+ grid_size = 10 ** int(math.floor(math.log10(abs(min_size)))) * 1e-12
255
+ # Create the geometry
256
+ geometries = [
257
+ set_precision(geometry, grid_size=grid_size)
258
+ for geometry in [fillet, top_flange, bottom_flange, web]
259
+ ]
260
+ geometry = orient(unary_union(geometries), 1)
261
+ # Return the geometry centered at the origin
262
+ return translate(
263
+ geometry, xoff=-geometry.centroid.x, yoff=-geometry.centroid.y
264
+ )
265
+
266
+
267
+ def _create_L_section(
268
+ h: float, b: float, t1: float, t2: float, r1: float, r2: float
269
+ ) -> Polygon:
270
+ """Returns a shapely polygon representing a L Section."""
271
+ # Create first part of line
272
+ ls = [set_precision(LineString([[0, h], [0, 0], [b, 0]]), grid_size=1e-13)]
273
+ # Create fillet
274
+ xy = np.array([[b, 0], [b, t1], [b / 2, t1]])
275
+ ls.append(
276
+ set_precision(
277
+ LineString(xy).offset_curve(r2).offset_curve(-r2), grid_size=1e-13
278
+ )
279
+ )
280
+ # Create second fillet
281
+ xy = np.array([[b / 2, t1], [t2, t1], [t2, h / 2]])
282
+ ls.append(
283
+ set_precision(
284
+ LineString(xy).offset_curve(-r1).offset_curve(r1), grid_size=1e-13
285
+ )
286
+ )
287
+ # Last fillet
288
+ xy = np.array([[t2, h / 2], [t2, h], [0, h]])
289
+ ls.append(
290
+ set_precision(
291
+ LineString(xy).offset_curve(r2).offset_curve(-r2), grid_size=1e-13
292
+ )
293
+ )
294
+ # Merge filleted
295
+ merged_ls = linemerge(ls)
296
+
297
+ merged_ls
298
+
299
+ # Create a polygon
300
+ poly = polygonize([merged_ls])
301
+
302
+ # Return the first and only polygon of this collection
303
+ poly = get_geometry(poly, 0)
304
+ # Translate it to the centroid when returning
305
+ return orient(
306
+ translate(poly, xoff=-poly.centroid.x, yoff=-poly.centroid.y), 1
307
+ )