Repository: robbievanleeuwen/section-properties (language: python)

Issue:
Docs/examples



Discussion / hints:

Fix patch:
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 01b2ea3d..2009e4bf 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -10,7 +10,7 @@
 import locale
 
 
-locale.setlocale(locale.LC_ALL, '')
+locale.setlocale(locale.LC_ALL, "")
 
 # -- Path setup --------------------------------------------------------------
 
@@ -50,10 +50,10 @@
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 extensions = [
-    'sphinx.ext.autodoc',
-    'sphinx.ext.mathjax',
-    'sphinx.ext.viewcode',
-    'sphinx_gallery.gen_gallery',
+    "sphinx.ext.autodoc",
+    "sphinx.ext.mathjax",
+    "sphinx.ext.viewcode",
+    "sphinx_gallery.gen_gallery",
 ]
 
 # Add any paths that contain templates here, relative to this directory.
@@ -181,23 +181,23 @@
 
 sphinx_gallery_conf = {
     # convert rst to md for ipynb
-    'pypandoc': False,
+    "pypandoc": False,
     # path to your examples scripts
-    'examples_dirs': ['../../examples/'],
+    "examples_dirs": ["../../examples/"],
     # path where to save gallery generated examples
-    'gallery_dirs': ['sphinx_gallery_examples'],
+    "gallery_dirs": ["sphinx_gallery_examples"],
     # Patter to search for example files
-    'filename_pattern': r'\.py',
+    "filename_pattern": r"\.py",
     # Remove the 'Download all examples' button from the top level gallery
-    'download_all_examples': False,
+    "download_all_examples": False,
     # Sort gallery example by file name instead of number of lines (default)
-    'within_subsection_order': FileNameSortKey,
+    "within_subsection_order": FileNameSortKey,
     # directory where function granular galleries are stored
-    'backreferences_dir': None,
+    "backreferences_dir": None,
     # Modules for which function level galleries are created.  In
-    'doc_module': 'sectionproperties',
-    'image_scrapers': ('matplotlib',),
-    'first_notebook_cell': ('%matplotlib inline\n'),
+    "doc_module": "sectionproperties",
+    "image_scrapers": ("matplotlib",),
+    "first_notebook_cell": ("%matplotlib inline\n"),
 }
 
 # sphinx_gallery_conf = {
diff --git a/docs/source/images/sections/concrete_circular_section_geometry.png b/docs/source/images/sections/concrete_circular_section_geometry.png
new file mode 100644
index 00000000..68a8c2bd
Binary files /dev/null and b/docs/source/images/sections/concrete_circular_section_geometry.png differ
diff --git a/docs/source/images/sections/concrete_circular_section_mesh.png b/docs/source/images/sections/concrete_circular_section_mesh.png
new file mode 100644
index 00000000..5822226c
Binary files /dev/null and b/docs/source/images/sections/concrete_circular_section_mesh.png differ
diff --git a/docs/source/images/sections/concrete_rectangular_section_geometry.png b/docs/source/images/sections/concrete_rectangular_section_geometry.png
new file mode 100644
index 00000000..911bf328
Binary files /dev/null and b/docs/source/images/sections/concrete_rectangular_section_geometry.png differ
diff --git a/docs/source/images/sections/concrete_rectangular_section_mesh.png b/docs/source/images/sections/concrete_rectangular_section_mesh.png
new file mode 100644
index 00000000..9e133bd0
Binary files /dev/null and b/docs/source/images/sections/concrete_rectangular_section_mesh.png differ
diff --git a/docs/source/images/sections/concrete_tee_section_geometry.png b/docs/source/images/sections/concrete_tee_section_geometry.png
new file mode 100644
index 00000000..d86f310c
Binary files /dev/null and b/docs/source/images/sections/concrete_tee_section_geometry.png differ
diff --git a/docs/source/images/sections/concrete_tee_section_mesh.png b/docs/source/images/sections/concrete_tee_section_mesh.png
new file mode 100644
index 00000000..35ba3504
Binary files /dev/null and b/docs/source/images/sections/concrete_tee_section_mesh.png differ
diff --git a/docs/source/index.rst b/docs/source/index.rst
index a781e588..8833b12d 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -27,6 +27,7 @@ can be found in the README file on github.
    rst/installation
    rst/structure
    rst/geom_mesh
+   rst/section_library
    rst/advanced_geom
    rst/analysis
    rst/post
@@ -36,14 +37,14 @@ can be found in the README file on github.
 
 Here's a quick example that harnesses some of the power of *sectionproperties* and shows its simplicity::
 
-  import sectionproperties.pre.sections as sections
+  import sectionproperties.pre.library.steel_sections as steel_sections
   from sectionproperties.analysis.cross_section import Section
 
   # create geometry of the cross-section
-  geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
+  geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
 
   # generate a finite element mesh
-  geometry.create_mesh(mesh_sizes=[2.5])
+  geometry.create_mesh(mesh_sizes=[10])
 
   # create a Section object for analysis
   section = Section(geometry)
@@ -58,9 +59,9 @@ Here's a quick example that harnesses some of the power of *sectionproperties* a
   print(section.get_ic())  # second moments of area about the centroidal axis
   >>>(23544664.29, 3063383.07, 0.00)
   print(section.get_j())  # torsion constant
-  >>>62907.79
+  >>>62954.43
   print(section.get_As())  # shear areas in the x & y directions
-  >>>(1842.17, 1120.18)
+  >>>(1842.24, 1120.19)
 
 Support
 -------
diff --git a/docs/source/rst/advanced_geom.rst b/docs/source/rst/advanced_geom.rst
index 8f017f45..b9338c3b 100644
--- a/docs/source/rst/advanced_geom.rst
+++ b/docs/source/rst/advanced_geom.rst
@@ -24,10 +24,10 @@ Creating Merged Sections
 
 For this example, we will create a custom section out of two similar "I" sections::
 
-    import sectionproperties.pre.sections as sections
+    import sectionproperties.pre.library.steel_sections as steel_sections
     import sectionproperties.analysis.cross_section as cross_section
 
-    i_sec1 = sections.i_section(d=250, b=150, t_f=13, t_w=10, r=12, n_r=12)
+    i_sec1 = steel_sections.i_section(d=250, b=150, t_f=13, t_w=10, r=12, n_r=12)
     i_sec2 = i_sec1.rotate_section(45)
 
 ..  figure:: ../images/examples/i_sec1.png
@@ -159,11 +159,11 @@ Another example
 
 Here, we will simply combine two squares with the default material::
 
-    import sectionproperties.pre.sections as sections
+    import sectionproperties.pre.library.standard_sections as standard_sections
     from sectionproperties.analysis.cross_section import Section
 
-    s1 = sections.rectangular_section(1,1)
-    s2 = sections.rectangular_section(0.5,0.5).shift_section(1,0.25)
+    s1 = standard_sections.rectangular_section(1,1)
+    s2 = standard_sections.rectangular_section(0.5,0.5).shift_section(1,0.25)
     geometry = s1 + s2
     geometry
 
diff --git a/docs/source/rst/api.rst b/docs/source/rst/api.rst
index 0ddb04d3..3c91530b 100644
--- a/docs/source/rst/api.rst
+++ b/docs/source/rst/api.rst
@@ -18,117 +18,186 @@ CompoundGeometry Class
 """"""""""""""""""""""
 ..  autoclass:: sectionproperties.pre.sections.CompoundGeometry
     :show-inheritance:
-    
-*sections* Functions
-^^^^^^^^^^^^^^^^^^^^^
+
+load_dxf
+""""""""
+..  autofunction:: sectionproperties.pre.sections.load_dxf
+
+create_facets
+"""""""""""""
+..  autofunction:: sectionproperties.pre.sections.create_facets
+
+create_exterior_points
+""""""""""""""""""""""
+..  autofunction:: sectionproperties.pre.sections.create_exterior_points
+
+create_interior_points
+""""""""""""""""""""""
+..  autofunction:: sectionproperties.pre.sections.create_interior_points
+
+create_points_and_facets
+""""""""""""""""""""""""
+..  autofunction:: sectionproperties.pre.sections.create_points_and_facets
+
+
+*pre* Module
+^^^^^^^^^^^^
+
+Material Class
+""""""""""""""
+
+  ..  autoclass:: sectionproperties.pre.pre.Material
+      :show-inheritance:
+      :members:
+
+create_mesh
+"""""""""""
+..  autofunction:: sectionproperties.pre.pre.create_mesh
+
+
+*rhino* Module
+^^^^^^^^^^^^^^
+
+load_3dm
+""""""""
+..  autofunction:: sectionproperties.pre.rhino.load_3dm
+
+load_brep_encoding
+""""""""""""""""""
+..  autofunction:: sectionproperties.pre.rhino.load_brep_encoding
+
+
+*bisect_section* Module
+^^^^^^^^^^^^^^^^^^^^^^^
+
+create_line_segment
+"""""""""""""""""""
+..  autofunction:: sectionproperties.pre.bisect_section.create_line_segment
+
+group_top_and_bottom_polys
+""""""""""""""""""""""""""
+..  autofunction:: sectionproperties.pre.bisect_section.group_top_and_bottom_polys
+
+line_mx_plus_b
+""""""""""""""
+..  autofunction:: sectionproperties.pre.bisect_section.line_mx_plus_b
+
+perp_mx_plus_b
+""""""""""""""
+..  autofunction:: sectionproperties.pre.bisect_section.perp_mx_plus_b
+
+line_intersection
+"""""""""""""""""
+..  autofunction:: sectionproperties.pre.bisect_section.line_intersection
+
+sum_poly_areas
+""""""""""""""
+..  autofunction:: sectionproperties.pre.bisect_section.sum_poly_areas
+
+
+*standard_sections* Module
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 rectangular_section
 """""""""""""""""""
-..  autofunction:: sectionproperties.pre.sections.rectangular_section
-    :noindex:
+..  autofunction:: sectionproperties.pre.library.standard_sections.rectangular_section
 
 circular_section
 """"""""""""""""
-..  autofunction:: sectionproperties.pre.sections.circular_section
-    :noindex:
-
-circular_hollow_section
-"""""""""""""""""""""""
-..  autofunction:: sectionproperties.pre.sections.circular_hollow_section
-    :noindex:
+..  autofunction:: sectionproperties.pre.library.standard_sections.circular_section
 
 elliptical_section
 """"""""""""""""""
-..  autofunction:: sectionproperties.pre.sections.elliptical_section
-    :noindex:
+..  autofunction:: sectionproperties.pre.library.standard_sections.elliptical_section
+
+cruciform_section
+""""""""""""""""""
+  ..  autofunction:: sectionproperties.pre.library.standard_sections.cruciform_section
+
+
+*steel_sections* Module
+^^^^^^^^^^^^^^^^^^^^^^^
+
+circular_hollow_section
+"""""""""""""""""""""""
+..  autofunction:: sectionproperties.pre.library.steel_sections.circular_hollow_section
 
 elliptical_hollow_section
 """""""""""""""""""""""""
-..  autofunction:: sectionproperties.pre.sections.elliptical_hollow_section
-    :noindex:
+..  autofunction:: sectionproperties.pre.library.steel_sections.elliptical_hollow_section
 
 rectangular_hollow_section
 """"""""""""""""""""""""""
-..  autofunction:: sectionproperties.pre.sections.rectangular_hollow_section
-    :noindex:
+..  autofunction:: sectionproperties.pre.library.steel_sections.rectangular_hollow_section
+
+polygon_hollow_section
+"""""""""""""""""""""""
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.polygon_hollow_section
 
 i_section
 """""""""
-  ..  autofunction:: sectionproperties.pre.sections.i_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.i_section
 
 mono_i_section
 """"""""""""""
-  ..  autofunction:: sectionproperties.pre.sections.mono_i_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.mono_i_section
 
 tapered_flange_i_section
 """"""""""""""""""""""""
-  ..  autofunction:: sectionproperties.pre.sections.tapered_flange_i_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.tapered_flange_i_section
 
 channel_section
 """""""""""""""
-  ..  autofunction:: sectionproperties.pre.sections.channel_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.channel_section
 
 tapered_flange_channel
 """"""""""""""""""""""
-  ..  autofunction:: sectionproperties.pre.sections.tapered_flange_channel
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.tapered_flange_channel
 
 tee_section
 """""""""""
-  ..  autofunction:: sectionproperties.pre.sections.tee_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.tee_section
 
 angle_section
 """"""""""""""
-  ..  autofunction:: sectionproperties.pre.sections.angle_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.angle_section
 
 cee_section
 """"""""""""
-  ..  autofunction:: sectionproperties.pre.sections.cee_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.cee_section
 
 zed_section
 """""""""""
-  ..  autofunction:: sectionproperties.pre.sections.zed_section
-      :noindex:
-
-cruciform_section
-""""""""""""""""""
-  ..  autofunction:: sectionproperties.pre.sections.cruciform_section
-      :noindex:
-
-polygon_hollow_section
-"""""""""""""""""""""""
-  ..  autofunction:: sectionproperties.pre.sections.polygon_hollow_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.zed_section
 
 box_girder_section
 """""""""""""""""""
-  ..  autofunction:: sectionproperties.pre.sections.box_girder_section
-      :noindex:
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.box_girder_section
 
-*pre* Module
-^^^^^^^^^^^^
 
-Material Class
-""""""""""""""
+*concrete_sections* Module
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-  ..  autoclass:: sectionproperties.pre.pre.Material
-      :show-inheritance:
-      :members:
+concrete_rectangular_section
+""""""""""""""""""""""""""""
+..  autofunction:: sectionproperties.pre.library.concrete_sections.concrete_rectangular_section
 
-pre Functions
-"""""""""""""
+concrete_tee_section
+""""""""""""""""""""
+..  autofunction:: sectionproperties.pre.library.concrete_sections.concrete_tee_section
+
+concrete_circular_section
+"""""""""""""""""""""""""
+..  autofunction:: sectionproperties.pre.library.concrete_sections.concrete_circular_section
 
-create_mesh
-""""""""""""
-..  autofunction:: sectionproperties.pre.pre.create_mesh
 
+*bridge_sections* Module
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+TBC
+
+
+.. _label-nastran-sections:
 
 *nastran_sections* Module
 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,127 +205,103 @@ This module contains sections as defined by Nastran and Nastran-based programs,
 such as MYSTRAN and ASTROS.
 
 nastran_bar
-""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_bar
-    :noindex:
+"""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_bar
 
 nastran_box
-""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_box
-    :noindex:
+"""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_box
 
 nastran_box1
-"""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_box1
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_box1
 
 nastran_chan
-"""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_chan
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_chan
 
 nastran_chan1
-""""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_chan1
-    :noindex:
+"""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_chan1
 
 nastran_chan2
-""""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_chan2
-    :noindex:
+"""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_chan2
 
 nastran_cross
-"""""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_cross
-    :noindex:
+"""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_cross
 
 nastran_dbox
-"""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_dbox
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_dbox
 
 nastran_fcross
-"""""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_fcross
-    :noindex:
+""""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_fcross
 
 nastran_gbox
-"""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_gbox
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_gbox
 
 nastran_h
 """"""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_h
-    :noindex:
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_h
 
 nastran_hat
-""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_hat
-    :noindex:
+"""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_hat
 
 nastran_hat1
-"""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_hat1
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_hat1
 
 nastran_hexa
-"""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_hexa
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_hexa
 
 nastran_i
-"""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_i
-    :noindex:
+"""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_i
 
 nastran_i1
-"""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_i1
-    :noindex:
+""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_i1
 
 nastran_l
-""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_l
-    :noindex:
+"""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_l
 
 nastran_rod
-""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_rod
-    :noindex:
+"""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_rod
 
 nastran_tee
-""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_tee
-    :noindex:
+"""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tee
 
 nastran_tee1
-"""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_tee1
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tee1
 
 nastran_tee2
-"""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_tee2
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tee2
 
 nastran_tube
-"""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_tube
-    :noindex:
+""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tube
 
 nastran_tube2
-""""""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_tube2
-    :noindex:
+"""""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tube2
 
 nastran_zed
-""""""""""""""
-..  autofunction:: sectionproperties.pre.nastran_sections.nastran_zed
-    :noindex:
+"""""""""""
+..  autofunction:: sectionproperties.pre.library.nastran_sections.nastran_zed
 
-References
-""""""""""
+Nastran References
+""""""""""""""""""
 .. [1]  MSC Nastran Quick Reference Guide 2012,
         PBEAML - Simple Beam Cross-Section Property, pp. 2890-2894
         https://simcompanion.mscsoftware.com/infocenter/index?page=content&id=DOC10351
@@ -273,6 +318,7 @@ References
         Section 5.1.3.2, pp. 56
         https://apps.dtic.mil/dtic/tr/fulltext/u2/a308134.pdf
 
+
 Analysis Package
 ----------------
 
@@ -280,7 +326,7 @@ Analysis Package
 ^^^^^^^^^^^^^^^^^^^^^^
 
 Section Class
-""""""""""""""""""
+"""""""""""""
 
   ..  autoclass:: sectionproperties.analysis.cross_section.Section
       :show-inheritance:
@@ -331,38 +377,73 @@ Tri6 Class
     :show-inheritance:
     :members:
 
-fea Functions
-"""""""""""""
-
+gauss_points
+""""""""""""
 ..  autofunction:: sectionproperties.analysis.fea.gauss_points
+
+shape_function
+""""""""""""""
 ..  autofunction:: sectionproperties.analysis.fea.shape_function
+
+extrapolate_to_nodes
+""""""""""""""""""""
 ..  autofunction:: sectionproperties.analysis.fea.extrapolate_to_nodes
+
+principal_coordinate
+""""""""""""""""""""
 ..  autofunction:: sectionproperties.analysis.fea.principal_coordinate
+
+global_coordinate
+"""""""""""""""""
 ..  autofunction:: sectionproperties.analysis.fea.global_coordinate
+
+point_above_line
+""""""""""""""""
 ..  autofunction:: sectionproperties.analysis.fea.point_above_line
 
+
 *solver* Module
 ^^^^^^^^^^^^^^^
 
-solver Functions
-""""""""""""""""
-
+solve_cgs
+"""""""""
 ..  autofunction:: sectionproperties.analysis.solver.solve_cgs
+
+solve_cgs_lagrange
+""""""""""""""""""
 ..  autofunction:: sectionproperties.analysis.solver.solve_cgs_lagrange
+
+solve_direct
+""""""""""""
 ..  autofunction:: sectionproperties.analysis.solver.solve_direct
+
+solve_direct_lagrange
+"""""""""""""""""""""
 ..  autofunction:: sectionproperties.analysis.solver.solve_direct_lagrange
+
+function_timer
+""""""""""""""
 ..  autofunction:: sectionproperties.analysis.solver.function_timer
 
+
 Post-Processor Package
 ----------------------
 
 *post* Module
 ^^^^^^^^^^^^^
 
-post Functions
-""""""""""""""
-
+setup_plot
+""""""""""
 ..  autofunction:: sectionproperties.post.post.setup_plot
+
+finish_plot
+"""""""""""
 ..  autofunction:: sectionproperties.post.post.finish_plot
+
+draw_principal_axis
+"""""""""""""""""""
 ..  autofunction:: sectionproperties.post.post.draw_principal_axis
+
+print_results
+"""""""""""""
 ..  autofunction:: sectionproperties.post.post.print_results
diff --git a/docs/source/rst/geom_mesh.rst b/docs/source/rst/geom_mesh.rst
index 3e422b33..5c4a370d 100644
--- a/docs/source/rst/geom_mesh.rst
+++ b/docs/source/rst/geom_mesh.rst
@@ -20,6 +20,7 @@ Section Geometry
 * The :class:`~sectionproperties.pre.sections.CompoundGeometry` class, comprised of two or more
   `Geometry` objects
 
+
 Geometry Class
 --------------
 
@@ -36,6 +37,7 @@ A :class:`~sectionproperties.pre.sections.Geometry` is instantiated with two arg
    assigned to the ``Geometry.material`` attribute. The default material has an elastic modulus of
    1, a Poisson's ratio of 0 and a yield strength of 1.
 
+
 CompoundGeometry Class
 ----------------------
 
@@ -88,12 +90,12 @@ In addition to creating geometries directly from :class:`shapely.geometry.Polygo
 analysis:
 
 #. From lists of points, facets, hole regions, and control regions
-#. From *sectionproperties*'s "factory functions" of common shapes
 #. From ``.dxf`` files
 #. From ``.3dm`` files
 #. From Rhino encodings
 #. Using transformation methods on existing geometries and/or by applying set operations
    (e.g. `|`, `+`, `-`, `&`, `^`)
+#. From *sectionproperties*'s section library
 
 For the first two approaches, an optional ``.material`` parameter can be passed containing a
 :class:`~sectionproperties.pre.pre.Material` (or list of `Material` objects) to associate with the
@@ -102,6 +104,8 @@ newly created geometry(ies). The material attribute can be altered afterward in
 different :class:`~sectionproperties.pre.pre.Material` to the ``.material`` attribute.
 
 
+.. _label-from-points:
+
 Geometry from points, facets, holes, and control_points
 -------------------------------------------------------
 
@@ -139,6 +143,7 @@ file (i.e. the number of contiguous regions).
 ..  autofunction:: sectionproperties.pre.sections.CompoundGeometry.from_dxf
    :noindex:
 
+
 Geometry from Rhino
 -------------------
 
@@ -178,104 +183,6 @@ These can be accessed by :attr:`sectionproperties.pre.rhino.load_3dm()` and
    :noindex:
 
 
-Creating Common Structural Geometries
--------------------------------------
-
-In order to make your life easier, there are a number of built-in functions that generate typical
-structural cross-sections, resulting in :class:`~sectionproperties.pre.sections.Geometry` objects.
-
-
-Rectangular Section
-^^^^^^^^^^^^^^^^^^^
-..  autofunction:: sectionproperties.pre.sections.rectangular_section
-    :noindex:
-
-Circular Section
-^^^^^^^^^^^^^^^^
-..  autofunction:: sectionproperties.pre.sections.circular_section
-    :noindex:
-
-Circular Hollow Section (CHS)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-..  autofunction:: sectionproperties.pre.sections.circular_hollow_section
-    :noindex:
-
-Elliptical Section
-^^^^^^^^^^^^^^^^^^
-..  autofunction:: sectionproperties.pre.sections.elliptical_section
-    :noindex:
-
-Elliptical Hollow Section (EHS)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-..  autofunction:: sectionproperties.pre.sections.elliptical_hollow_section
-    :noindex:
-
-Rectangular Hollow Section (RHS)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-..  autofunction:: sectionproperties.pre.sections.rectangular_hollow_section
-    :noindex:
-
-I-Section
-^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.i_section
-      :noindex:
-
-Monosymmetric I-Section
-^^^^^^^^^^^^^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.mono_i_section
-      :noindex:
-
-Tapered Flange I-Section
-^^^^^^^^^^^^^^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.tapered_flange_i_section
-      :noindex:
-
-Parallel Flange Channel (PFC) Section
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.channel_section
-      :noindex:
-
-Tapered Flange Channel Section
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.tapered_flange_channel
-      :noindex:
-
-Tee Section
-^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.tee_section
-      :noindex:
-
-Angle Section
-^^^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.angle_section
-      :noindex:
-
-Cee Section
-^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.cee_section
-      :noindex:
-
-Zed Section
-^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.zed_section
-      :noindex:
-
-Cruciform Section
-^^^^^^^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.cruciform_section
-      :noindex:
-
-Polygon Hollow Section
-^^^^^^^^^^^^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.polygon_hollow_section
-      :noindex:
-
-Box Girder Section
-^^^^^^^^^^^^^^^^^^
-  ..  autofunction:: sectionproperties.pre.sections.box_girder_section
-      :noindex:
-
-
 Combining Geometries Using Set Operations
 -----------------------------------------
 
@@ -293,6 +200,12 @@ Both `Geometry` and `CompoundGeometry` objects can be manipulated using Python's
 See :ref:`label-advanced_geom` for an example using set operations.
 
 
+*sectionproperties* Section Library
+-----------------------------------
+
+See :ref:`label-section-library`.
+
+
 Manipulating Geometries
 =======================
 
@@ -316,18 +229,21 @@ Aligning
   ..  autofunction:: sectionproperties.pre.sections.Geometry.align_to
       :noindex:
 
+
 Mirroring
 ---------
 
   ..  autofunction:: sectionproperties.pre.sections.Geometry.mirror_section
       :noindex:
 
+
 Rotating
 --------
 
   ..  autofunction:: sectionproperties.pre.sections.Geometry.rotate_section
       :noindex:
 
+
 Shifting
 --------
 
@@ -337,12 +253,14 @@ Shifting
   ..  autofunction:: sectionproperties.pre.sections.Geometry.shift_section
       :noindex:
 
+
 Splitting
 ---------
 
   ..  autofunction:: sectionproperties.pre.sections.Geometry.split_section
       :noindex:
 
+
 Offsetting the Perimeter
 ------------------------
 
diff --git a/docs/source/rst/post.rst b/docs/source/rst/post.rst
index 68d036dc..cd8eeaa1 100644
--- a/docs/source/rst/post.rst
+++ b/docs/source/rst/post.rst
@@ -291,10 +291,10 @@ The examples shown in the methods below are performed on a 150x90x12 UA
 (unequal angle) section. The :class:`~sectionproperties.analysis.cross_section.Section`
 object is created below::
 
-  import sectionproperties.pre.sections as sections
+  import sectionproperties.pre.library.steel_sections as steel_sections
   from sectionproperties.analysis.cross_section import Section
 
-  geometry = sections.AngleSection(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+  geometry = steel_sections.AngleSection(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
   mesh = geometry.create_mesh(mesh_sizes=[2.5])
   section = Section(geometry, mesh)
 
diff --git a/docs/source/rst/section_library.rst b/docs/source/rst/section_library.rst
new file mode 100644
index 00000000..1c123936
--- /dev/null
+++ b/docs/source/rst/section_library.rst
@@ -0,0 +1,137 @@
+.. _label-section-library:
+
+====================================================
+Creating Section Geometries from the Section Library
+====================================================
+
+In order to make your life easier, there are a number of built-in functions that generate typical
+structural cross-sections, resulting in :class:`~sectionproperties.pre.sections.Geometry` objects.
+These typical cross-sections reside in the ``sectionproperties.pre.library`` module.
+
+Standard Sections Library
+=========================
+
+Rectangular Section
+-------------------
+..  autofunction:: sectionproperties.pre.library.standard_sections.rectangular_section
+    :noindex:
+
+Circular Section
+----------------
+..  autofunction:: sectionproperties.pre.library.standard_sections.circular_section
+    :noindex:
+
+Elliptical Section
+------------------
+..  autofunction:: sectionproperties.pre.library.standard_sections.elliptical_section
+    :noindex:
+
+Cruciform Section
+-----------------
+  ..  autofunction:: sectionproperties.pre.library.standard_sections.cruciform_section
+      :noindex:
+
+
+Steel Sections Library
+======================
+
+Circular Hollow Section (CHS)
+-----------------------------
+..  autofunction:: sectionproperties.pre.library.steel_sections.circular_hollow_section
+    :noindex:
+
+Elliptical Hollow Section (EHS)
+-------------------------------
+..  autofunction:: sectionproperties.pre.library.steel_sections.elliptical_hollow_section
+    :noindex:
+
+Rectangular Hollow Section (RHS)
+--------------------------------
+..  autofunction:: sectionproperties.pre.library.steel_sections.rectangular_hollow_section
+    :noindex:
+
+Polygon Hollow Section
+----------------------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.polygon_hollow_section
+      :noindex:
+
+I-Section
+---------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.i_section
+      :noindex:
+
+Monosymmetric I-Section
+-----------------------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.mono_i_section
+      :noindex:
+
+Tapered Flange I-Section
+------------------------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.tapered_flange_i_section
+      :noindex:
+
+Parallel Flange Channel (PFC) Section
+-------------------------------------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.channel_section
+      :noindex:
+
+Tapered Flange Channel Section
+------------------------------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.tapered_flange_channel
+      :noindex:
+
+Tee Section
+-----------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.tee_section
+      :noindex:
+
+Angle Section
+-------------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.angle_section
+      :noindex:
+
+Cee Section
+-----------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.cee_section
+      :noindex:
+
+Zed Section
+-----------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.zed_section
+      :noindex:
+
+Box Girder Section
+------------------
+  ..  autofunction:: sectionproperties.pre.library.steel_sections.box_girder_section
+      :noindex:
+
+
+Concrete Sections Library
+=========================
+
+Concrete Rectangular Section
+----------------------------
+..  autofunction:: sectionproperties.pre.library.concrete_sections.concrete_rectangular_section
+    :noindex:
+
+Concrete Tee Section
+--------------------
+..  autofunction:: sectionproperties.pre.library.concrete_sections.concrete_tee_section
+    :noindex:
+
+Concrete Circular Section
+-------------------------
+..  autofunction:: sectionproperties.pre.library.concrete_sections.concrete_circular_section
+    :noindex:
+
+
+Bridge Sections Library
+=======================
+
+TBC
+
+
+Nastran Sections Library
+========================
+
+See :ref:`label-nastran-sections`.
diff --git a/docs/source/rst/structure.rst b/docs/source/rst/structure.rst
index cf8c3622..aaef56d8 100644
--- a/docs/source/rst/structure.rst
+++ b/docs/source/rst/structure.rst
@@ -12,14 +12,15 @@ Creating a Geometry and Mesh
 ----------------------------
 
 The dimensions and shape of the cross-section to be analysed define the *geometry*
-of the cross-section. The :ref:`label-sections-module` provides a number of functions
-to easily generate either commonly used structural sections or an arbitrary
-cross-section, defined by an ordered list of points.
+of the cross-section. The :ref:`Section Library<label-section-library>` provides a number of
+functions to easily generate either commonly used structural sections. Alternatively,
+arbitrary cross-sections can be built from a list of user-defined points, see
+:ref:`label-from-points`.
 
 The final stage in the pre-processor involves generating a finite element mesh of
 the *geometry* that the solver can use to calculate the cross-section properties.
-This can easily be performed using the :func:`~sectionproperties.pre.sections.Geometry.create_mesh`
-method that all :class:`~sectionproperties.pre.sections.Geometry` objects have
+This can easily be performed using the :func:`~sectionproperties.pre.geometry.Geometry.create_mesh`
+method that all :class:`~sectionproperties.pre.geometry.Geometry` objects have
 access to.
 
 The following example creates a geometry object with a circular cross-section.
@@ -27,9 +28,9 @@ The diameter of the circle is 50 and 64 points are used to discretise the circum
 of the circle. A finite element mesh is generated with a maximum triangular area
 of 2.5::
 
-      import sectionproperties.pre.sections as sections
+      import sectionproperties.pre.library.standard_sections as standard_sections
 
-      geometry = sections.circular_section(d=50, n=64)
+      geometry = standard_sections.circular_section(d=50, n=64)
       geometry.create_mesh(mesh_sizes=[2.5])
 
 ..  figure:: ../images/sections/circle_mesh.png
@@ -71,14 +72,14 @@ The following example performs a geometric and warping analysis on the circular
 cross-section defined in the previous section with steel used as the material
 property::
 
-  import sectionproperties.pre.sections as sections
+  import sectionproperties.pre.library.standard_sections as standard_sections
   from sectionproperties.analysis.cross_section import Section
   from sectionproperties.pre.pre import Material
 
 
   steel = Material(name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, density=7.85e-6,
                    yield_strength=500, color='grey')
-  geometry = sections.circular_section(d=50, n=64, material=steel)
+  geometry = standard_sections.circular_section(d=50, n=64, material=steel)
   geometry.create_mesh(mesh_sizes=[2.5])  # Adds the mesh to the geometry
 
   section = Section(geometry)
@@ -99,10 +100,10 @@ displayed and the cross-section stresses visualised in a contour plot.
 The following example analyses a 200 PFC section. The cross-section properties
 are printed to the terminal and a plot of the centroids is displayed::
 
-  import sectionproperties.pre.sections as sections
+  import sectionproperties.pre.library.steel_sections as steel_sections
   from sectionproperties.analysis.cross_section import Section
 
-  geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
+  geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
   geometry.create_mesh(mesh_sizes=[2.5])  # Adds the mesh to the geometry
 
   section = Section(geometry)
@@ -188,5 +189,4 @@ method::
   SF_22+  = 1.802381e+00
   SF_22-  = 8.688337e-01
 
-Refer to :ref:`label-post` for a more detailed explanation of the post-processing
-stage.
+Refer to :ref:`label-post` for a more detailed explanation of the post-processing stage.
diff --git a/examples/00-basic/01_simple.py b/examples/00-basic/01_simple.py
index 73b4f8b8..4a48ec24 100644
--- a/examples/00-basic/01_simple.py
+++ b/examples/00-basic/01_simple.py
@@ -21,8 +21,8 @@
 
 # sphinx_gallery_thumbnail_number = 1
 
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.standard_sections as sections
+from sectionproperties.analysis.section import Section
 
 # %%
 # Create a 50 diameter circle discretised by 64 points
@@ -35,7 +35,7 @@
 
 section = Section(geometry, time_info=True)
 section.display_mesh_info()
-section.plot_mesh() 
+section.plot_mesh()
 
 # %%
 # perform a geometric, warping and plastic analysis, displaying the time info
diff --git a/examples/00-basic/02_nastran_section.py b/examples/00-basic/02_nastran_section.py
index 8c9a1814..67b1d8f1 100644
--- a/examples/00-basic/02_nastran_section.py
+++ b/examples/00-basic/02_nastran_section.py
@@ -23,8 +23,8 @@
 # sphinx_gallery_thumbnail_number = 1
 
 from typing import get_origin
-import sectionproperties.pre.nastran_sections as nsections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.nastran_sections as nsections
+from sectionproperties.analysis.section import Section
 
 # %%
 # Create a HAT1 section
diff --git a/examples/00-basic/03_custom.py b/examples/00-basic/03_custom.py
index 10c3780e..c9ef6e56 100644
--- a/examples/00-basic/03_custom.py
+++ b/examples/00-basic/03_custom.py
@@ -22,8 +22,8 @@
 
 # sphinx_gallery_thumbnail_number = 2
 
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+from sectionproperties.pre.geometry import CompoundGeometry
+from sectionproperties.analysis.section import Section
 
 # %%
 # Define parameters for the angle section
@@ -33,18 +33,37 @@
 
 # %%
 # Build the lists of points, facets, holes and control points
-points = [[-t/2, -2*a], [t/2, -2*a], [t/2, -t/2], [a, -t/2], [a, t/2],
-          [-t/2, t/2], [-b/2, -2*a], [b/2, -2*a], [b/2, -2*a-t],
-          [-b/2, -2*a-t]]
-facets = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0], [6, 7], [7, 8],
-          [8, 9], [9, 6]]
+points = [
+    [-t / 2, -2 * a],
+    [t / 2, -2 * a],
+    [t / 2, -t / 2],
+    [a, -t / 2],
+    [a, t / 2],
+    [-t / 2, t / 2],
+    [-b / 2, -2 * a],
+    [b / 2, -2 * a],
+    [b / 2, -2 * a - t],
+    [-b / 2, -2 * a - t],
+]
+facets = [
+    [0, 1],
+    [1, 2],
+    [2, 3],
+    [3, 4],
+    [4, 5],
+    [5, 0],
+    [6, 7],
+    [7, 8],
+    [8, 9],
+    [9, 6],
+]
 holes = []
 control_points = [[0, 0], [0, -2 * a - t / 2]]
 
 # %%
 # Because we have two separate geometry regions (as indicated by our control_points)
 # we create a CompoundGeometry from points
-geometry = sections.CompoundGeometry.from_points(points, facets, control_points, holes)
+geometry = CompoundGeometry.from_points(points, facets, control_points, holes)
 
 # %%
 # Create the mesh and section. For the mesh, use a smaller refinement for the angle region.
diff --git a/examples/00-basic/04_merged.py b/examples/00-basic/04_merged.py
index 73b724fe..d5c67cad 100644
--- a/examples/00-basic/04_merged.py
+++ b/examples/00-basic/04_merged.py
@@ -24,24 +24,25 @@
 
 # sphinx_gallery_thumbnail_number = 1
 
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.steel_sections as steel_sections
+from sectionproperties.pre.geometry import Geometry
+from sectionproperties.analysis.section import Section
 
 # %%
 # Create a 150x100x6 RHS
-rhs = sections.rectangular_hollow_section(d=150, b=100, t=6, r_out=15, n_r=8)
+rhs = steel_sections.rectangular_hollow_section(d=150, b=100, t=6, r_out=15, n_r=8)
 
 # %%
 # Create a triangular section from points, facets, and control points
 points = [[0, 0], [50, 0], [25, 50]]
 facets = [[0, 1], [1, 2], [2, 0]]
-control_points = [[25,25]]
-triangle = sections.Geometry.from_points(points, facets, control_points)
+control_points = [[25, 25]]
+triangle = Geometry.from_points(points, facets, control_points)
 triangle = triangle.align_center(rhs).align_to(rhs, on="top")
 
 # %%
 # Create a 100x100x6 angle and position it on the right of the RHS
-angle = sections.angle_section(d=100, b=100, t=6, r_r=8, r_t=5, n_r=8)
+angle = steel_sections.angle_section(d=100, b=100, t=6, r_r=8, r_t=5, n_r=8)
 angle = angle.shift_section(x_offset=100, y_offset=25)
 
 # %%
@@ -50,7 +51,7 @@
 geometry.plot_geometry()  # plot the geometry
 
 # %%
-# Create a mesh and section. For the mesh, use a mesh size of 2.5 for 
+# Create a mesh and section. For the mesh, use a mesh size of 2.5 for
 # the RHS, 5 for the triangle and 3 for the angle.
 geometry.create_mesh(mesh_sizes=[2.5, 5, 3])
 
diff --git a/examples/00-basic/05_mirr_rot.py b/examples/00-basic/05_mirr_rot.py
index fda8ee79..c76d3f76 100644
--- a/examples/00-basic/05_mirr_rot.py
+++ b/examples/00-basic/05_mirr_rot.py
@@ -23,18 +23,19 @@
 
 # sphinx_gallery_thumbnail_number = 1
 
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.steel_sections as steel_sections
+from sectionproperties.analysis.section import Section
 
 # %%
 # Create a 200PFC and a 150PFC
-pfc1 = sections.channel_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
-pfc2 = sections.channel_section(
-    d=150, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8).shift_section(0, 26.5)
+pfc1 = steel_sections.channel_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
+pfc2 = steel_sections.channel_section(
+    d=150, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8
+).shift_section(0, 26.5)
 
 # %%
 # Mirror the 200 PFC about the y-axis
-pfc1 = pfc1.mirror_section(axis='y', mirror_point=[0, 0])
+pfc1 = pfc1.mirror_section(axis="y", mirror_point=[0, 0])
 
 # %%
 # Merge the pfc sections
@@ -43,7 +44,7 @@
 # %%
 # Rotate the geometry counter-clockwise by 30 degrees
 geometry = geometry.rotate_section(angle=30)
-geometry.plot_geometry()  
+geometry.plot_geometry()
 
 # %%
 # Create a mesh and section. For the mesh, use a mesh size of 5 for the 200PFC
diff --git a/examples/00-basic/06_stress.py b/examples/00-basic/06_stress.py
index b41a7cd0..7270296a 100644
--- a/examples/00-basic/06_stress.py
+++ b/examples/00-basic/06_stress.py
@@ -18,12 +18,12 @@
 
 # sphinx_gallery_thumbnail_number = 1
 
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.steel_sections as steel_sections
+from sectionproperties.analysis.section import Section
 
 # %%
 # Create a 150x100x6 RHS on its side
-geometry = sections.rectangular_hollow_section(d=100, b=150, t=6, r_out=15, n_r=8)
+geometry = steel_sections.rectangular_hollow_section(d=100, b=150, t=6, r_out=15, n_r=8)
 
 # %%
 # Create a mesh and section object. For the mesh, use a maximum area of 2
diff --git a/examples/00-basic/07_composite.py b/examples/00-basic/07_composite.py
index 6cb8cb11..e9e25857 100644
--- a/examples/00-basic/07_composite.py
+++ b/examples/00-basic/07_composite.py
@@ -19,20 +19,36 @@
 
 # sphinx_gallery_thumbnail_number = 2
 
-import sectionproperties.pre.sections as sections
+import sectionproperties.pre.library.standard_sections as sections
+import sectionproperties.pre.library.steel_sections as steel_sections
+from sectionproperties.pre.geometry import CompoundGeometry
 from sectionproperties.pre.pre import Material
-from sectionproperties.analysis.cross_section import Section
+from sectionproperties.analysis.section import Section
 
 # %%
 # Create material properties
-steel = Material(name='Steel', elastic_modulus=200e3, poissons_ratio=0.3,
-                 yield_strength=500, density=8.05e-6 ,color='grey')
-timber = Material(name='Timber', elastic_modulus=8e3, poissons_ratio=0.35,
-                  yield_strength=20, density=0.78e-6, color='burlywood')
+steel = Material(
+    name="Steel",
+    elastic_modulus=200e3,
+    poissons_ratio=0.3,
+    yield_strength=500,
+    density=8.05e-6,
+    color="grey",
+)
+timber = Material(
+    name="Timber",
+    elastic_modulus=8e3,
+    poissons_ratio=0.35,
+    yield_strength=20,
+    density=0.78e-6,
+    color="burlywood",
+)
 
 # %%
 # Create 310UB40.4
-ub = sections.i_section(d=304, b=165, t_f=10.2, t_w=6.1, r=11.4, n_r=8, material=steel)
+ub = steel_sections.i_section(
+    d=304, b=165, t_f=10.2, t_w=6.1, r=11.4, n_r=8, material=steel
+)
 
 # %%
 # Create timber panel on top of the UB
@@ -41,36 +57,36 @@
 
 # %%
 # Merge the two sections into one geometry object
-geometry = sections.CompoundGeometry([ub, panel])
+section_geometry = sections.CompoundGeometry([ub, panel])
 
 # %%
 # Create a mesh and a Section object. For the mesh use a mesh size of 5 for
 # the UB, 20 for the panel
-geometry.create_mesh(mesh_sizes=[5, 20])
-section = Section(geometry, time_info=True)
-section.display_mesh_info()  # display the mesh information
+section_geometry.create_mesh(mesh_sizes=[5, 20])
+comp_section = Section(section_geometry, time_info=True)
+comp_section.display_mesh_info()  # display the mesh information
 
 # %%
 # Plot the mesh with coloured materials and a line transparency of 0.6
-section.plot_mesh(materials=True, alpha=0.6)
+comp_section.plot_mesh(materials=True, alpha=0.6)
 
 # %%
 # Perform a geometric, warping and plastic analysis
-section.calculate_geometric_properties()
-section.calculate_warping_properties()
-section.calculate_plastic_properties(verbose=True)
+comp_section.calculate_geometric_properties()
+comp_section.calculate_warping_properties()
+comp_section.calculate_plastic_properties(verbose=True)
 
 # %%
 # Perform a stress analysis with N = 100 kN, Mxx = 120 kN.m and Vy = 75 kN
-stress_post = section.calculate_stress(N=-100e3, Mxx=-120e6, Vy=-75e3)
+stress_post = comp_section.calculate_stress(N=-100e3, Mxx=-120e6, Vy=-75e3)
 
 # %%
 # Print the results to the terminal
-section.display_results()
+comp_section.display_results()
 
 # %%
 # Plot the centroids
-section.plot_centroids()
+comp_section.plot_centroids()
 
 # %%
 # Plot the axial stress
@@ -82,4 +98,4 @@
 
 # %%
 # Plot the shear stress
-stress_post.plot_stress_v_zxy()
\ No newline at end of file
+stress_post.plot_stress_v_zxy()
diff --git a/examples/00-basic/08_frame.py b/examples/00-basic/08_frame.py
index 9ea1d690..7e5d0d1d 100644
--- a/examples/00-basic/08_frame.py
+++ b/examples/00-basic/08_frame.py
@@ -19,8 +19,8 @@
 import time
 import numpy as np
 import matplotlib.pyplot as plt
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.standard_sections as sections
+from sectionproperties.analysis.section import Section
 
 # %%
 # Create a rectangular section
diff --git a/examples/01-advanced/01-torsion_constant.py b/examples/01-advanced/01-torsion_constant.py
index cee94d82..61518918 100644
--- a/examples/01-advanced/01-torsion_constant.py
+++ b/examples/01-advanced/01-torsion_constant.py
@@ -15,8 +15,8 @@
 
 import numpy as np
 import matplotlib.pyplot as plt
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.standard_sections as sections
+from sectionproperties.analysis.section import Section
 
 # %%
 # Rectangle dimensions
@@ -47,7 +47,7 @@
 
     # get the torsion constant
     j = section.get_j()
-    print("d/b = {0:.3f}; J = {1:.5e}".format(d/b, j))
+    print("d/b = {0:.3f}; J = {1:.5e}".format(d / b, j))
     j_list.append(j)
 
 # %%
diff --git a/examples/01-advanced/02-mesh_refinement.py b/examples/01-advanced/02-mesh_refinement.py
index 8d6eea0d..af43991c 100644
--- a/examples/01-advanced/02-mesh_refinement.py
+++ b/examples/01-advanced/02-mesh_refinement.py
@@ -16,8 +16,8 @@
 
 import numpy as np
 import matplotlib.pyplot as plt
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.steel_sections as steel_sections
+from sectionproperties.analysis.section import Section
 
 # %%
 # Define mesh sizes
@@ -33,7 +33,7 @@
 
 # %%
 # Calculate reference solution
-geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=64)
+geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=64)
 geometry.create_mesh(mesh_sizes=[0.5])  # create mesh
 section = Section(geometry)  # create a Section object
 section.calculate_geometric_properties()
@@ -43,7 +43,7 @@
 # %%
 # Run through mesh_sizes with n_r = 16
 for mesh_size in mesh_size_list:
-    geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16)
+    geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16)
     geometry.create_mesh(mesh_sizes=[mesh_size])  # create mesh
     section = Section(geometry)  # create a Section object
     section.calculate_geometric_properties()
@@ -55,7 +55,7 @@
 # %%
 # Run through n_r with mesh_size = 3
 for n_r in nr_list:
-    geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=n_r)
+    geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=n_r)
     geometry.create_mesh(mesh_sizes=[3])  # create mesh
     section = Section(geometry)  # create a Section object
     section.calculate_geometric_properties()
@@ -74,10 +74,10 @@
 # %%
 # Plot the results
 (fig, ax) = plt.subplots()
-ax.loglog(mesh_elements, mesh_error_vals, 'kx-', label='Mesh Size Refinement')
-ax.loglog(nr_elements, nr_error_vals, 'rx-', label='Root Radius Refinement')
+ax.loglog(mesh_elements, mesh_error_vals, "kx-", label="Mesh Size Refinement")
+ax.loglog(nr_elements, nr_error_vals, "rx-", label="Root Radius Refinement")
 plt.xlabel("Number of Elements")
 plt.ylabel("Torsion Constant Error [%]")
-plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
+plt.legend(loc="center left", bbox_to_anchor=(1, 0.5))
 plt.tight_layout()
 plt.show()
diff --git a/sectionproperties/analysis/cross_section.py b/sectionproperties/analysis/section.py
similarity index 92%
rename from sectionproperties/analysis/cross_section.py
rename to sectionproperties/analysis/section.py
index 13736df0..3d4718b5 100644
--- a/sectionproperties/analysis/cross_section.py
+++ b/sectionproperties/analysis/section.py
@@ -14,7 +14,7 @@
 from scipy.sparse import csc_matrix, coo_matrix, linalg
 from scipy.optimize import brentq
 import sectionproperties.pre.pre as pre
-import sectionproperties.pre.sections as sections
+import sectionproperties.pre.geometry as section_geometry
 import sectionproperties.analysis.fea as fea
 import sectionproperties.analysis.solver as solver
 import sectionproperties.post.post as post
@@ -31,17 +31,17 @@ class Section:
     corresponding Tri6 finite element objects.
 
     :param geometry: Cross-section geometry object used to generate the mesh
-    :type geometry: :class:`~sectionproperties.pre.sections.Geometry`
+    :type geometry: :class:`~sectionproperties.pre.geometry.Geometry`
     :param bool time_info: If set to True, a detailed description of the computation and the time
         cost is printed to the terminal for every computation performed.
 
-    The following example creates a :class:`~sectionproperties.analysis.cross_section.Section`
+    The following example creates a :class:`~sectionproperties.analysis.section.Section`
     object of a 100D x 50W rectangle using a mesh size of 5::
 
-        import sectionproperties.pre.sections as sections
-        from sectionproperties.analysis.cross_section import Section
+        import sectionproperties.pre.library.standard_sections as standard_sections
+        from sectionproperties.analysis.section import Section
 
-        geometry = sections.rectangular_section(d=100, b=50)
+        geometry = standard_sections.rectangular_section(d=100, b=50)
         geometry.create_mesh(mesh_sizes=[5])
         section = Section(geometry)
 
@@ -49,7 +49,7 @@ class Section:
     :vartype elements: list[:class:`~sectionproperties.analysis.fea.Tri6`]
     :cvar int num_nodes: Number of nodes in the finite element mesh
     :cvar geometry: Cross-section geometry object used to generate the mesh
-    :vartype geometry: :class:`~sectionproperties.pre.sections.Geometry`
+    :vartype geometry: :class:`~sectionproperties.pre.geometry.Geometry`
     :cvar mesh: Mesh dict returned by triangle
     :vartype mesh: dict(mesh)
     :cvar mesh_nodes: Array of node coordinates from the mesh
@@ -63,7 +63,7 @@ class Section:
     :cvar material_groups: List of objects containing the elements in each defined material
     :type material_groups: list[:class:`~sectionproperties.pre.pre.MaterialGroup`]
     :cvar section_props: Class to store calculated section properties
-    :vartype section_props: :class:`~sectionproperties.analysis.cross_section.SectionProperties`
+    :vartype section_props: :class:`~sectionproperties.analysis.section.SectionProperties`
 
     :raises AssertionError: If the number of materials does not equal the number of regions
     :raises ValueError: If geometry does not contain a mesh
@@ -71,7 +71,7 @@ class Section:
 
     def __init__(
         self,
-        geometry: Union[sections.Geometry, sections.CompoundGeometry],
+        geometry: Union[section_geometry.Geometry, section_geometry.CompoundGeometry],
         time_info: bool = False,
     ):
         """Inits the Section class."""
@@ -89,7 +89,7 @@ def __init__(
         mesh = self.mesh
 
         def init():
-            if isinstance(self.geometry, sections.CompoundGeometry):
+            if isinstance(self.geometry, section_geometry.CompoundGeometry):
                 self.materials = [geom.material for geom in self.geometry.geoms]
             else:
                 self.materials = [self.geometry.material]
@@ -190,7 +190,7 @@ def init():
 
     def calculate_geometric_properties(self):
         """Calculates the geometric properties of the cross-section and stores them in the
-        :class:`~sectionproperties.analysis.cross_section.SectionProperties` object contained in
+        :class:`~sectionproperties.analysis.section.SectionProperties` object contained in
         the ``section_props`` class variable.
 
         The following geometric section properties are calculated:
@@ -272,7 +272,7 @@ def calculate_geom():
 
     def calculate_warping_properties(self, solver_type="direct"):
         """Calculates all the warping properties of the cross-section and stores them in the
-        :class:`~sectionproperties.analysis.cross_section.SectionProperties` object contained in
+        :class:`~sectionproperties.analysis.section.SectionProperties` object contained in
         the ``section_props`` class variable.
 
         :param string solver_type: Solver used for solving systems of linear equations, either
@@ -657,7 +657,7 @@ def calculate_monosymmetry_integrals():
 
     def calculate_frame_properties(self, solver_type="direct"):
         """Calculates and returns the properties required for a frame analysis. The properties are
-        also stored in the :class:`~sectionproperties.analysis.cross_section.SectionProperties`
+        also stored in the :class:`~sectionproperties.analysis.section.SectionProperties`
         object contained in the ``section_props`` class variable.
 
         :param string solver_type: Solver used for solving systems of linear equations, either
@@ -794,7 +794,7 @@ def calculate_frame():
 
     def calculate_plastic_properties(self, verbose=False, debug=False):
         """Calculates the plastic properties of the cross-section and stores the, in the
-        :class:`~sectionproperties.analysis.cross_section.SectionProperties` object contained in
+        :class:`~sectionproperties.analysis.section.SectionProperties` object contained in
         the ``section_props`` class variable.
 
         :param bool verbose: If set to True, the number of iterations required for each plastic
@@ -838,7 +838,7 @@ def calc_plastic():
 
     def calculate_stress(self, N=0, Vx=0, Vy=0, Mxx=0, Myy=0, M11=0, M22=0, Mzz=0):
         """Calculates the cross-section stress resulting from design actions and returns a
-        :class:`~sectionproperties.analysis.cross_section.StressPost` object allowing
+        :class:`~sectionproperties.analysis.section.StressPost` object allowing
         post-processing of the stress results.
 
         :param float N: Axial force
@@ -850,7 +850,7 @@ def calculate_stress(self, N=0, Vx=0, Vy=0, Mxx=0, Myy=0, M11=0, M22=0, Mzz=0):
         :param float M22: Bending moment about the centroidal 22-axis
         :param float Mzz: Torsion moment about the centroidal zz-axis
         :return: Object for post-processing cross-section stresses
-        :rtype: :class:`~sectionproperties.analysis.cross_section.StressPost`
+        :rtype: :class:`~sectionproperties.analysis.section.StressPost`
 
         Note that a geometric and warping analysis must be performed before a stress analysis is
         carried out::
@@ -1089,7 +1089,7 @@ def plot_mesh(
             If set to false, the script continues immediately after the window is rendered.
         :param float alpha: Transparency of the mesh outlines: :math:`0 \leq \\alpha \leq 1`
         :param bool materials: If set to true and material properties have been provided to the
-            :class:`~sectionproperties.analysis.cross_section.Section` object, shades the
+            :class:`~sectionproperties.analysis.section.Section` object, shades the
             elements with the specified material colours
         :param mask: Mask array, of length ``num_nodes``, to mask out triangles
         :type mask: list[bool]
@@ -1098,12 +1098,12 @@ def plot_mesh(
         :rtype: (:class:`matplotlib.figure.Figure`, :class:`matplotlib.axes`)
 
         The following example plots the mesh generated for the second example
-        listed under the :class:`~sectionproperties.analysis.cross_section.Section` object
+        listed under the :class:`~sectionproperties.analysis.section.Section` object
         definition::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.standard_sections as standard_sections
             from sectionproperties.pre.pre import Material
-            from sectionproperties.analysis.cross_section import Section
+            from sectionproperties.analysis.section import Section
 
             steel = Material(
                 name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, density=7.85e-6,
@@ -1114,8 +1114,8 @@ def plot_mesh(
                 yield_strength=20, color='burlywood'
             )
 
-            geom_steel = sections.rectangular_section(d=50, b=50, material=steel)
-            geom_timber = sections.rectangular_section(d=50, b=50, material=timber)
+            geom_steel = standard_sections.rectangular_section(d=50, b=50, material=steel)
+            geom_timber = standard_sections.rectangular_section(d=50, b=50, material=timber)
             geometry = geom_timber.align_to(geom_steel, on="right") + geom_steel
 
             geometry.create_mesh(mesh_sizes=[10, 5])
@@ -1202,10 +1202,10 @@ def plot_centroids(self, pause=True, size=500, dpi=96):
         The following example analyses a 200 PFC section and displays a plot of
         the centroids::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
+            geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
 
             section = Section(geometry)
@@ -1224,10 +1224,10 @@ def plot_centroids(self, pause=True, size=500, dpi=96):
         The following example analyses a 150x90x12 UA section and displays a plot of the
         centroids::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
 
             section = Section(geometry)
@@ -1311,11 +1311,11 @@ def display_mesh_info(self):
         The following example displays the mesh statistics for a Tee section merged from two
         rectangles::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.standard_sections as standard_sections
+            from sectionproperties.analysis.section import Section
 
-            rec1 = sections.rectangular_section(d=100, b=25)
-            rec2 = sections.rectangular_section(d=25, b=100)
+            rec1 = standard_sections.rectangular_section(d=100, b=25)
+            rec2 = standard_sections.rectangular_section(d=25, b=100)
             rec1 = rec1.shift_section(x_offset=-12.5)
             rec2 = rec2.shift_section(x_offset=-50, y_offset=100)
 
@@ -1352,10 +1352,10 @@ def display_results(self, fmt="8.6e"):
         The following example displays the geometric section properties for a 100D x 50W rectangle
         with three digits after the decimal point::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.standard_sections as standard_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.rectangular_section(d=100, b=50)
+            geometry = standard_sections.rectangular_section(d=100, b=50)
             geometry.create_mesh(mesh_sizes=[5])
 
             section = Section(geometry)
@@ -1927,13 +1927,13 @@ class PlasticSection:
     plastic section properties.
 
     :param section: Section object
-    :type section: :class:`~sectionproperties.analysis.cross_section.Section`
+    :type section: :class:`~sectionproperties.analysis.section.Section`
 
     :param bool debug: If set to True, the geometry is plotted each time a new mesh is generated by
         the plastic centroid algorithm.
 
     :cvar geometry: Deep copy of the Section geometry object provided to the constructor
-    :vartype geometry: :class:`~sectionproperties.pre.sections.Geometry`
+    :vartype geometry: :class:`~sectionproperties.pre.geometry.Geometry`
     :cvar materials: A list of material properties corresponding to various regions in the geometry
         and mesh.
     :vartype materials: list[:class:`~sectionproperties.pre.pre.Material`]
@@ -1955,7 +1955,9 @@ class PlasticSection:
     :type c_bot: list[float, float]
     """
 
-    def __init__(self, geom: Union[sections.Geometry, sections.CompoundGeometry]):
+    def __init__(
+        self, geom: Union[section_geometry.Geometry, section_geometry.CompoundGeometry]
+    ):
         """Inits the PlasticSection class."""
         self.geometry = geom.align_center()
         self.geometry.compile_geometry()
@@ -1980,7 +1982,7 @@ def calculate_centroid(self, elements):
 
         # General case
         # loop through all the geometries
-        if isinstance(self.geometry, sections.CompoundGeometry):
+        if isinstance(self.geometry, section_geometry.CompoundGeometry):
             for geom in self.geometry.geoms:
                 e = geom.material.elastic_modulus
                 area = geom.calculate_area()
@@ -2002,14 +2004,14 @@ def calculate_centroid(self, elements):
 
         return (qy / ea, qx, ea)
 
-    def calculate_plastic_properties(self, cross_section, verbose):
+    def calculate_plastic_properties(self, section, verbose):
         """Calculates the location of the plastic centroid with respect to the centroidal and
         principal bending axes, the plastic section moduli and shape factors and stores the results
-        to the supplied :class:`~sectionproperties.analysis.cross_section.Section` object.
+        to the supplied :class:`~sectionproperties.analysis.section.Section` object.
 
-        :param cross_section: Cross section object that uses the same geometry and materials
+        :param section: Cross section object that uses the same geometry and materials
             specified in the class constructor
-        :type cross_section: :class:`~sectionproperties.analysis.cross_section.Section`
+        :type section: :class:`~sectionproperties.analysis.section.Section`
         :param bool verbose: If set to True, the number of iterations required for each plastic
             axis is printed to the terminal.
         """
@@ -2025,8 +2027,8 @@ def calculate_plastic_properties(self, cross_section, verbose):
         )  # fibres[2:] = ymin, ymax
 
         self.check_convergence(r, "x-axis")
-        cross_section.section_props.y_pc = y_pc
-        cross_section.section_props.sxx = f * abs(c_top[1] - c_bot[1])
+        section.section_props.y_pc = y_pc
+        section.section_props.sxx = f * abs(c_top[1] - c_bot[1])
 
         if verbose:
             self.print_verbose(y_pc, r, "x-axis")  # Location of axis for each iteration
@@ -2037,22 +2039,22 @@ def calculate_plastic_properties(self, cross_section, verbose):
         )  # fibres[0:2] = xmin, xmax
 
         self.check_convergence(r, "y-axis")
-        cross_section.section_props.x_pc = x_pc
-        cross_section.section_props.syy = f * abs(c_top[0] - c_bot[0])
+        section.section_props.x_pc = x_pc
+        section.section_props.syy = f * abs(c_top[0] - c_bot[0])
 
         if verbose:
             self.print_verbose(x_pc, r, "y-axis")  # Location of axis for each iteration
 
         # 2) Calculate plastic properties for principal axis
         # convert principal axis angle to radians
-        angle = cross_section.section_props.phi * np.pi / 180
+        angle = section.section_props.phi * np.pi / 180
 
         # unit vectors in the axis directions
         ux = np.array([np.cos(angle), np.sin(angle)])  # Unit vectors
         uy = np.array([-np.sin(angle), np.cos(angle)])  # Unit vectors
 
         # calculate distances to the extreme fibres in the principal axis
-        fibres = self.calculate_extreme_fibres(cross_section.section_props.phi)
+        fibres = self.calculate_extreme_fibres(section.section_props.phi)
 
         # 2a) Calculate 11-axis plastic centroid
         (y22_pc, r, f, c_top, c_bot) = self.pc_algorithm(
@@ -2061,15 +2063,15 @@ def calculate_plastic_properties(self, cross_section, verbose):
 
         # calculate the centroids in the principal coordinate system
         c_top_p = fea.principal_coordinate(
-            cross_section.section_props.phi, c_top[0], c_top[1]
+            section.section_props.phi, c_top[0], c_top[1]
         )
         c_bot_p = fea.principal_coordinate(
-            cross_section.section_props.phi, c_bot[0], c_bot[1]
+            section.section_props.phi, c_bot[0], c_bot[1]
         )
 
         self.check_convergence(r, "11-axis")
-        cross_section.section_props.y22_pc = y22_pc
-        cross_section.section_props.s11 = f * abs(c_top_p[1] - c_bot_p[1])
+        section.section_props.y22_pc = y22_pc
+        section.section_props.s11 = f * abs(c_top_p[1] - c_bot_p[1])
 
         if verbose:
             self.print_verbose(y22_pc, r, "11-axis")
@@ -2081,45 +2083,45 @@ def calculate_plastic_properties(self, cross_section, verbose):
 
         # calculate the centroids in the principal coordinate system
         c_top_p = fea.principal_coordinate(
-            cross_section.section_props.phi, c_top[0], c_top[1]
+            section.section_props.phi, c_top[0], c_top[1]
         )
         c_bot_p = fea.principal_coordinate(
-            cross_section.section_props.phi, c_bot[0], c_bot[1]
+            section.section_props.phi, c_bot[0], c_bot[1]
         )
 
         self.check_convergence(r, "22-axis")
-        cross_section.section_props.x11_pc = x11_pc
-        cross_section.section_props.s22 = f * abs(c_top_p[0] - c_bot_p[0])
+        section.section_props.x11_pc = x11_pc
+        section.section_props.s22 = f * abs(c_top_p[0] - c_bot_p[0])
 
         if verbose:
             self.print_verbose(x11_pc, r, "22-axis")
 
         # if there are no materials specified, calculate shape factors
-        if list(set(cross_section.materials)) == [pre.DEFAULT_MATERIAL]:
-            cross_section.section_props.sf_xx_plus = (
-                cross_section.section_props.sxx / cross_section.section_props.zxx_plus
+        if list(set(section.materials)) == [pre.DEFAULT_MATERIAL]:
+            section.section_props.sf_xx_plus = (
+                section.section_props.sxx / section.section_props.zxx_plus
             )
-            cross_section.section_props.sf_xx_minus = (
-                cross_section.section_props.sxx / cross_section.section_props.zxx_minus
+            section.section_props.sf_xx_minus = (
+                section.section_props.sxx / section.section_props.zxx_minus
             )
-            cross_section.section_props.sf_yy_plus = (
-                cross_section.section_props.syy / cross_section.section_props.zyy_plus
+            section.section_props.sf_yy_plus = (
+                section.section_props.syy / section.section_props.zyy_plus
             )
-            cross_section.section_props.sf_yy_minus = (
-                cross_section.section_props.syy / cross_section.section_props.zyy_minus
+            section.section_props.sf_yy_minus = (
+                section.section_props.syy / section.section_props.zyy_minus
             )
 
-            cross_section.section_props.sf_11_plus = (
-                cross_section.section_props.s11 / cross_section.section_props.z11_plus
+            section.section_props.sf_11_plus = (
+                section.section_props.s11 / section.section_props.z11_plus
             )
-            cross_section.section_props.sf_11_minus = (
-                cross_section.section_props.s11 / cross_section.section_props.z11_minus
+            section.section_props.sf_11_minus = (
+                section.section_props.s11 / section.section_props.z11_minus
             )
-            cross_section.section_props.sf_22_plus = (
-                cross_section.section_props.s22 / cross_section.section_props.z22_plus
+            section.section_props.sf_22_plus = (
+                section.section_props.s22 / section.section_props.z22_plus
             )
-            cross_section.section_props.sf_22_minus = (
-                cross_section.section_props.s22 / cross_section.section_props.z22_minus
+            section.section_props.sf_22_minus = (
+                section.section_props.s22 / section.section_props.z22_minus
             )
 
     def check_convergence(self, root_result, axis):
@@ -2327,24 +2329,24 @@ class StressPost:
     the MaterialGroups within the cross-section to allow the calculation of stresses for each
     material. Methods for post-processing the calculated stresses are provided.
 
-    :param cross_section: Cross section object for stress calculation
-    :type cross_section: :class:`~sectionproperties.analysis.cross_section.Section`
+    :param section: Cross section object for stress calculation
+    :type section: :class:`~sectionproperties.analysis.section.Section`
 
-    :cvar cross_section: Cross section object for stress calculation
-    :vartype cross_section: :class:`~sectionproperties.analysis.cross_section.Section`
-    :cvar material_groups: A deep copy of the `cross_section` material groups to allow a new stress
+    :cvar section: Cross section object for stress calculation
+    :vartype section: :class:`~sectionproperties.analysis.section.Section`
+    :cvar material_groups: A deep copy of the `section` material groups to allow a new stress
         analysis
     :vartype material_groups: list[:class:`~sectionproperties.pre.pre.MaterialGroup`]
     """
 
-    def __init__(self, cross_section):
+    def __init__(self, section):
         """Inits the StressPost class."""
 
-        self.cross_section = cross_section
+        self.section = section
 
         # make a deep copy of the material groups to the StressPost object such that stress results
         # can be saved to a new material group
-        self.material_groups = copy.deepcopy(cross_section.material_groups)
+        self.material_groups = copy.deepcopy(section.material_groups)
 
     def plot_stress_contour(
         self, sigs, title, pause, cmap, normalize=True, size=500, dpi=96
@@ -2371,16 +2373,16 @@ def plot_stress_contour(
         post.setup_plot(ax, pause)
 
         # plot the finite element mesh
-        self.cross_section.plot_mesh(ax, pause, materials=False, alpha=0.5)
+        self.section.plot_mesh(ax, pause, materials=False, alpha=0.5)
 
         # set up the colormap
         cmap = cm.get_cmap(name=cmap)
 
         # create triangulation
         triang = tri.Triangulation(
-            self.cross_section.mesh_nodes[:, 0],
-            self.cross_section.mesh_nodes[:, 1],
-            self.cross_section.mesh_elements[:, 0:3],
+            self.section.mesh_nodes[:, 0],
+            self.section.mesh_nodes[:, 1],
+            self.section.mesh_elements[:, 0:3],
         )
 
         # determine minimum and maximum stress values for the contour list
@@ -2404,7 +2406,7 @@ def plot_stress_contour(
         # plot the filled contour, looping through the materials
         for (i, sig) in enumerate(sigs):
             # create and set the mask for the current material
-            mask_array = np.ones(len(self.cross_section.elements), dtype=bool)
+            mask_array = np.ones(len(self.section.elements), dtype=bool)
             mask_array[self.material_groups[i].el_ids] = False
             triang.set_mask(mask_array)
 
@@ -2450,7 +2452,7 @@ def plot_stress_vector(
         post.setup_plot(ax, pause)
 
         # plot the finite element mesh
-        self.cross_section.plot_mesh(ax, pause, materials=False, alpha=0.5)
+        self.section.plot_mesh(ax, pause, materials=False, alpha=0.5)
 
         # set up the colormap
         cmap = cm.get_cmap(name=cmap)
@@ -2471,8 +2473,8 @@ def plot_stress_vector(
             c = np.hypot(sigx, sigy)
 
             quiv = ax.quiver(
-                self.cross_section.mesh_nodes[:, 0],
-                self.cross_section.mesh_nodes[:, 1],
+                self.section.mesh_nodes[:, 0],
+                self.section.mesh_nodes[:, 1],
                 sigx,
                 sigy,
                 c,
@@ -2512,7 +2514,7 @@ def plot_stress_vector(
 
     def get_stress(self):
         """Returns the stresses within each material belonging to the current
-        :class:`~sectionproperties.analysis.cross_section.StressPost` object.
+        :class:`~sectionproperties.analysis.section.StressPost` object.
 
         :return: A list of dictionaries containing the cross-section stresses for each material.
         :rtype: list[dict]
@@ -2572,24 +2574,11 @@ def get_stress(self):
 
         ::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.pre.pre import Material
-            from sectionproperties.analysis.cross_section import Section
-
-            steel = Material(
-                name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, density=7.85e-6,
-                yield_strength=250, color='grey'
-            )
-            timber = Material(
-                name='Timber', elastic_modulus=8e3, poissons_ratio=0.35, density=6.5e-7,
-                yield_strength=20, color='burlywood'
-            )
-
-            geom_steel = sections.rectangular_section(d=50, b=50, material=steel)
-            geom_timber = sections.rectangular_section(d=50, b=50, material=timber)
-            geometry = geom_timber.align_to(geom_steel, on="right") + geom_steel
-            geometry.create_mesh(mesh_sizes=[10, 5])
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
             section.calculate_geometric_properties()
@@ -2678,10 +2667,10 @@ def plot_stress_n_zz(
         The following example plots the normal stress within a 150x90x12 UA section resulting from
         an axial force of 10 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -2728,10 +2717,10 @@ def plot_stress_mxx_zz(
         The following example plots the normal stress within a 150x90x12 UA section resulting from
         a bending moment about the x-axis of 5 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -2778,10 +2767,10 @@ def plot_stress_myy_zz(
         The following example plots the normal stress within a 150x90x12 UA section resulting from
         a bending moment about the y-axis of 2 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -2828,10 +2817,10 @@ def plot_stress_m11_zz(
         The following example plots the normal stress within a 150x90x12 UA section resulting from
         a bending moment about the 11-axis of 5 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -2878,10 +2867,10 @@ def plot_stress_m22_zz(
         The following example plots the normal stress within a 150x90x12 UA section resulting from
         a bending moment about the 22-axis of 2 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -2929,10 +2918,10 @@ def plot_stress_m_zz(
         a bending moment about the x-axis of 5 kN.m, a bending moment about the y-axis of 2 kN.m
         and a bending moment of 3 kN.m about the 11-axis::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -2979,10 +2968,10 @@ def plot_stress_mzz_zx(
         The following example plots the x-component of the shear stress within a 150x90x12 UA
         section resulting from a torsion moment of 1 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3029,10 +3018,10 @@ def plot_stress_mzz_zy(
         The following example plots the y-component of the shear stress within a 150x90x12 UA
         section resulting from a torsion moment of 1 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3079,10 +3068,10 @@ def plot_stress_mzz_zxy(
         The following example plots a contour of the resultant shear stress within a 150x90x12 UA
         section resulting from a torsion moment of 1 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3129,10 +3118,10 @@ def plot_vector_mzz_zxy(
         The following example generates a vector plot of the shear stress within a 150x90x12 UA
         section resulting from a torsion moment of 1 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3181,10 +3170,10 @@ def plot_stress_vx_zx(
         The following example plots the x-component of the shear stress within a 150x90x12 UA
         section resulting from a shear force in the x-direction of 15 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3231,10 +3220,10 @@ def plot_stress_vx_zy(
         The following example plots the y-component of the shear stress within a 150x90x12 UA
         section resulting from a shear force in the x-direction of 15 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3281,10 +3270,10 @@ def plot_stress_vx_zxy(
         The following example plots a contour of the resultant shear stress within a 150x90x12 UA
         section resulting from a shear force in the x-direction of 15 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3331,10 +3320,10 @@ def plot_vector_vx_zxy(
         The following example generates a vector plot of the shear stress within a 150x90x12 UA
         section resulting from a shear force in the x-direction of 15 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3383,10 +3372,10 @@ def plot_stress_vy_zx(
         The following example plots the x-component of the shear stress within a 150x90x12 UA
         section resulting from a shear force in the y-direction of 30 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3433,10 +3422,10 @@ def plot_stress_vy_zy(
         The following example plots the y-component of the shear stress within a 150x90x12 UA
         section resulting from a shear force in the y-direction of 30 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3483,10 +3472,10 @@ def plot_stress_vy_zxy(
         The following example plots a contour of the resultant shear stress within a 150x90x12 UA
         section resulting from a shear force in the y-direction of 30 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3533,10 +3522,10 @@ def plot_vector_vy_zxy(
         The following example generates a vector plot of the shear stress within a 150x90x12 UA
         section resulting from a shear force in the y-direction of 30 kN::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3587,10 +3576,10 @@ def plot_stress_v_zx(
         section resulting from a shear force of 15 kN in the x-direction and 30 kN in the
         y-direction::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3639,10 +3628,10 @@ def plot_stress_v_zy(
         section resulting from a shear force of 15 kN in the x-direction and 30 kN in the
         y-direction::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3691,10 +3680,10 @@ def plot_stress_v_zxy(
         section resulting from a shear force of 15 kN in the x-direction and 30 kN in the
         y-direction::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3743,10 +3732,10 @@ def plot_vector_v_zxy(
         section resulting from a shear force of 15 kN in the x-direction and 30 kN in the
         y-direction::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3796,10 +3785,10 @@ def plot_stress_zz(
         an axial force of 100 kN, a bending moment about the x-axis of 5 kN.m and a bending moment
         about the y-axis of 2 kN.m::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3847,10 +3836,10 @@ def plot_stress_zx(
         section resulting from a torsion moment of 1 kN.m and a shear force of 30 kN in the
         y-direction::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3898,10 +3887,10 @@ def plot_stress_zy(
         section resulting from a torsion moment of 1 kN.m and a shear force of 30 kN in the
         y-direction::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -3949,10 +3938,10 @@ def plot_stress_zxy(
         section resulting from a torsion moment of 1 kN.m and a shear force of 30 kN in the
         y-direction::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -4000,10 +3989,10 @@ def plot_vector_zxy(
         section resulting from a torsion moment of 1 kN.m and a shear force of 30 kN in the
         y-direction::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -4056,12 +4045,12 @@ def plot_stress_1(
 
         ::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
-            geometry.create_mesh(mesh_sizes=[20])
-            section = Section(geometry)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            mesh = geometry.create_mesh(mesh_sizes=[2.5])
+            section = CrossSection(geometry, mesh)
 
             section.calculate_geometric_properties()
             section.calculate_warping_properties()
@@ -4112,12 +4101,12 @@ def plot_stress_3(
 
         ::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
-            geometry.create_mesh(mesh_sizes=[20])
-            section = Section(geometry)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            mesh = geometry.create_mesh(mesh_sizes=[2.5])
+            section = CrossSection(geometry, mesh)
 
             section.calculate_geometric_properties()
             section.calculate_warping_properties()
@@ -4173,10 +4162,10 @@ def plot_stress_vm(
 
         ::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
             geometry.create_mesh(mesh_sizes=[20])
             section = Section(geometry)
 
@@ -4230,12 +4219,12 @@ def plot_mohrs_circles(self, x, y, pause=True, cmap="coolwarm", size=500, dpi=96
 
         ::
 
-            import sectionproperties.pre.sections as sections
-            from sectionproperties.analysis.cross_section import Section
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            from sectionproperties.analysis.section import Section
 
-            geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
-            geometry.create_mesh(mesh_sizes=[20])
-            section = Section(geometry)
+            geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+            mesh = geometry.create_mesh(mesh_sizes=[2.5])
+            section = Section(geometry, mesh)
 
             section.calculate_geometric_properties()
             section.calculate_warping_properties()
@@ -4254,14 +4243,14 @@ def plot_mohrs_circles(self, x, y, pause=True, cmap="coolwarm", size=500, dpi=96
         """
 
         pt = (x, y)
-        nodes = self.cross_section.mesh_nodes
-        ele = self.cross_section.mesh_elements
+        nodes = self.section.mesh_nodes
+        ele = self.section.mesh_elements
         triang = tri.Triangulation(nodes[:, 0], nodes[:, 1], ele[:, 0:3])
 
         # Find in which material group the point lies
         pt_group = None
         for group in self.material_groups:
-            mask_array = np.ones(len(self.cross_section.elements), dtype=bool)
+            mask_array = np.ones(len(self.section.elements), dtype=bool)
             mask_array[group.el_ids] = False
             triang.set_mask(mask_array)
             trifinder = triang.get_trifinder()
@@ -4399,7 +4388,7 @@ class MaterialGroup:
     :cvar material: Material object for the current MaterialGroup
     :vartype material: :class:`~sectionproperties.pre.pre.Material`
     :cvar stress_result: A StressResult object for saving the stresses of the current material
-    :vartype stress_result: :class:`~sectionproperties.analysis.cross_section.StressResult`
+    :vartype stress_result: :class:`~sectionproperties.analysis.section.StressResult`
     :cvar elements: A list of finite element objects that are of the current material type
     :vartype elements: list[:class:`~sectionproperties.analysis.fea.Tri6`]
     :cvar el_ids: A list of the element IDs of the elements that are of the current material type
diff --git a/sectionproperties/pre/bisect_section.py b/sectionproperties/pre/bisect_section.py
index a221230e..44b414a7 100644
--- a/sectionproperties/pre/bisect_section.py
+++ b/sectionproperties/pre/bisect_section.py
@@ -1,5 +1,4 @@
 from typing import Tuple, Union, List, Optional
-from sectionproperties.pre import sections
 
 import numpy as np
 import shapely
diff --git a/sectionproperties/pre/dxf.py b/sectionproperties/pre/dxf.py
deleted file mode 100644
index 50df83a1..00000000
--- a/sectionproperties/pre/dxf.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import pathlib
-from shapely.geometry import Polygon, MultiPolygon
-import cad_to_shapely as c2s
-from sectionproperties.pre.sections import Geometry, CompoundGeometry
-
-
-def load_dxf(dxf_filepath: pathlib.Path):
-    """
-    Import any-old-shape in dxf format for analysis.
-    Code by aegis1980 and connorferster
-    """
-    if not dxf_filepath.exists():
-        raise ValueError(f"The filepath does not exist: {dxf_filepath}")
-
-    my_dxf = c2s.dxf.DxfImporter(dxf_filepath)
-    my_dxf.process()
-    my_dxf.cleanup()
-
-    polygons = my_dxf.polygons
-    new_polygons = c2s.utils.find_holes(polygons)
-    if isinstance(new_polygons, MultiPolygon):
-        return CompoundGeometry(new_polygons)
-    elif isinstance(new_polygons, Polygon):
-        return Geometry(new_polygons)
-    else:
-        print(f"No shapely.Polygon objects found in file: {dxf_filepath}")
diff --git a/sectionproperties/pre/sections.py b/sectionproperties/pre/geometry.py
similarity index 58%
rename from sectionproperties/pre/sections.py
rename to sectionproperties/pre/geometry.py
index 197ceffa..75a84a8f 100644
--- a/sectionproperties/pre/sections.py
+++ b/sectionproperties/pre/geometry.py
@@ -76,7 +76,7 @@ def __init__(
         self.compile_geometry()
 
     def _repr_svg_(self):
-        print("sectionproperties.pre.sections.Geometry")
+        print("sectionproperties.pre.geometry.Geometry")
         print(f"object at: {hex(id(self))}")
         print(f"Material: {self.material.name}")
         return self.geom._repr_svg_()
@@ -226,7 +226,7 @@ def from_3dm(cls, filepath: Union[str, pathlib.Path], **kwargs) -> Geometry:
             Try adjusting the keyword arguments if this error is raised.
         :return:
             A Geometry object.
-        :rtype: :class:`sectionproperties.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         :Keyword Arguments:
             * *refine_num* (``int, optional``) --
@@ -277,7 +277,7 @@ def from_rhino_encoding(cls, r3dm_brep: str, **kwargs) -> Geometry:
             See below.
         :return:
             A Geometry object found in the encoded string.
-        :rtype: :class:`sectionproperties.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         :Keyword Arguments:
             * *refine_num* (``int, optional``) --
@@ -341,14 +341,14 @@ def create_mesh(self, mesh_sizes: Union[float, List[float]]):
 
         :return: Geometry-object with mesh data stored in .mesh attribute. Returned
             Geometry-object is self, not a new instance.
-        :rtype: :class:`sectionproperties.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         The following example creates a circular cross-section with a diameter of 50 with 64
         points, and generates a mesh with a maximum triangular area of 2.5::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.standard_sections as standard_sections
 
-            geometry = sections.CircularSection(d=50, n=64)
+            geometry = standard_sections.circular_section(d=50, n=64)
             geometry = geometry.create_mesh(mesh_sizes=2.5)
 
         ..  figure:: ../images/sections/circle_mesh.png
@@ -387,7 +387,7 @@ def align_to(
 
         :param other: Either another Geometry or a tuple representing an
             *(x,y)* coordinate point that 'self' should align to.
-        :type other: Union[sectionproperties.pre.sections.Geometry, Tuple[float, float]]
+        :type other: Union[sectionproperties.pre.geometry.Geometry, Tuple[float, float]]
 
         :param on: A str of either "left", "right", "bottom", or "top" indicating which
             side of 'other' that self should be aligned to.
@@ -398,7 +398,7 @@ def align_to(
         :type inner: bool
 
         :return: Geometry object translated to alignment location
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
         """
         # Mappings are for indexes in the list of bbox extents of both
         # 'self' and 'align_to'. i.e. a mapping of which "word" corresponds
@@ -460,10 +460,10 @@ def align_center(self, align_to: Optional[Geometry] = None):
         object will be aligned with it's centroid at the origin.
 
         :param align_to: Another Geometry to align to or None (default is None)
-        :type align_to: Optional[sectionproperties.pre.sections.Geometry]
+        :type align_to: Optional[sectionproperties.pre.geometry.Geometry]
 
         :return: Geometry object translated to new alignment
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
         """
         cx, cy = list(self.geom.centroid.coords)[0]
         # Suggested by Agent 6-6-6: Hard-rounding of cx and cy allows
@@ -494,7 +494,7 @@ def shift_section(
         :type y_offset: float
 
         :return: New Geometry-object shifted by 'x_offset' and 'y_offset'
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
         """
         # Move assigned control point
         new_ctrl_point = None
@@ -526,13 +526,13 @@ def rotate_section(
         :param use_radians: Boolean to indicate whether 'angle' is in degrees or radians. If True, 'angle' is interpreted as radians.
 
         :return: New Geometry-object rotated by 'angle' about 'rot_point'
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         The following example rotates a 200UB25 section clockwise by 30 degrees::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
 
-            geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
+            geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
             new_geometry = geometry.rotate_section(angle=-30)
         """
         new_ctrl_point = None
@@ -562,13 +562,13 @@ def mirror_section(
         :type mirror_point: Union[list[float, float], str]
 
         :return: New Geometry-object mirrored on 'axis' about 'mirror_point'
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         The following example mirrors a 200PFC section about the y-axis and the point (0, 0)::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
 
-            geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
+            geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
             new_geometry = geometry.mirror_section(axis='y', mirror_point=[0, 0])
         """
         x_mirror = 1
@@ -631,10 +631,10 @@ def split_section(
 
         The following example splits a 200PFC section about the y-axis::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
             from shapely.geometry import LineString
 
-            geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
+            geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
             right_geom, left_geom = geometry.split_section((0, 0), (0, 1))
         """
         if point_j:
@@ -680,11 +680,11 @@ def offset_perimeter(
         :type resolution: float
 
         :return: Geometry object translated to new alignment
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         The following example erodes a 200PFC section by 2 mm::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
 
             geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
             new_geometry = geometry.offset_perimeter(amount=-2)
@@ -785,14 +785,14 @@ def shift_points(
         :type abs_y: Optional[float]
 
         :return: Geometry object with selected points translated to the new location.
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         The following example expands the sides of a rectangle, one point at a time,
         to make it a square::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.standard_sections as standard_sections
 
-            geometry = sections.rectangular_section(d=200, b=150)
+            geometry = standard_sections.rectangular_section(d=200, b=150)
 
             # Using relative shifting
             one_pt_shifted_geom = geometry.shift_points(point_idxs=1, dx=50)
@@ -868,9 +868,9 @@ def plot_geometry(
         The following example creates a CHS discretised with 64 points, with a diameter of 48 and
         thickness of 3.2, and plots the geometry::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
 
-            geometry = sections.chs(d=48, t=3.2, n=64)
+            geometry = steel_sections.circular_hollow_section(d=48, t=3.2, n=64)
             geometry.plot_geometry()
 
         ..  figure:: ../images/sections/chs_geometry.png
@@ -1125,9 +1125,6 @@ def __and__(self, other):
             )
 
 
-###
-
-
 class CompoundGeometry(Geometry):
     """Class for defining a geometry of multiple distinct regions, each potentially
     having different material properties.
@@ -1143,7 +1140,7 @@ class CompoundGeometry(Geometry):
 
     :cvar geoms: either a list of Geometry objects or a shapely.geometry.MultiPolygon
         instance.
-    :vartype geoms: Union[shapely.geometry.MultiPolygon, List[sectionproperties.pre.sections.Geometry]]
+    :vartype geoms: Union[shapely.geometry.MultiPolygon, List[sectionproperties.pre.geometry.Geometry]]
     """
 
     def __init__(self, geoms: Union[MultiPolygon, List[Geometry]]):
@@ -1372,14 +1369,14 @@ def create_mesh(self, mesh_sizes: List[float]):
 
         :return: Geometry-object with mesh data stored in .mesh attribute. Returned
             Geometry-object is self, not a new instance.
-        :rtype: :class:`sectionproperties.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         The following example creates a circular cross-section with a diameter of 50 with 64
         points, and generates a mesh with a maximum triangular area of 2.5::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.standard_sections as standard_sections
 
-            geometry = sections.circular_section(d=50, n=64)
+            geometry = standard_sections.circular_section(d=50, n=64)
             geometry = geometry.create_mesh(mesh_sizes=[2.5])
 
         ..  figure:: ../images/sections/circle_mesh.png
@@ -1407,7 +1404,7 @@ def shift_section(self, x_offset: float = 0, y_offset: float = 0):
         :type y_offset: float
 
         :return: CompoundGeometry object shifted by 'x_offset' and 'y_offset'
-        :rtype: :class:`sections.pre.sections.CompoundGeometry`
+        :rtype: :class:`sectionproperties.pre.sections.CompoundGeometry`
         """
         geoms_acc = []
         for geom in self.geoms:
@@ -1432,14 +1429,15 @@ def rotate_section(
         :param use_radians: Boolean to indicate whether 'angle' is in degrees or radians. If True, 'angle' is interpreted as radians.
 
         :return: CompoundGeometry object rotated by 'angle' about 'rot_point'
-        :rtype: :class:`sections.pre.sections.CompoundGeometry`
+        :rtype: :class:`sectionproperties.pre.sections.CompoundGeometry`
 
-        The following example rotates a 200UB25 section clockwise by 30 degrees::
+        The following example rotates a 200UB25 section with a plate clockwise by 30 degrees::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            import sectionproperties.pre.library.standard_sections as standard_sections
 
-            geometry_1 = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
-            geometry_2 = sections.rectangular_section(d=20, b=133)
+            geometry_1 = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
+            geometry_2 = standard_sections.rectangular_section(d=20, b=133)
             compound = geometry_2.align_center(geometry_1).align_to(geometry_1, on="top") + geometry_1
             new_compound = compound.rotate_section(angle=-30)
         """
@@ -1463,16 +1461,17 @@ def mirror_section(
         :type mirror_point: Union[list[float, float], str]
 
         :return: Geometry object mirrored on 'axis' about 'mirror_point'
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
-        The following example mirrors a 200PFC section about the y-axis and the point (0, 0)::
+        The following example mirrors a 200PFC section with a plate about the y-axis and the point (0, 0)::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            import sectionproperties.pre.library.standard_sections as standard_sections
 
-            geometry_1 = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
-            geometry_2 = sections.rectangular_section(d=20, b=133)
+            geometry_1 = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
+            geometry_2 = standard_sections.rectangular_section(d=20, b=133)
             compound = geometry_2.align_center(geometry_1).align_to(geometry_1, on="top") + geometry_1
-            new_compound = compound.mirror_section(axis='y')
+            new_compound = compound.mirror_section(axis='y', mirror_point=[0,0])
         """
         geoms_acc = []
         for geom in self.geoms:
@@ -1493,10 +1492,10 @@ def align_center(self, align_to: Optional[Geometry] = None):
         geometry's assigned material.
 
         :param align_to: Another Geometry to align to or None (default is None)
-        :type align_to: Optional[sectionproperties.pre.sections.Geometry]
+        :type align_to: Optional[sectionproperties.pre.geometry.Geometry]
 
         :return: Geometry object translated to new alignment
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
         """
         EA_sum = sum(
             [
@@ -1564,10 +1563,10 @@ def split_section(
 
         The following example splits a 200PFC section about the y-axis::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
             from shapely.geometry import LineString
 
-            geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
+            geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8)
             right_geom, left_geom = geometry.split_section((0, 0), (0, 1))
         """
         top_geoms_acc = []
@@ -1593,14 +1592,15 @@ def offset_perimeter(
         :param resolution: Number of segments used to approximate a quarter circle around a point
         :type resolution: float
         :return: Geometry object translated to new alignment
-        :rtype: :class:`sections.pre.sections.Geometry`
+        :rtype: :class:`sectionproperties.pre.geometry.Geometry`
 
         The following example erodes a 200UB25 with a 12 plate stiffener section by 2 mm::
 
-            import sectionproperties.pre.sections as sections
+            import sectionproperties.pre.library.steel_sections as steel_sections
+            import sectionproperties.pre.library.standard_sections as standard_sections
 
-            geometry_1 = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
-            geometry_2 = sections.rectangular_section(d=12, b=133)
+            geometry_1 = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8)
+            geometry_2 = standard_sections.rectangular_section(d=12, b=133)
             compound = geometry_2.align_center(geometry_1).align_to(geometry_1, on="top") + geometry_1
             new_geometry = compound.offset_perimeter(amount=-2)
 
@@ -1882,1461 +1882,3 @@ def filter_non_polygons(
             return MultiPolygon(acc)
     elif isinstance(input_geom, (Point, LineString)):
         return Polygon()
-
-
-def draw_radius(
-    pt: list, r: float, theta: float, n, ccw: bool = True
-):  # Changed 'anti' to ccw to match shapely
-    """Adds a quarter radius of points to the points list - centered at point *pt*, with radius
-    *r*, starting at angle *theta*, with *n* points. If r = 0, adds pt only.
-
-    :param pt: Centre of radius *(x,y)*
-    :type pt: list[float, float]
-    :param float r: Radius
-    :param float theta: Initial angle
-    :param int n: Number of points
-    :param bool ccw: Counter-clockwise rotation?
-    """
-    points = []
-    if r == 0:
-        points.append(pt)
-        return points
-
-    if ccw:
-        mult = 1
-    else:
-        mult = -1
-
-    # calculate radius of points
-    for i in range(n):
-        # determine angle
-        t = theta + mult * i * 1.0 / max(1, n - 1) * np.pi * 0.5
-
-        x = pt[0] + r * np.cos(t)
-        y = pt[1] + r * np.sin(t)
-        points.append([x, y])
-    return points
-
-
-def rectangular_section(
-    b, d, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a rectangular section with the bottom left corner at the origin *(0, 0)*, with
-    depth *d* and width *b*.
-
-    :param float d: Depth (y) of the rectangle
-    :param float b: Width (x) of the rectangle
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a rectangular cross-section with a depth of 100 and width of 50,
-    and generates a mesh with a maximum triangular area of 5::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.rectangular_section(d=100, b=50)
-        geometry.create_mesh(mesh_sizes=[5])
-
-    ..  figure:: ../images/sections/rectangle_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Rectangular section geometry.
-
-    ..  figure:: ../images/sections/rectangle_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points = [[0, 0], [b, 0], [b, d], [0, d]]
-    rectangle = Polygon(points)
-    return Geometry(rectangle, material)
-
-
-def circular_section(
-    d: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a solid circle centered at the origin *(0, 0)* with diameter *d* and using *n*
-    points to construct the circle.
-
-    :param float d: Diameter of the circle
-    :param int n: Number of points discretising the circle
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a circular geometry with a diameter of 50 with 64 points,
-    and generates a mesh with a maximum triangular area of 2.5::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.circular_section(d=50, n=64)
-        geometry.create_mesh(mesh_sizes=[2.5])
-
-    ..  figure:: ../images/sections/circle_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Circular section geometry.
-
-    ..  figure:: ../images/sections/circle_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    x_off, y_off = (0, 0)
-    points = []
-    # loop through each point on the circle
-    for i in range(n):
-        # determine polar angle
-        theta = i * 2 * np.pi * 1.0 / n
-
-        # calculate location of the point
-        x = 0.5 * d * np.cos(theta) + x_off
-        y = 0.5 * d * np.sin(theta) + y_off
-
-        # append the current point to the points list
-        points.append([x, y])
-
-    circle = Polygon(points)
-    return Geometry(circle, material)
-
-
-def circular_hollow_section(
-    d: float, t: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a circular hollow section (CHS) centered at the origin *(0, 0)*, with diameter *d* and
-    thickness *t*, using *n* points to construct the inner and outer circles.
-
-    :param float d: Outer diameter of the CHS
-    :param float t: Thickness of the CHS
-    :param int n: Number of points discretising the inner and outer circles
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a CHS discretised with 64 points, with a diameter of 48 and
-    thickness of 3.2, and generates a mesh with a maximum triangular area of 1.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.circular_hollow_section(d=48, t=3.2, n=64)
-        geometry.create_mesh(mesh_sizes=[1.0])
-
-    ..  figure:: ../images/sections/chs_geometry.png
-        :align: center
-        :scale: 75 %
-
-        CHS geometry.
-
-    ..  figure:: ../images/sections/chs_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points_inner = []
-    points_outer = []
-    # loop through each point of the CHS
-    for i in range(n):
-        # determine polar angle
-        theta = i * 2 * np.pi * 1.0 / n
-
-        # calculate location of outer and inner points
-        x_outer = 0.5 * d * np.cos(theta)
-        y_outer = 0.5 * d * np.sin(theta)
-        x_inner = (0.5 * d - t) * np.cos(theta)
-        y_inner = (0.5 * d - t) * np.sin(theta)
-
-        # append the current points to the points list
-        points_outer.append([x_outer, y_outer])
-        points_inner.append([x_inner, y_inner])
-
-    inner_circle = Polygon(points_inner)
-    outer_circle = Polygon(points_outer)
-    return Geometry(outer_circle - inner_circle, material)
-
-
-def elliptical_section(
-    d_y: float, d_x: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a solid ellipse centered at the origin *(0, 0)* with vertical diameter *d_y* and
-    horizontal diameter *d_x*, using *n* points to construct the ellipse.
-
-    :param float d_y: Diameter of the ellipse in the y-dimension
-    :param float d_x: Diameter of the ellipse in the x-dimension
-    :param int n: Number of points discretising the ellipse
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates an elliptical cross-section with a vertical diameter of 25 and
-    horizontal diameter of 50, with 40 points, and generates a mesh with a maximum triangular area
-    of 1.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.elliptical_section(d_y=25, d_x=50, n=40)
-        geometry.create_mesh(mesh_sizes=[1.0])
-
-    ..  figure:: ../images/sections/ellipse_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Elliptical section geometry.
-
-    ..  figure:: ../images/sections/ellipse_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points = []
-
-    # loop through each point on the ellipse
-    for i in range(n):
-        # determine polar angle
-        theta = i * 2 * np.pi * 1.0 / n
-
-        # calculate location of the point
-        x = 0.5 * d_x * np.cos(theta)
-        y = 0.5 * d_y * np.sin(theta)
-
-        # append the current point to the points list
-        points.append([x, y])
-
-    ellipse = Polygon(points)
-    return Geometry(ellipse, material)
-
-
-def elliptical_hollow_section(
-    d_y: float,
-    d_x: float,
-    t: float,
-    n: int,
-    material: pre.Material = pre.DEFAULT_MATERIAL,
-) -> Geometry:
-    """Constructs an elliptical hollow section (EHS) centered at the origin *(0, 0)*, with outer vertical
-    diameter *d_y*, outer horizontal diameter *d_x*, and thickness *t*, using *n* points to
-    construct the inner and outer ellipses.
-
-    :param float d_y: Diameter of the ellipse in the y-dimension
-    :param float d_x: Diameter of the ellipse in the x-dimension
-    :param float t: Thickness of the EHS
-    :param int n: Number of points discretising the inner and outer ellipses
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a EHS discretised with 30 points, with a outer vertical diameter
-    of 25, outer horizontal diameter of 50, and thickness of 2.0, and generates a mesh with a
-    maximum triangular area of 0.5::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.elliptical_hollow_section(d_y=25, d_x=50, t=2.0, n=64)
-        geometry.create_mesh(mesh_sizes=[0.5])
-
-    ..  figure:: ../images/sections/ehs_geometry.png
-        :align: center
-        :scale: 75 %
-
-        EHS geometry.
-
-    ..  figure:: ../images/sections/ehs_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points_inner = []
-    points_outer = []
-    # loop through each point of the EHS
-    for i in range(n):
-        # determine polar angle
-        theta = i * 2 * np.pi * 1.0 / n
-
-        # calculate location of outer and inner points
-        x_outer = 0.5 * d_x * np.cos(theta)
-        y_outer = 0.5 * d_y * np.sin(theta)
-        x_inner = ((0.5 * d_x) - t) * np.cos(theta)
-        y_inner = ((0.5 * d_y) - t) * np.sin(theta)
-
-        # append the current points to the points list
-        points_outer.append([x_outer, y_outer])
-        points_inner.append([x_inner, y_inner])
-
-    outer = Polygon(points_outer)
-    inner = Polygon(points_inner)
-    return Geometry(outer - inner, material)
-
-
-def rectangular_hollow_section(
-    b: float,
-    d: float,
-    t: float,
-    r_out: float,
-    n_r: int,
-    material: pre.Material = pre.DEFAULT_MATERIAL,
-) -> Geometry:
-    """Constructs a rectangular hollow section (RHS) centered at *(b/2, d/2)*, with depth *d*, width *b*,
-    thickness *t* and outer radius *r_out*, using *n_r* points to construct the inner and outer
-    radii. If the outer radius is less than the thickness of the RHS, the inner radius is set to
-    zero.
-
-    :param float d: Depth of the RHS
-    :param float b: Width of the RHS
-    :param float t: Thickness of the RHS
-    :param float r_out: Outer radius of the RHS
-    :param int n_r: Number of points discretising the inner and outer radii
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates an RHS with a depth of 100, a width of 50, a thickness of 6 and
-    an outer radius of 9, using 8 points to discretise the inner and outer radii. A mesh is
-    generated with a maximum triangular area of 2.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.rectangular_hollow_section(d=100, b=50, t=6, r_out=9, n_r=8)
-        geometry.create_mesh(mesh_sizes=[2.0])
-
-    ..  figure:: ../images/sections/rhs_geometry.png
-        :align: center
-        :scale: 75 %
-
-        RHS geometry.
-
-    ..  figure:: ../images/sections/rhs_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points_inner = []
-    points_outer = []
-    # calculate internal radius
-    r_in = max(r_out - t, 0)
-    # construct the outer radius points
-    points_outer += draw_radius([r_out, r_out], r_out, np.pi, n_r)
-    points_outer += draw_radius([b - r_out, r_out], r_out, 1.5 * np.pi, n_r)
-    points_outer += draw_radius([b - r_out, d - r_out], r_out, 0, n_r)
-    points_outer += draw_radius([r_out, d - r_out], r_out, 0.5 * np.pi, n_r)
-
-    points_inner += draw_radius([t + r_in, t + r_in], r_in, np.pi, n_r)
-    points_inner += draw_radius([b - t - r_in, t + r_in], r_in, 1.5 * np.pi, n_r)
-    points_inner += draw_radius([b - t - r_in, d - t - r_in], r_in, 0, n_r)
-    points_inner += draw_radius([t + r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r)
-
-    outer = Polygon(points_outer)
-    inner = Polygon(points_inner)
-    return Geometry(outer - inner, material)
-
-
-def i_section(
-    d: float,
-    b: float,
-    t_f: float,
-    t_w: float,
-    r: float,
-    n_r: int,
-    material: pre.Material = pre.DEFAULT_MATERIAL,
-) -> Geometry:  # More specific description and less ambiguous? e.g. not an "S" section.
-    """Constructs an I-section centered at *(b/2, d/2)*, with depth *d*, width *b*, flange
-    thickness *t_f*, web thickness *t_w*, and root radius *r*, using *n_r* points to construct the
-    root radius.
-
-    :param float d: Depth of the I-section
-    :param float b: Width of the I-section
-    :param float t_f: Flange thickness of the I-section
-    :param float t_w: Web thickness of the I-section
-    :param float r: Root radius of the I-section
-    :param int n_r: Number of points discretising the root radius
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates an I-section with a depth of 203, a width of 133, a flange
-    thickness of 7.8, a web thickness of 5.8 and a root radius of 8.9, using 16 points to
-    discretise the root radius. A mesh is generated with a maximum triangular area of 3.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16)
-        geometry.create_mesh(mesh_sizes=[3.0])
-
-    ..  figure:: ../images/sections/isection_geometry.png
-        :align: center
-        :scale: 75 %
-
-        I-section geometry.
-
-    ..  figure:: ../images/sections/isection_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points = []
-
-    # add first three points
-    points.append([0, 0])
-    points.append([b, 0])
-    points.append([b, t_f])
-
-    # construct the bottom right radius
-    pt = [b * 0.5 + t_w * 0.5 + r, t_f + r]
-    points += draw_radius(pt, r, 1.5 * np.pi, n_r, False)
-
-    # construct the top right radius
-    pt = [b * 0.5 + t_w * 0.5 + r, d - t_f - r]
-    points += draw_radius(pt, r, np.pi, n_r, False)
-
-    # add the next four points
-    points.append([b, d - t_f])
-    points.append([b, d])
-    points.append([0, d])
-    points.append([0, d - t_f])
-
-    # construct the top left radius
-    pt = [b * 0.5 - t_w * 0.5 - r, d - t_f - r]
-    points += draw_radius(pt, r, 0.5 * np.pi, n_r, False)
-
-    # construct the bottom left radius
-    pt = [b * 0.5 - t_w * 0.5 - r, t_f + r]
-    points += draw_radius(pt, r, 0, n_r, False)
-
-    # # add the last point
-    points.append([0, t_f])
-    i_section = Polygon(points)
-    return Geometry(i_section, material)
-
-
-def mono_i_section(
-    d, b_t, b_b, t_fb, t_ft, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a monosymmetric I-section centered at *(max(b_t, b_b)/2, d/2)*, with depth *d*,
-    top flange width *b_t*, bottom flange width *b_b*, top flange thickness *t_ft*, top flange
-    thickness *t_fb*, web thickness *t_w*, and root radius *r*, using *n_r* points to construct the
-    root radius.
-
-    :param float d: Depth of the I-section
-    :param float b_t: Top flange width
-    :param float b_b: Bottom flange width
-    :param float t_ft: Top flange thickness of the I-section
-    :param float t_fb: Bottom flange thickness of the I-section
-    :param float t_w: Web thickness of the I-section
-    :param float r: Root radius of the I-section
-    :param int n_r: Number of points discretising the root radius
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a monosymmetric I-section with a depth of 200, a top flange width
-    of 50, a top flange thickness of 12, a bottom flange width of 130, a bottom flange thickness of
-    8, a web thickness of 6 and a root radius of 8, using 16 points to discretise the root radius.
-    A mesh is generated with a maximum triangular area of 3.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.mono_i_section(
-            d=200, b_t=50, b_b=130, t_ft=12, t_fb=8, t_w=6, r=8, n_r=16
-        )
-        geometry.create_mesh(mesh_sizes=[3.0])
-
-    ..  figure:: ../images/sections/monoisection_geometry.png
-        :align: center
-        :scale: 75 %
-
-        I-section geometry.
-
-    ..  figure:: ../images/sections/monoisection_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points = []
-    # calculate central axis
-    x_central = max(b_t, b_b) * 0.5
-
-    # add first three points
-    points.append([x_central - b_b * 0.5, 0])
-    points.append([x_central + b_b * 0.5, 0])
-    points.append([x_central + b_b * 0.5, t_fb])
-
-    # construct the bottom right radius
-    pt = [x_central + t_w * 0.5 + r, t_fb + r]
-    points += draw_radius(pt, r, 1.5 * np.pi, n_r, False)
-
-    # construct the top right radius
-    pt = [x_central + t_w * 0.5 + r, d - t_ft - r]
-    points += draw_radius(pt, r, np.pi, n_r, False)
-
-    # add the next four points
-    points.append([x_central + b_t * 0.5, d - t_ft])
-    points.append([x_central + b_t * 0.5, d])
-    points.append([x_central - b_t * 0.5, d])
-    points.append([x_central - b_t * 0.5, d - t_ft])
-
-    # construct the top left radius
-    pt = [x_central - t_w * 0.5 - r, d - t_ft - r]
-    points += draw_radius(pt, r, 0.5 * np.pi, n_r, False)
-
-    # construct the bottom left radius
-    pt = [x_central - t_w * 0.5 - r, t_fb + r]
-    points += draw_radius(pt, r, 0, n_r, False)
-
-    # add the last point
-    points.append([x_central - b_b * 0.5, t_fb])
-
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-def tapered_flange_i_section(
-    d, b, t_f, t_w, r_r, r_f, alpha, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a Tapered Flange I-section centered at *(b/2, d/2)*, with depth *d*, width *b*,
-    mid-flange thickness *t_f*, web thickness *t_w*, root radius *r_r*, flange radius *r_f* and
-    flange angle *alpha*, using *n_r* points to construct the radii.
-
-    :param float d: Depth of the Tapered Flange I-section
-    :param float b: Width of the Tapered Flange I-section
-    :param float t_f: Mid-flange thickness of the Tapered Flange I-section (measured at the point
-        equidistant from the face of the web to the edge of the flange)
-    :param float t_w: Web thickness of the Tapered Flange I-section
-    :param float r_r: Root radius of the Tapered Flange I-section
-    :param float r_f: Flange radius of the Tapered Flange I-section
-    :param float alpha: Flange angle of the Tapered Flange I-section (degrees)
-    :param int n_r: Number of points discretising the radii
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a Tapered Flange I-section with a depth of 588, a width of 191, a
-    mid-flange thickness of 27.2, a web thickness of 15.2, a root radius of 17.8, a flange radius
-    of 8.9 and a flange angle of 8°, using 16 points to discretise the radii. A mesh is generated
-    with a maximum triangular area of 20.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.tapered_flange_i_section(
-            d=588, b=191, t_f=27.2, t_w=15.2, r_r=17.8, r_f=8.9, alpha=8, n_r=16
-        )
-        geometry.create_mesh(mesh_sizes=[20.0])
-
-    ..  figure:: ../images/sections/taperedisection_geometry.png
-        :align: center
-        :scale: 75 %
-
-        I-section geometry.
-
-    ..  figure:: ../images/sections/taperedisection_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points = []
-
-    # calculate alpha in radians
-    alpha_rad = np.pi * alpha / 180
-
-    # calculate the height of the flange toe and dimensions of the straight
-    x1 = b * 0.25 - t_w * 0.25 - r_f * (1 - np.sin(alpha_rad))
-    y1 = x1 * np.tan(alpha_rad)
-    x2 = b * 0.25 - t_w * 0.25 - r_r * (1 - np.sin(alpha_rad))
-    y2 = x2 * np.tan(alpha_rad)
-    y_t = t_f - y1 - r_f * np.cos(alpha_rad)
-
-    # add first two points
-    points.append([0, 0])
-    points.append([b, 0])
-
-    # construct the bottom right flange toe radius
-    if r_f == 0:
-        points.append([b, y_t])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-
-            # calculate the locations of the radius points
-            x = b - r_f + r_f * np.cos(theta)
-            y = y_t + r_f * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the bottom right root radius
-    if r_r == 0:
-        points.append([b * 0.5 + t_w * 0.5, t_f + y2])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = (3.0 / 2 * np.pi - alpha_rad) - (
-                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-            )
-
-            # calculate the locations of the radius points
-            x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta)
-            y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the top right root radius
-    if r_r == 0:
-        points.append([b * 0.5 + t_w * 0.5, d - t_f - y2])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-
-            # calculate the locations of the radius points
-            x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta)
-            y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the top right flange toe radius
-    if r_f == 0:
-        points.append([b, d - y_t])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = (3.0 * np.pi / 2 + alpha_rad) + i * 1.0 / max(1, n_r - 1) * (
-                np.pi * 0.5 - alpha_rad
-            )
-
-            # calculate the locations of the radius points
-            x = b - r_f + r_f * np.cos(theta)
-            y = d - y_t + r_f * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # add the next two points
-    points.append([b, d])
-    points.append([0, d])
-
-    # construct the top left flange toe radius
-    if r_f == 0:
-        points.append([0, d - y_t])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = np.pi + (i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad))
-
-            # calculate the locations of the radius points
-            x = r_f + r_f * np.cos(theta)
-            y = d - y_t + r_f * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the top left root radius
-    if r_r == 0:
-        points.append([b * 0.5 - t_w * 0.5, d - t_f - y2])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = (np.pi * 0.5 - alpha_rad) - (
-                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-            )
-
-            # calculate the locations of the radius points
-            x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta)
-            y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the bottom left root radius
-    if r_r == 0:
-        points.append([b * 0.5 - t_w * 0.5, t_f + y2])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = -i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-
-            # calculate the locations of the radius points
-            x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta)
-            y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the bottom left flange toe radius
-    if r_f == 0:
-        points.append([0, y_t])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = (np.pi * 0.5 + alpha_rad) + (
-                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-            )
-
-            # calculate the locations of the radius points
-            x = r_f + r_f * np.cos(theta)
-            y = y_t + r_f * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-def channel_section(
-    d, b, t_f, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a parallel-flange channel (PFC) section with the bottom left corner at the origin *(0, 0)*, with depth *d*,
-    width *b*, flange thickness *t_f*, web  thickness *t_w* and root radius *r*, using *n_r* points
-    to construct the root radius.
-
-    :param float d: Depth of the PFC section
-    :param float b: Width of the PFC section
-    :param float t_f: Flange thickness of the PFC section
-    :param float t_w: Web thickness of the PFC section
-    :param float r: Root radius of the PFC section
-    :param int n_r: Number of points discretising the root radius
-    :param shift: Vector that shifts the cross-section by *(x, y)*
-    :type shift: list[float, float]
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a PFC section with a depth of 250, a width of 90, a flange
-    thickness of 15, a web thickness of 8 and a root radius of 12, using 8 points to discretise the
-    root radius. A mesh is generated with a maximum triangular area of 5.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.channel_section(d=250, b=90, t_f=15, t_w=8, r=12, n_r=8)
-        geometry.create_mesh(mesh_sizes=[5.0])
-
-    ..  figure:: ../images/sections/pfc_geometry.png
-        :align: center
-        :scale: 75 %
-
-        PFC geometry.
-
-    ..  figure:: ../images/sections/pfc_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points = []
-
-    # add first three points
-    points.append([0, 0])
-    points.append([b, 0])
-    points.append([b, t_f])
-
-    # construct the bottom right radius
-    pt = [t_w + r, t_f + r]
-    points += draw_radius(pt, r, 1.5 * np.pi, n_r, False)
-
-    # construct the top right radius
-    pt = [t_w + r, d - t_f - r]
-    points += draw_radius(pt, r, np.pi, n_r, False)
-
-    # add last three points
-    points.append([b, d - t_f])
-    points.append([b, d])
-    points.append([0, d])
-
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-def tapered_flange_channel(
-    d, b, t_f, t_w, r_r, r_f, alpha, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a Tapered Flange Channel section with the bottom left corner at the origin
-    *(0, 0)*, with depth *d*, width *b*, mid-flange thickness *t_f*, web thickness *t_w*, root
-    radius *r_r*, flange radius *r_f* and flange angle *alpha*, using *n_r* points to construct the
-    radii.
-
-    :param float d: Depth of the Tapered Flange Channel section
-    :param float b: Width of the Tapered Flange Channel section
-    :param float t_f: Mid-flange thickness of the Tapered Flange Channel section (measured at the
-        point equidistant from the face of the web to the edge of the flange)
-    :param float t_w: Web thickness of the Tapered Flange Channel section
-    :param float r_r: Root radius of the Tapered Flange Channel section
-    :param float r_f: Flange radius of the Tapered Flange Channel section
-    :param float alpha: Flange angle of the Tapered Flange Channel section (degrees)
-    :param int n_r: Number of points discretising the radii
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a Tapered Flange Channel section with a depth of 10, a width of
-    3.5, a mid-flange thickness of 0.575, a web thickness of 0.475, a root radius of 0.575, a
-    flange radius of 0.4 and a flange angle of 8°, using 16 points to discretise the radii. A mesh
-    is generated with a maximum triangular area of 0.02::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.tapered_flange_channel(
-            d=10, b=3.5, t_f=0.575, t_w=0.475, r_r=0.575, r_f=0.4, alpha=8, n_r=16
-        )
-        geometry.create_mesh(mesh_sizes=[0.02])
-
-    ..  figure:: ../images/sections/taperedchannel_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Tapered flange channel geometry.
-
-    ..  figure:: ../images/sections/taperedchannel_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points = []
-
-    # calculate alpha in radians
-    alpha_rad = np.pi * alpha / 180
-
-    # calculate the height of the flange toe and dimensions of the straight
-    x1 = b * 0.5 - t_w * 0.5 - r_f * (1 - np.sin(alpha_rad))
-    y1 = x1 * np.tan(alpha_rad)
-    x2 = b * 0.5 - t_w * 0.5 - r_r * (1 - np.sin(alpha_rad))
-    y2 = x2 * np.tan(alpha_rad)
-    y_t = t_f - y1 - r_f * np.cos(alpha_rad)
-
-    # add first two points
-    points.append([0, 0])
-    points.append([b, 0])
-
-    # construct the bottom right flange toe radius
-    if r_f == 0:
-        points.append([b, y_t])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-
-            # calculate the locations of the radius points
-            x = b - r_f + r_f * np.cos(theta)
-            y = y_t + r_f * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the bottom right root radius
-    if r_r == 0:
-        points.append([t_w, t_f + y2])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = (3.0 / 2 * np.pi - alpha_rad) - (
-                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-            )
-
-            # calculate the locations of the radius points
-            x = t_w + r_r + r_r * np.cos(theta)
-            y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the top right root radius
-    if r_r == 0:
-        points.append([t_w, d - t_f - y2])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-
-            # calculate the locations of the radius points
-            x = t_w + r_r + r_r * np.cos(theta)
-            y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # construct the top right flange toe radius
-    if r_f == 0:
-        points.append([b, d - y_t])
-    else:
-        for i in range(n_r):
-            # determine polar angle
-            theta = (3.0 * np.pi / 2 + alpha_rad) + (
-                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
-            )
-
-            # calculate the locations of the radius points
-            x = b - r_f + r_f * np.cos(theta)
-            y = d - y_t + r_f * np.sin(theta)
-
-            # append the current points to the points list
-            points.append([x, y])
-
-    # add the final two points
-    points.append([b, d])
-    points.append([0, d])
-
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-def tee_section(
-    d, b, t_f, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a Tee section with the top left corner at *(0, d)*, with depth *d*, width *b*,
-    flange thickness *t_f*, web thickness *t_w* and root radius *r*, using *n_r* points to
-    construct the root radius.
-
-    :param float d: Depth of the Tee section
-    :param float b: Width of the Tee section
-    :param float t_f: Flange thickness of the Tee section
-    :param float t_w: Web thickness of the Tee section
-    :param float r: Root radius of the Tee section
-    :param int n_r: Number of points discretising the root radius
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a Tee section with a depth of 200, a width of 100, a flange
-    thickness of 12, a web thickness of 6 and a root radius of 8, using 8 points to discretise the
-    root radius. A mesh is generated with a maximum triangular area of 3.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.tee_section(d=200, b=100, t_f=12, t_w=6, r=8, n_r=8)
-        geometry.create_mesh(mesh_sizes=[3.0])
-
-    ..  figure:: ../images/sections/tee_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Tee section geometry.
-
-    ..  figure:: ../images/sections/tee_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    points = []
-    # add first two points
-    points.append([b * 0.5 - t_w * 0.5, 0])
-    points.append([b * 0.5 + t_w * 0.5, 0])
-
-    # construct the top right radius
-    pt = [b * 0.5 + t_w * 0.5 + r, d - t_f - r]
-    points += draw_radius(pt, r, np.pi, n_r, False)
-
-    # add next four points
-    points.append([b, d - t_f])
-    points.append([b, d])
-    points.append([0, d])
-    points.append([0, d - t_f])
-
-    # construct the top left radius
-    pt = [b * 0.5 - t_w * 0.5 - r, d - t_f - r]
-    points += draw_radius(pt, r, 0.5 * np.pi, n_r, False)
-
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-def angle_section(
-    d, b, t, r_r, r_t, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs an angle section with the bottom left corner at the origin *(0, 0)*, with depth
-    *d*, width *b*, thickness *t*, root radius *r_r* and toe radius *r_t*, using *n_r* points to
-    construct the radii.
-
-    :param float d: Depth of the angle section
-    :param float b: Width of the angle section
-    :param float t: Thickness of the angle section
-    :param float r_r: Root radius of the angle section
-    :param float r_t: Toe radius of the angle section
-    :param int n_r: Number of points discretising the radii
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates an angle section with a depth of 150, a width of 100, a thickness
-    of 8, a root radius of 12 and a toe radius of 5, using 16 points to discretise the radii. A
-    mesh is generated with a maximum triangular area of 2.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.angle_section(d=150, b=100, t=8, r_r=12, r_t=5, n_r=16)
-        geometry.create_mesh(mesh_sizes=[2.0])
-
-    ..  figure:: ../images/sections/angle_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Angle section geometry.
-
-    ..  figure:: ../images/sections/angle_mesh.png
-        :align: center
-        :scale: 75 %
-    """
-    if r_t > t:
-        raise ValueError(
-            "The radius of the toe (r_t) cannot be larger than the toe thickness (t)."
-        )
-
-    points = []
-
-    # add first two points
-    points.append([0, 0])
-    points.append([b, 0])
-
-    # construct the bottom toe radius
-    pt = [b - r_t, t - r_t]
-    points += draw_radius(pt, r_t, 0, n_r)
-
-    # construct the root radius
-    pt = [t + r_r, t + r_r]
-    points += draw_radius(pt, r_r, 1.5 * np.pi, n_r, False)
-
-    # construct the top toe radius
-    pt = [t - r_t, d - r_t]
-    points += draw_radius(pt, r_t, 0, n_r)
-
-    # add the next point
-    points.append([0, d])
-
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-def cee_section(
-    d, b, l, t, r_out, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a Cee section (typical of cold-formed steel) with the bottom left corner at the
-    origin *(0, 0)*, with depth *d*, width *b*, lip *l*, thickness *t* and outer radius *r_out*,
-    using *n_r* points to construct the radius. If the outer radius is less than the thickness
-    of the Cee Section, the inner radius is set to zero.
-
-    :param float d: Depth of the Cee section
-    :param float b: Width of the Cee section
-    :param float l: Lip of the Cee section
-    :param float t: Thickness of the Cee section
-    :param float r_out: Outer radius of the Cee section
-    :param int n_r: Number of points discretising the outer radius
-    :raises Exception: Lip length must be greater than the outer radius
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a Cee section with a depth of 125, a width of 50, a lip of 30, a
-    thickness of 1.5 and an outer radius of 6, using 8 points to discretise the radius. A mesh is
-    generated with a maximum triangular area of 0.25::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.cee_section(d=125, b=50, l=30, t=1.5, r_out=6, n_r=8)
-        geometry.create_mesh(mesh_sizes=[0.25])
-
-    ..  figure:: ../images/sections/cee_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Cee section geometry.
-
-    ..  figure:: ../images/sections/cee_mesh.png
-        :align: center
-        :scale: 75 %
-    """
-    # ensure the lip length is greater than the outer radius
-    if l < r_out:
-        raise Exception("Lip length must be greater than the outer radius")
-
-    points = []
-
-    # calculate internal radius
-    r_in = max(r_out - t, 0)
-
-    # construct the outer bottom left radius
-    points += draw_radius([r_out, r_out], r_out, np.pi, n_r)
-
-    # construct the outer bottom right radius
-    points += draw_radius([b - r_out, r_out], r_out, 1.5 * np.pi, n_r)
-
-    if r_out != l:
-        # add next two points
-        points.append([b, l])
-        points.append([b - t, l])
-
-    # construct the inner bottom right radius
-    points += draw_radius([b - t - r_in, t + r_in], r_in, 0, n_r, False)
-
-    # construct the inner bottom left radius
-    points += draw_radius([t + r_in, t + r_in], r_in, 1.5 * np.pi, n_r, False)
-
-    # construct the inner top left radius
-    points += draw_radius([t + r_in, d - t - r_in], r_in, np.pi, n_r, False)
-
-    # construct the inner top right radius
-    points += draw_radius([b - t - r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r, False)
-
-    if r_out != l:
-        # add next two points
-        points.append([b - t, d - l])
-        points.append([b, d - l])
-
-    # construct the outer top right radius
-    points += draw_radius([b - r_out, d - r_out], r_out, 0, n_r)
-
-    # construct the outer top left radius
-    points += draw_radius([r_out, d - r_out], r_out, 0.5 * np.pi, n_r)
-
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-def zed_section(
-    d, b_l, b_r, l, t, r_out, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a zed section with the bottom left corner at the origin *(0, 0)*, with depth *d*,
-    left flange width *b_l*, right flange width *b_r*, lip *l*, thickness *t* and outer radius
-    *r_out*, using *n_r* points to construct the radius. If the outer radius is less than the
-    thickness of the Zed Section, the inner radius is set to zero.
-
-    :param float d: Depth of the zed section
-    :param float b_l: Left flange width of the Zed section
-    :param float b_r: Right flange width of the Zed section
-    :param float l: Lip of the Zed section
-    :param float t: Thickness of the Zed section
-    :param float r_out: Outer radius of the Zed section
-    :param int n_r: Number of points discretising the outer radius
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a zed section with a depth of 100, a left flange width of 40, a
-    right flange width of 50, a lip of 20, a thickness of 1.2 and an outer radius of 5, using 8
-    points to discretise the radius. A mesh is generated with a maximum triangular area of 0.15::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.zed_section(d=100, b_l=40, b_r=50, l=20, t=1.2, r_out=5, n_r=8)
-        geometry.create_mesh(mesh_sizes=[0.15])
-
-    ..  figure:: ../images/sections/zed_geometry.png
-        :align: center
-        :scale: 75 %
-
-        zed section geometry.
-
-    ..  figure:: ../images/sections/zed_mesh.png
-        :align: center
-        :scale: 75 %
-    """
-    # ensure the lip length is greater than the outer radius
-    if l < r_out:
-        raise Exception("Lip length must be greater than the outer radius")
-
-    points = []
-
-    # calculate internal radius
-    r_in = max(r_out - t, 0)
-
-    # construct the outer bottom left radius
-    points += draw_radius([r_out, r_out], r_out, np.pi, n_r)
-
-    # construct the outer bottom right radius
-    points += draw_radius([b_r - r_out, r_out], r_out, 1.5 * np.pi, n_r)
-
-    if r_out != l:
-        # add next two points
-        points.append([b_r, l])
-        points.append([b_r - t, l])
-
-    # construct the inner bottom right radius
-    points += draw_radius([b_r - t - r_in, t + r_in], r_in, 0, n_r, False)
-
-    # construct the inner bottom left radius
-    points += draw_radius([t + r_in, t + r_in], r_in, 1.5 * np.pi, n_r, False)
-
-    # construct the outer top right radius
-    points += draw_radius([t - r_out, d - r_out], r_out, 0, n_r)
-
-    # construct the outer top left radius
-    points += draw_radius([t - b_l + r_out, d - r_out], r_out, 0.5 * np.pi, n_r)
-
-    if r_out != l:
-        # add the next two points
-        points.append([t - b_l, d - l])
-        points.append([t - b_l + t, d - l])
-
-    # construct the inner top left radius
-    points += draw_radius([2 * t - b_l + r_in, d - t - r_in], r_in, np.pi, n_r, False)
-
-    # construct the inner top right radius
-    points += draw_radius([-r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r, False)
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-zee_section = zed_section  # An alias for our American friends (and friends who use "American English")
-
-
-def cruciform_section(
-    d, b, t, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a cruciform section centered at the origin *(0, 0)*, with depth *d*, width *b*,
-    thickness *t* and root radius *r*, using *n_r* points to construct the root radius.
-
-    :param float d: Depth of the cruciform section
-    :param float b: Width of the cruciform section
-    :param float t: Thickness of the cruciform section
-    :param float r: Root radius of the cruciform section
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-
-    The following example creates a cruciform section with a depth of 250, a width of 175, a
-    thickness of 12 and a root radius of 16, using 16 points to discretise the radius. A mesh is
-    generated with a maximum triangular area of 5.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.cruciform_section(d=250, b=175, t=12, r=16, n_r=16)
-        geometry.create_mesh(mesh_sizes=[5.0])
-
-    ..  figure:: ../images/sections/cruciform_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Cruciform section geometry.
-
-    ..  figure:: ../images/sections/cruciform_mesh.png
-        :align: center
-        :scale: 75 %
-    """
-    points = []
-
-    # add first two points
-    points.append([-t * 0.5, -d * 0.5])
-    points.append([t * 0.5, -d * 0.5])
-
-    # construct the bottom right radius
-    pt = [0.5 * t + r, -0.5 * t - r]
-    points += draw_radius(pt, r, np.pi, n_r, False)
-
-    # add the next two points
-    points.append([0.5 * b, -t * 0.5])
-    points.append([0.5 * b, t * 0.5])
-
-    # construct the top right radius
-    pt = [0.5 * t + r, 0.5 * t + r]
-    points += draw_radius(pt, r, 1.5 * np.pi, n_r, False)
-
-    # add the next two points
-    points.append([t * 0.5, 0.5 * d])
-    points.append([-t * 0.5, 0.5 * d])
-
-    # construct the top left radius
-    pt = [-0.5 * t - r, 0.5 * t + r]
-    points += draw_radius(pt, r, 0, n_r, False)
-
-    # add the next two points
-    points.append([-0.5 * b, t * 0.5])
-    points.append([-0.5 * b, -t * 0.5])
-
-    # construct the bottom left radius
-    pt = [-0.5 * t - r, -0.5 * t - r]
-    points += draw_radius(pt, r, 0.5 * np.pi, n_r, False)
-
-    polygon = Polygon(points)
-    return Geometry(polygon, material)
-
-
-def polygon_hollow_section(
-    d, t, n_sides, r_in=0, n_r=1, rot=0, material: pre.Material = pre.DEFAULT_MATERIAL
-) -> Geometry:
-    """Constructs a regular hollow polygon section centered at *(0, 0)*, with a pitch circle
-    diameter of bounding polygon *d*, thickness *t*, number of sides *n_sides* and an optional
-    inner radius *r_in*, using *n_r* points to construct the inner and outer radii (if radii is
-    specified).
-
-    :param float d: Pitch circle diameter of the outer bounding polygon (i.e. diameter of circle
-        that passes through all vertices of the outer polygon)
-    :param float t: Thickness of the polygon section wall
-    :param float r_in: Inner radius of the polygon corners. By default, if not specified, a polygon
-        with no corner radii is generated.
-    :param int n_r: Number of points discretising the inner and outer radii, ignored if no inner
-        radii is specified
-    :param rot: Initial counterclockwise rotation in degrees. By default bottom face is aligned
-        with x axis.
-    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
-    :raises Exception: Number of sides in polygon must be greater than or equal to 3
-
-    The following example creates an Octagonal section (8 sides) with a diameter of 200, a
-    thickness of 6 and an inner radius of 20, using 12 points to discretise the inner and outer
-    radii. A mesh is generated with a maximum triangular area of 5::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.polygon_hollow_section(d=200, t=6, n_sides=8, r_in=20, n_r=12)
-        geometry.create_mesh(mesh_sizes=[5])
-
-    ..  figure:: ../images/sections/polygon_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Octagonal section geometry.
-
-    ..  figure:: ../images/sections/polygon_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    outer_points = []
-    inner_points = []
-
-    if n_sides < 3:
-        msg = "n_sides required to be greater than 3 for polygon_section()"
-        raise Exception(msg)
-
-    # initial rotation
-    rot = rot * np.pi / 180  # radians
-
-    # determine triangular segment angle
-    alpha = 2 * np.pi / n_sides  # radians
-
-    # determine distance from origin to point perpendicular on face of side
-    a_out = d / 2 * np.cos(alpha / 2)
-    a_in = a_out - t
-
-    # determine side length for outer & inner faces neglecting radii
-    side_length_out = d * np.sin(alpha / 2)
-    side_length_in = a_in / a_out * side_length_out
-
-    # check limit on internal radii, if exceeded then radii merge to circle
-    if r_in > a_in:
-        r_in = a_in
-        circle = True
-    else:
-        circle = False
-
-    # calculate external radius, if r_in is zero, r_out also is zero
-    if r_in == 0:
-        r_out = 0
-        n_r = 1
-    else:
-        r_out = r_in + t
-
-    # equivalent side length of half the corner radii triangular segment
-    c_out = r_out * (side_length_out / 2) / a_out
-    c_in = r_in * (side_length_in / 2) / a_in
-
-    # determine straight side length between corner radii (if present)
-    side_length_straight_out = side_length_out - (2 * c_out)
-    side_length_straight_in = side_length_in - (2 * c_in)
-
-    # temp list for repeating geometry
-    outer_base_points = []
-    inner_base_points = []
-
-    # start at bottom face, constructing one corner radii, then rotate by initial rotation +
-    # alpha and repeat for n_side number of times to form full section perimeter
-
-    # construct the first radius (bottom right)
-    for i in range(n_r):
-        # determine polar angle
-        theta = 1 / 2 * np.pi + i * 1.0 / max(1, n_r - 1) * alpha
-
-        # calculate location of inner and outer points
-        x_outer = side_length_straight_out / 2 - r_out * np.cos(theta)
-        y_outer = -a_out + r_out - r_out * np.sin(theta)
-        x_inner = side_length_straight_in / 2 - r_in * np.cos(theta)
-        y_inner = -a_in + r_in - r_in * np.sin(theta)
-
-        # append the current temporary points to the temporary points list
-        outer_base_points.append([x_outer, y_outer])
-        inner_base_points.append([x_inner, y_inner])
-
-    for i in range(n_sides):
-        for point in outer_base_points:
-            point_new = rotate(point, alpha * i + rot)
-            outer_points.append(point_new)
-
-        for point in inner_base_points:
-            point_new = rotate(point, alpha * i + rot)
-            inner_points.append(point_new)
-
-    outer_polygon = Polygon(outer_points)
-    inner_polygon = Polygon(inner_points)
-    return Geometry(outer_polygon - inner_polygon, material)
-
-
-def rotate(point, angle: float):
-    """
-    Rotate a point counterclockwise by a given angle around origin [0, 0]
-
-    :param list point: Point coordinates to be rotated
-    :param float angle: Angle to rotate point coordinates
-    :return: Coordinates of rotated point
-    :rtype: list[float, float]
-    """
-
-    pt_x, pt_y = point
-
-    c = np.cos(angle)
-    s = np.sin(angle)
-
-    new_x = c * pt_x - s * pt_y
-    new_y = s * pt_x + c * pt_y
-
-    return [new_x, new_y]
-
-
-def box_girder_section(
-    d, b_t, b_b, t_ft, t_fb, t_w, material: pre.Material = pre.DEFAULT_MATERIAL
-):
-    """Constructs a box girder section centered at at *(max(b_t, b_b)/2, d/2)*, with depth *d*, top
-    width *b_t*, bottom width *b_b*, top flange thickness *t_ft*, bottom flange thickness *t_fb*
-    and web thickness *t_w*.
-
-    :param float d: Depth of the Box Girder section
-    :param float b_t: Top width of the Box Girder section
-    :param float b_b: Bottom width of the Box Girder section
-    :param float t_ft: Top flange thickness of the Box Girder section
-    :param float t_fb: Bottom flange thickness of the Box Girder section
-    :param float t_w: Web thickness of the Box Girder section
-
-    The following example creates a Box Girder section with a depth of 1200, a top width of 1200, a
-    bottom width of 400, a top flange thickness of 16, a bottom flange thickness of 12 and a web
-    thickness of 8. A mesh is generated with a maximum triangular area of 5.0::
-
-        import sectionproperties.pre.sections as sections
-
-        geometry = sections.box_girder_section(d=1200, b_t=1200, b_b=400, t_ft=100, t_fb=80, t_w=50)
-        geometry.create_mesh(mesh_sizes=[200.0])
-
-    ..  figure:: ../images/sections/box_girder_geometry.png
-        :align: center
-        :scale: 75 %
-
-        Box Girder geometry.
-
-    ..  figure:: ../images/sections/box_girder_mesh.png
-        :align: center
-        :scale: 75 %
-
-        Mesh generated from the above geometry.
-    """
-    outer_points = []
-    inner_points = []
-
-    # calculate central axis
-    x_c = max(b_t, b_b) * 0.5
-
-    # determine side wall angle
-    if b_t < b_b:
-        phi_b = np.arctan2(d, 0.5 * (b_b - b_t))
-        phi_t = np.pi - phi_b
-    else:
-        phi_t = np.arctan2(d, 0.5 * (b_t - b_b))
-        phi_b = np.pi - phi_t
-
-    # determine inner wall x-offsets
-    x_bot = t_fb / np.tan(np.pi - phi_b)
-    x_top = t_ft / np.tan(np.pi - phi_t)
-    web_x = abs(t_w / np.sin(np.pi - phi_b))
-
-    # add outer points
-    outer_points.append([x_c - 0.5 * b_b, 0])
-    outer_points.append([x_c + 0.5 * b_b, 0])
-    outer_points.append([x_c + 0.5 * b_t, d])
-    outer_points.append([x_c - 0.5 * b_t, d])
-
-    # add inner points
-    inner_points.append([x_c - 0.5 * b_b - x_bot + web_x, t_fb])
-    inner_points.append([x_c + 0.5 * b_b + x_bot - web_x, t_fb])
-    inner_points.append([x_c + 0.5 * b_t + x_top - web_x, d - t_ft])
-    inner_points.append([x_c - 0.5 * b_t - x_top + web_x, d - t_ft])
-
-    outer_polygon = Polygon(outer_points)
-    inner_polygon = Polygon(inner_points)
-
-    return Geometry(outer_polygon - inner_polygon, material)
diff --git a/sectionproperties/pre/library/bridge_sections.py b/sectionproperties/pre/library/bridge_sections.py
new file mode 100644
index 00000000..58b992a4
--- /dev/null
+++ b/sectionproperties/pre/library/bridge_sections.py
@@ -0,0 +1,1 @@
+# to be completed by @ccaprani
diff --git a/sectionproperties/pre/library/concrete_sections.py b/sectionproperties/pre/library/concrete_sections.py
new file mode 100644
index 00000000..1f95a17f
--- /dev/null
+++ b/sectionproperties/pre/library/concrete_sections.py
@@ -0,0 +1,234 @@
+import numpy as np
+from shapely.geometry import Polygon
+import sectionproperties.pre.pre as pre
+from sectionproperties.pre.geometry import Geometry
+import sectionproperties.pre.library.standard_sections as standard_sections
+
+
+def concrete_rectangular_section(
+    b: float,
+    d: float,
+    dia: float,
+    n_bar: int,
+    n_circle: int,
+    cover: float,
+    conc_mat: pre.Material = pre.DEFAULT_MATERIAL,
+    steel_mat: pre.Material = pre.DEFAULT_MATERIAL,
+) -> Geometry:
+    """Constructs a concrete rectangular section of width *b* and depth *d*, with *n_bar* steel bars
+    of diameter *dia*, discretised with *n_circle* points with equal side and bottom *cover* to the
+    steel.
+
+    :param float b: Concrete section depth
+    :param float d: Concrete section width
+    :param float dia: Diameter of the steel reinforcing bars
+    :param int n_bar: Number of steel reinforcing bars
+    :param int n_circle: Number of points discretising the steel reinforcing bars
+    :param float cover: Side and bottom cover to the steel reinforcing bars
+    :param Optional[sectionproperties.pre.pre.Material] conc_mat: Material to associate with
+        the concrete
+    :param Optional[sectionproperties.pre.pre.Material] steel_mat: Material to associate with
+        the steel
+
+    :raises ValueErorr: If the number of bars is not greater than or equal to 2
+
+    The following example creates a 600D x 300W concrete beam with 3N20 steel reinforcing bars and
+    30 mm cover::
+
+        from sectionproperties.pre.library.concrete_sections import concrete_rectangular_section
+        from sectionproperties.pre.pre import Material
+
+        concrete = Material(
+            name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32, color='lightgrey'
+        )
+        steel = Material(
+            name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500, color='grey'
+        )
+
+        geometry = concrete_rectangular_section(
+            b=300, d=600, dia=20, n_bar=3, n_circle=24, cover=30, conc_mat=concrete, steel_mat=steel
+        )
+        geometry.create_mesh(mesh_sizes=[500])
+
+    ..  figure:: ../images/sections/concrete_rectangular_section_geometry.png
+        :align: center
+        :scale: 50 %
+
+        Concrete rectangular section geometry.
+
+    ..  figure:: ../images/sections/concrete_rectangular_section_mesh.png
+        :align: center
+        :scale: 50 %
+
+        Mesh generated from the above geometry.
+    """
+
+    if n_bar < 2:
+        raise ValueError("Please provide 2 or more steel reinforcing bars.")
+
+    geom = standard_sections.rectangular_section(b=b, d=d, material=conc_mat)
+
+    x_i = cover + dia / 2
+    spacing = (b - 2 * cover - dia) / (n_bar - 1)
+
+    for i in range(n_bar):
+        bar = standard_sections.circular_section(d=dia, n=n_circle, material=steel_mat)
+        geom += bar.shift_section(x_offset=x_i + spacing * i, y_offset=cover + dia / 2)
+
+    return geom
+
+
+def concrete_tee_section(
+    b: float,
+    d: float,
+    b_f: float,
+    d_f: float,
+    dia: float,
+    n_bar: int,
+    n_circle: int,
+    cover: float,
+    conc_mat: pre.Material = pre.DEFAULT_MATERIAL,
+    steel_mat: pre.Material = pre.DEFAULT_MATERIAL,
+) -> Geometry:
+    """Constructs a concrete tee section of width *b*, depth *d*, flange width *b_f* and flange
+    depth *d_f* with *n_bar* steel bars of diameter *dia*, discretised with *n_circle* points with
+    equal side and bottom *cover* to the steel.
+
+    :param float b: Concrete section depth
+    :param float d: Concrete section width
+    :param float b_f: Concrete section flange depth
+    :param float d_f: Concrete section flange width
+    :param float dia: Diameter of the steel reinforcing bars
+    :param int n_bar: Number of steel reinforcing bars
+    :param int n_circle: Number of points discretising the steel reinforcing bars
+    :param float cover: Side and bottom cover to the steel reinforcing bars
+    :param Optional[sectionproperties.pre.pre.Material] conc_mat: Material to associate with
+        the concrete
+    :param Optional[sectionproperties.pre.pre.Material] steel_mat: Material to associate with
+        the steel
+
+    :raises ValueErorr: If the number of bars is not greater than or equal to 2
+
+    The following example creates a 900D x 450W concrete beam with a 1200W x 250D flange, with 5N24
+    steel reinforcing bars and 30 mm cover::
+
+        from sectionproperties.pre.library.concrete_sections import concrete_tee_section
+        from sectionproperties.pre.pre import Material
+
+        concrete = Material(
+            name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32, color='lightgrey'
+        )
+        steel = Material(
+            name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500, color='grey'
+        )
+
+        geometry = concrete_tee_section(
+            b=450, d=900, b_f=1200, d_f=250, dia=24, n_bar=5, n_circle=24, cover=30,
+            conc_mat=concrete, steel_mat=steel
+        )
+        geometry.create_mesh(mesh_sizes=[500])
+
+    ..  figure:: ../images/sections/concrete_tee_section_geometry.png
+        :align: center
+        :scale: 50 %
+
+        Concrete tee section geometry.
+
+    ..  figure:: ../images/sections/concrete_tee_section_mesh.png
+        :align: center
+        :scale: 50 %
+
+        Mesh generated from the above geometry.
+    """
+
+    if n_bar < 2:
+        raise ValueError("Please provide 2 or more steel reinforcing bars.")
+
+    geom = standard_sections.rectangular_section(b=b, d=d - d_f, material=conc_mat)
+    flange = standard_sections.rectangular_section(b=b_f, d=d_f, material=conc_mat)
+    geom += flange.align_center(align_to=geom).align_to(other=geom, on="top")
+    # geom += flange.align_center(align_to=geom)
+
+    x_i = cover + dia / 2
+    spacing = (b - 2 * cover - dia) / (n_bar - 1)
+
+    for i in range(n_bar):
+        bar = standard_sections.circular_section(d=dia, n=n_circle, material=steel_mat)
+        geom += bar.shift_section(x_offset=x_i + spacing * i, y_offset=cover + dia / 2)
+
+    return geom
+
+
+def concrete_circular_section(
+    d: float,
+    n: int,
+    dia: float,
+    n_bar: int,
+    n_circle: int,
+    cover: float,
+    conc_mat: pre.Material = pre.DEFAULT_MATERIAL,
+    steel_mat: pre.Material = pre.DEFAULT_MATERIAL,
+) -> Geometry:
+    """Constructs a concrete circular section of diameter *d* discretised with *n* points, with
+    *n_bar* steel bars of diameter *dia*, discretised with *n_circle* points with equal side and
+    bottom *cover* to the steel.
+
+    :param float d: Concrete diameter
+    :param float n: Number of points discretising the concrete section
+    :param float dia: Diameter of the steel reinforcing bars
+    :param int n_bar: Number of steel reinforcing bars
+    :param int n_circle: Number of points discretising the steel reinforcing bars
+    :param float cover: Side and bottom cover to the steel reinforcing bars
+    :param Optional[sectionproperties.pre.pre.Material] conc_mat: Material to associate with
+        the concrete
+    :param Optional[sectionproperties.pre.pre.Material] steel_mat: Material to associate with
+        the steel
+
+    :raises ValueErorr: If the number of bars is not greater than or equal to 2
+
+    The following example creates a 450DIA concrete column with with 6N20 steel reinforcing bars
+    and 45 mm cover::
+
+        from sectionproperties.pre.library.concrete_sections import concrete_circular_section
+        from sectionproperties.pre.pre import Material
+
+        concrete = Material(
+            name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32, color='lightgrey'
+        )
+        steel = Material(
+            name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500, color='grey'
+        )
+
+        geometry = concrete_circular_section(
+            d=450, n=64, dia=20, n_bar=6, n_circle=24, cover=45, conc_mat=concrete, steel_mat=steel
+        )
+        geometry.create_mesh(mesh_sizes=[500])
+
+    ..  figure:: ../images/sections/concrete_circular_section_geometry.png
+        :align: center
+        :scale: 50 %
+
+        Concrete circular section geometry.
+
+    ..  figure:: ../images/sections/concrete_circular_section_mesh.png
+        :align: center
+        :scale: 50 %
+
+        Mesh generated from the above geometry.
+    """
+
+    if n_bar < 2:
+        raise ValueError("Please provide 2 or more steel reinforcing bars.")
+
+    geom = standard_sections.circular_section(d=d, n=n, material=conc_mat)
+
+    r = d / 2 - cover - dia / 2
+    d_theta = 2 * np.pi / n_bar
+
+    for i in range(n_bar):
+        bar = standard_sections.circular_section(d=dia, n=n_circle, material=steel_mat)
+        geom += bar.shift_section(
+            x_offset=r * np.cos(i * d_theta), y_offset=r * np.sin(i * d_theta)
+        )
+
+    return geom
diff --git a/sectionproperties/pre/nastran_sections.py b/sectionproperties/pre/library/nastran_sections.py
similarity index 92%
rename from sectionproperties/pre/nastran_sections.py
rename to sectionproperties/pre/library/nastran_sections.py
index 023e362a..198a13b9 100644
--- a/sectionproperties/pre/nastran_sections.py
+++ b/sectionproperties/pre/library/nastran_sections.py
@@ -1,8 +1,8 @@
 import numpy as np
 from shapely.geometry import Polygon
-from sectionproperties.pre.sections import Geometry, CompoundGeometry
-from sectionproperties.pre import pre
-from sectionproperties.pre.sections import draw_radius
+from sectionproperties.pre.geometry import Geometry
+import sectionproperties.pre.pre as pre
+from sectionproperties.pre.library.utils import draw_radius
 
 
 def nastran_bar(
@@ -19,9 +19,9 @@ def nastran_bar(
     The following example creates a BAR cross-section with a depth of 1.5 and width of 2.0, and
     generates a mesh with a maximum triangular area of 0.001::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_bar
 
-        geometry = nsections.nastran_bar(DIM1=2.0, DIM2=1.5)
+        geometry = nastran_bar(DIM1=2.0, DIM2=1.5)
         mesh = geometry.create_mesh(mesh_sizes=[0.001])
 
     ..  figure:: ../images/sections/bar_geometry.png
@@ -71,9 +71,9 @@ def nastran_box(
     The following example creates a BOX cross-section with a depth of 3.0 and width of 4.0, and
     generates a mesh with a maximum triangular area of 0.001::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_box
 
-        geometry = nsections.nastran_box(DIM1=4.0, DIM2=3.0, DIM3=0.375, DIM4=0.5)
+        geometry = nastran_box(DIM1=4.0, DIM2=3.0, DIM3=0.375, DIM4=0.5)
         mesh = geometry.create_mesh(mesh_sizes=[0.001])
 
     ..  figure:: ../images/sections/box_geometry.png
@@ -91,23 +91,30 @@ def nastran_box(
     # Ensure dimensions are physically relevant
     np.testing.assert_(2.0 * DIM4 < DIM1, "Invalid geometry specified.")
     np.testing.assert_(2.0 * DIM3 < DIM2, "Invalid geometry specified.")
-
-    points = [
+    points_outer = [
         [-0.5 * DIM1, -0.5 * DIM2],
         [0.5 * DIM1, -0.5 * DIM2],
         [0.5 * DIM1, 0.5 * DIM2],
         [-0.5 * DIM1, 0.5 * DIM2],
+    ]
+    points_inner = [
         [-0.5 * DIM1 + DIM4, -0.5 * DIM2 + DIM3],
         [0.5 * DIM1 - DIM4, -0.5 * DIM2 + DIM3],
         [0.5 * DIM1 - DIM4, 0.5 * DIM2 - DIM3],
         [-0.5 * DIM1 + DIM4, 0.5 * DIM2 - DIM3],
     ]
-    geometry = Geometry(Polygon(points), material)
+
+    inner_box = Polygon(points_inner)
+    outer_box = Polygon(points_outer)
+
     C = (0.5 * DIM1, 0.5 * DIM2)
     D = (0.5 * DIM1, -0.5 * DIM2)
     E = (-0.5 * DIM1, -0.5 * DIM2)
     F = (-0.5 * DIM1, 0.5 * DIM2)
+
+    geometry = Geometry(outer_box - inner_box, material)
     geometry.recovery_points = [C, D, E, F]
+
     return geometry
 
 
@@ -135,9 +142,9 @@ def nastran_box1(
     The following example creates a BOX1 cross-section with a depth of 3.0 and width of 4.0, and
     generates a mesh with a maximum triangular area of 0.007::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_box1
 
-        geometry = nsections.nastran_box1(
+        geometry = nastran_box1(
             DIM1=4.0, DIM2=3.0, DIM3=0.375, DIM4=0.5, DIM5=0.25, DIM6=0.75
         )
         mesh = geometry.create_mesh(mesh_sizes=[0.007])
@@ -200,9 +207,9 @@ def nastran_chan(
     The following example creates a CHAN cross-section with a depth of 4.0 and width of 2.0, and
     generates a mesh with a maximum triangular area of 0.008::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_chan
 
-        geometry = nsections.nastran_chan(DIM1=2.0, DIM2=4.0, DIM3=0.25, DIM4=0.5)
+        geometry = nastran_chan(DIM1=2.0, DIM2=4.0, DIM3=0.25, DIM4=0.5)
         mesh = geometry.create_mesh(mesh_sizes=[0.008])
 
     ..  figure:: ../images/sections/chan_geometry.png
@@ -264,9 +271,9 @@ def nastran_chan1(
     The following example creates a CHAN1 cross-section with a depth of 4.0 and width of 1.75, and
     generates a mesh with a maximum triangular area of 0.01::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_chan1
 
-        geometry = nsections.nastran_chan1(DIM1=0.75, DIM2=1.0, DIM3=3.5, DIM4=4.0)
+        geometry = nastran_chan1(DIM1=0.75, DIM2=1.0, DIM3=3.5, DIM4=4.0)
         mesh = geometry.create_mesh(mesh_sizes=[0.01])
 
     ..  figure:: ../images/sections/chan1_geometry.png
@@ -326,9 +333,9 @@ def nastran_chan2(
     The following example creates a CHAN2 cross-section with a depth of 2.0 and width of 4.0, and
     generates a mesh with a maximum triangular area of 0.01::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_chan2
 
-        geometry = nsections.nastran_chan2(DIM1=0.375, DIM2=0.5, DIM3=2.0, DIM4=4.0)
+        geometry = nastran_chan2(DIM1=0.375, DIM2=0.5, DIM3=2.0, DIM4=4.0)
         mesh = geometry.create_mesh(mesh_sizes=[0.01])
 
     ..  figure:: ../images/sections/chan2_geometry.png
@@ -389,9 +396,9 @@ def nastran_cross(
     The following example creates a rectangular cross-section with a depth of 3.0 and width of
     1.875, and generates a mesh with a maximum triangular area of 0.008::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_cross
 
-        geometry = nsections.nastran_cross(DIM1=1.5, DIM2=0.375, DIM3=3.0, DIM4=0.25)
+        geometry = nastran_cross(DIM1=1.5, DIM2=0.375, DIM3=3.0, DIM4=0.25)
         mesh = geometry.create_mesh(mesh_sizes=[0.008])
 
     ..  figure:: ../images/sections/cross_geometry.png
@@ -460,9 +467,9 @@ def nastran_fcross(
 
     The following example demonstrates the creation of a flanged cross section::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_fcross
 
-        geometry = nsections.nastran_fcross(
+        geometry = nastran_fcross(
             DIM1=9.0, DIM2=6.0, DIM3=0.75, DIM4=0.625, DIM5=2.1, DIM6=0.375, DIM7=4.5, DIM8=0.564
         )
         mesh = geometry.create_mesh(mesh_sizes=[0.03])
@@ -560,9 +567,9 @@ def nastran_dbox(
     The following example creates a DBOX cross-section with a depth of 3.0 and width of 8.0, and
     generates a mesh with a maximum triangular area of 0.01::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_dbox
 
-        geometry = nsections.nastran_dbox(
+        geometry = nastran_dbox(
             DIM1=8.0, DIM2=3.0, DIM3=3.0, DIM4=0.5, DIM5=0.625, DIM6=0.75, DIM7=0.375, DIM8=0.25,
             DIM9=0.5, DIM10=0.375
         )
@@ -641,9 +648,9 @@ def nastran_gbox(
     The following example creates a GBOX cross-section with a depth of 2.5 and width of 6.0, and
     generates a mesh with a maximum triangular area of 0.01::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_gbox
 
-        geometry = nsections.nastran_gbox(
+        geometry = nastran_gbox(
             DIM1=6.0, DIM2=2.5, DIM3=0.375, DIM4=0.25, DIM5=0.625, DIM6=1.0
         )
         mesh = geometry.create_mesh(mesh_sizes=[0.01])
@@ -717,9 +724,9 @@ def nastran_h(
     The following example creates a H cross-section with a depth of 3.5 and width of 2.75, and
     generates a mesh with a maximum triangular area of 0.005::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_h
 
-        geometry = nsections.nastran_h(DIM1=2.0, DIM2=0.75, DIM3=3.5, DIM4=0.25)
+        geometry = nastran_h(DIM1=2.0, DIM2=0.75, DIM3=3.5, DIM4=0.25)
         mesh = geometry.create_mesh(mesh_sizes=[0.005])
 
     ..  figure:: ../images/sections/h_geometry.png
@@ -784,9 +791,9 @@ def nastran_hat(
     The following example creates a HAT cross-section with a depth of 1.25 and width of 2.5, and
     generates a mesh with a maximum triangular area of 0.001::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_hat
 
-        geometry = nsections.nastran_hat(DIM1=1.25, DIM2=0.25, DIM3=1.5, DIM4=0.5)
+        geometry = nastran_hat(DIM1=1.25, DIM2=0.25, DIM3=1.5, DIM4=0.5)
         mesh = geometry.create_mesh(mesh_sizes=[0.001])
 
     ..  figure:: ../images/sections/hat_geometry.png
@@ -852,9 +859,9 @@ def nastran_hat1(
     The following example creates a HAT1 cross-section with a depth of 2.0 and width of 4.0, and
     generates a mesh with a maximum triangular area of 0.005::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_hat1
 
-        geometry = nsections.nastran_hat1(DIM1=4.0, DIM2=2.0, DIM3=1.5, DIM4=0.1875, DIM5=0.375)
+        geometry = nastran_hat1(DIM1=4.0, DIM2=2.0, DIM3=1.5, DIM4=0.1875, DIM5=0.375)
         mesh = geometry.create_mesh(mesh_sizes=[0.005])
 
     ..  figure:: ../images/sections/hat1_geometry.png
@@ -914,9 +921,9 @@ def nastran_hexa(
     The following example creates a rectangular cross-section with a depth of 1.5 and width of 2.0,
     and generates a mesh with a maximum triangular area of 0.005::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_hexa
 
-        geometry = nsections.nastran_hexa(DIM1=0.5, DIM2=2.0, DIM3=1.5)
+        geometry = nastran_hexa(DIM1=0.5, DIM2=2.0, DIM3=1.5)
         mesh = geometry.create_mesh(mesh_sizes=[0.005])
 
     ..  figure:: ../images/sections/hexa_geometry.png
@@ -978,9 +985,9 @@ def nastran_i(
     The following example creates a Nastran I cross-section with a depth of 5.0, and generates a
     mesh with a maximum triangular area of 0.008::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_i
 
-        geometry = nsections.nastran_i(
+        geometry = nastran_i(
             DIM1=5.0, DIM2=2.0, DIM3=3.0, DIM4=0.25, DIM5=0.375, DIM6=0.5
         )
         mesh = geometry.create_mesh(mesh_sizes=[0.008])
@@ -1051,9 +1058,9 @@ def nastran_i1(
     5.0 and width of 1.75, and generates a mesh with a maximum triangular area of
     0.02::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_i1
 
-        geometry = nsections.nastran_i1(DIM1=1.0, DIM2=0.75, DIM3=4.0, DIM4=5.0)
+        geometry = nastran_i1(DIM1=1.0, DIM2=0.75, DIM3=4.0, DIM4=5.0)
         mesh = geometry.create_mesh(mesh_sizes=[0.02])
 
     ..  figure:: ../images/sections/i1_geometry.png
@@ -1118,9 +1125,9 @@ def nastran_l(
     The following example creates a L cross-section with a depth of 6.0 and width of 3.0, and
     generates a mesh with a maximum triangular area of 0.01::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_l
 
-        geometry = nsections.nastran_l(DIM1=3.0, DIM2=6.0, DIM3=0.375, DIM4=0.625)
+        geometry = nastran_l(DIM1=3.0, DIM2=6.0, DIM3=0.375, DIM4=0.625)
         mesh = geometry.create_mesh(mesh_sizes=[0.01])
 
     ..  figure:: ../images/sections/l_geometry.png
@@ -1149,7 +1156,7 @@ def nastran_l(
     E = (-0.5 * DIM4, -0.5 * DIM3)
     F = (-0.5 * DIM4, DIM2 - 0.5 * DIM3)
 
-    geometry.recovery_points([C, D, E, F])
+    geometry.recovery_points = [C, D, E, F]
     return geometry
 
 
@@ -1167,9 +1174,9 @@ def nastran_rod(
     The following example creates a circular rod with a radius of 3.0 and 50 points discretising
     the boundary, and generates a mesh with a maximum triangular area of 0.01::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_rod
 
-        geometry = nsections.nastran_rod(DIM1=3.0, n=50)
+        geometry = nastran_rod(DIM1=3.0, n=50)
         mesh = geometry.create_mesh(mesh_sizes=[0.01])
 
     ..  figure:: ../images/sections/rod_geometry.png
@@ -1205,7 +1212,7 @@ def nastran_rod(
     E = (0, -DIM1)
     F = (-DIM1, 0)
 
-    geometry.recovery_points([C, D, E, F])
+    geometry.recovery_points = [C, D, E, F]
 
     return geometry
 
@@ -1230,9 +1237,9 @@ def nastran_tee(
     The following example creates a T cross-section with a depth of 4.0 and width of 3.0, and
     generates a mesh with a maximum triangular area of 0.001::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_tee
 
-        geometry = nsections.nastran_t(DIM1=3.0, DIM2=4.0, DIM3=0.375, DIM4=0.25)
+        geometry = nastran_tee(DIM1=3.0, DIM2=4.0, DIM3=0.375, DIM4=0.25)
         mesh = geometry.create_mesh(mesh_sizes=[0.001])
 
     ..  figure:: ../images/sections/t_geometry.png
@@ -1309,9 +1316,9 @@ def nastran_tee1(
     The following example creates a T1 cross-section with a depth of 3.0 and width of 3.875, and
     generates a mesh with a maximum triangular area of 0.001::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_tee1
 
-        geometry = nsections.nastran_t1(DIM1=3.0, DIM2=3.5, DIM3=0.375, DIM4=0.25)
+        geometry = nastran_tee1(DIM1=3.0, DIM2=3.5, DIM3=0.375, DIM4=0.25)
         mesh = geometry.create_mesh(mesh_sizes=[0.001])
 
     ..  figure:: ../images/sections/t1_geometry.png
@@ -1373,9 +1380,9 @@ def nastran_tee2(
     The following example creates a T2 cross-section with a depth of 4.0 and width of 3.0, and
     generates a mesh with a maximum triangular area of 0.005::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_tee2
 
-        geometry = nsections.nastran_t2(DIM1=3.0, DIM2=4.0, DIM3=0.375, DIM4=0.5)
+        geometry = nastran_tee2(DIM1=3.0, DIM2=4.0, DIM3=0.375, DIM4=0.5)
         mesh = geometry.create_mesh(mesh_sizes=[0.005])
 
     ..  figure:: ../images/sections/t2_geometry.png
@@ -1433,9 +1440,9 @@ def nastran_tube(
     inner radius of 2.5, and generates a mesh with 37 points discretising the boundaries and a
     maximum triangular area of 0.01::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_tube
 
-        geometry = nsections.nastran_tube(DIM1=3.0, DIM2=2.5, n=37)
+        geometry = nastran_tube(DIM1=3.0, DIM2=2.5, n=37)
         mesh = geometry.create_mesh(mesh_sizes=[0.01])
 
     ..  figure:: ../images/sections/tube_geometry.png
@@ -1501,9 +1508,9 @@ def nastran_tube2(
     wall thickness of 0.5, and generates a mesh with 37 point discretising the boundary and a
     maximum triangular area of 0.01::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_tube2
 
-        geometry = nsections.nastran_tube2(DIM1=3.0, DIM2=0.5, n=37)
+        geometry = nastran_tube2(DIM1=3.0, DIM2=0.5, n=37)
         mesh = geometry.create_mesh(mesh_sizes=[0.01])
 
     ..  figure:: ../images/sections/tube2_geometry.png
@@ -1542,16 +1549,16 @@ def nastran_tube2(
         points_outer.append([x_outer, y_outer])
         points_inner.append([x_inner, y_inner])
 
-        exterior = Geometry(Polygon(points_outer), material)
-        interior = Geometry(Polygon(points_inner), material)
-        geometry = exterior - interior
+    exterior = Geometry(Polygon(points_outer), material)
+    interior = Geometry(Polygon(points_inner), material)
+    geometry = exterior - interior
 
-        C = (0, DIM1)
-        D = (DIM1, 0)
-        E = (0, -DIM1)
-        F = (-DIM1, 0)
-        geometry.recovery_points = [C, D, E, F]
-        return geometry
+    C = (0, DIM1)
+    D = (DIM1, 0)
+    E = (0, -DIM1)
+    F = (-DIM1, 0)
+    geometry.recovery_points = [C, D, E, F]
+    return geometry
 
 
 def nastran_zed(
@@ -1574,9 +1581,9 @@ def nastran_zed(
     The following example creates a rectangular cross-section with a depth of 4.0 and width of
     2.75, and generates a mesh with a maximum triangular area of 0.005::
 
-        import sectionproperties.pre.nastran_sections as nsections
+        from sectionproperties.pre.library.nastran_sections import nastran_zed
 
-        geometry = nsections.nastran_z(DIM1=1.125, DIM2=0.5, DIM3=3.5, DIM4=4.0)
+        geometry = nastran_zed(DIM1=1.125, DIM2=0.5, DIM3=3.5, DIM4=4.0)
         mesh = geometry.create_mesh(mesh_sizes=[0.005])
 
     ..  figure:: ../images/sections/z_geometry.png
diff --git a/sectionproperties/pre/library/standard_sections.py b/sectionproperties/pre/library/standard_sections.py
new file mode 100644
index 00000000..7058d02b
--- /dev/null
+++ b/sectionproperties/pre/library/standard_sections.py
@@ -0,0 +1,207 @@
+import numpy as np
+from shapely.geometry import Polygon
+from sectionproperties.pre.geometry import Geometry
+import sectionproperties.pre.pre as pre
+from sectionproperties.pre.library.utils import draw_radius
+
+
+def rectangular_section(
+    b, d, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a rectangular section with the bottom left corner at the origin *(0, 0)*, with
+    depth *d* and width *b*.
+
+    :param float d: Depth (y) of the rectangle
+    :param float b: Width (x) of the rectangle
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a rectangular cross-section with a depth of 100 and width of 50,
+    and generates a mesh with a maximum triangular area of 5::
+
+        from sectionproperties.pre.library.standard_sections import rectangular_section
+
+        geometry = rectangular_section(d=100, b=50)
+        geometry.create_mesh(mesh_sizes=[5])
+
+    ..  figure:: ../images/sections/rectangle_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Rectangular section geometry.
+
+    ..  figure:: ../images/sections/rectangle_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points = [[0, 0], [b, 0], [b, d], [0, d]]
+    rectangle = Polygon(points)
+    return Geometry(rectangle, material)
+
+
+def circular_section(
+    d: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a solid circle centered at the origin *(0, 0)* with diameter *d* and using *n*
+    points to construct the circle.
+
+    :param float d: Diameter of the circle
+    :param int n: Number of points discretising the circle
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a circular geometry with a diameter of 50 with 64 points,
+    and generates a mesh with a maximum triangular area of 2.5::
+
+        from sectionproperties.pre.library.standard_sections import circular_section
+
+        geometry = circular_section(d=50, n=64)
+        geometry.create_mesh(mesh_sizes=[2.5])
+
+    ..  figure:: ../images/sections/circle_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Circular section geometry.
+
+    ..  figure:: ../images/sections/circle_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    x_off, y_off = (0, 0)
+    points = []
+    # loop through each point on the circle
+    for i in range(n):
+        # determine polar angle
+        theta = i * 2 * np.pi * 1.0 / n
+
+        # calculate location of the point
+        x = 0.5 * d * np.cos(theta) + x_off
+        y = 0.5 * d * np.sin(theta) + y_off
+
+        # append the current point to the points list
+        points.append([x, y])
+
+    circle = Polygon(points)
+    return Geometry(circle, material)
+
+
+def elliptical_section(
+    d_y: float, d_x: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a solid ellipse centered at the origin *(0, 0)* with vertical diameter *d_y* and
+    horizontal diameter *d_x*, using *n* points to construct the ellipse.
+
+    :param float d_y: Diameter of the ellipse in the y-dimension
+    :param float d_x: Diameter of the ellipse in the x-dimension
+    :param int n: Number of points discretising the ellipse
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates an elliptical cross-section with a vertical diameter of 25 and
+    horizontal diameter of 50, with 40 points, and generates a mesh with a maximum triangular area
+    of 1.0::
+
+        from sectionproperties.pre.library.standard_sections import elliptical_section
+
+        geometry = elliptical_section(d_y=25, d_x=50, n=40)
+        geometry.create_mesh(mesh_sizes=[1.0])
+
+    ..  figure:: ../images/sections/ellipse_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Elliptical section geometry.
+
+    ..  figure:: ../images/sections/ellipse_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points = []
+
+    # loop through each point on the ellipse
+    for i in range(n):
+        # determine polar angle
+        theta = i * 2 * np.pi * 1.0 / n
+
+        # calculate location of the point
+        x = 0.5 * d_x * np.cos(theta)
+        y = 0.5 * d_y * np.sin(theta)
+
+        # append the current point to the points list
+        points.append([x, y])
+
+    ellipse = Polygon(points)
+    return Geometry(ellipse, material)
+
+
+def cruciform_section(
+    d, b, t, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a cruciform section centered at the origin *(0, 0)*, with depth *d*, width *b*,
+    thickness *t* and root radius *r*, using *n_r* points to construct the root radius.
+
+    :param float d: Depth of the cruciform section
+    :param float b: Width of the cruciform section
+    :param float t: Thickness of the cruciform section
+    :param float r: Root radius of the cruciform section
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a cruciform section with a depth of 250, a width of 175, a
+    thickness of 12 and a root radius of 16, using 16 points to discretise the radius. A mesh is
+    generated with a maximum triangular area of 5.0::
+
+        from sectionproperties.pre.library.standard_sections import cruciform_section
+
+        geometry = cruciform_section(d=250, b=175, t=12, r=16, n_r=16)
+        geometry.create_mesh(mesh_sizes=[5.0])
+
+    ..  figure:: ../images/sections/cruciform_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Cruciform section geometry.
+
+    ..  figure:: ../images/sections/cruciform_mesh.png
+        :align: center
+        :scale: 75 %
+    """
+    points = []
+
+    # add first two points
+    points.append([-t * 0.5, -d * 0.5])
+    points.append([t * 0.5, -d * 0.5])
+
+    # construct the bottom right radius
+    pt = [0.5 * t + r, -0.5 * t - r]
+    points += draw_radius(pt, r, np.pi, n_r, False)
+
+    # add the next two points
+    points.append([0.5 * b, -t * 0.5])
+    points.append([0.5 * b, t * 0.5])
+
+    # construct the top right radius
+    pt = [0.5 * t + r, 0.5 * t + r]
+    points += draw_radius(pt, r, 1.5 * np.pi, n_r, False)
+
+    # add the next two points
+    points.append([t * 0.5, 0.5 * d])
+    points.append([-t * 0.5, 0.5 * d])
+
+    # construct the top left radius
+    pt = [-0.5 * t - r, 0.5 * t + r]
+    points += draw_radius(pt, r, 0, n_r, False)
+
+    # add the next two points
+    points.append([-0.5 * b, t * 0.5])
+    points.append([-0.5 * b, -t * 0.5])
+
+    # construct the bottom left radius
+    pt = [-0.5 * t - r, -0.5 * t - r]
+    points += draw_radius(pt, r, 0.5 * np.pi, n_r, False)
+
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
diff --git a/sectionproperties/pre/library/steel_sections.py b/sectionproperties/pre/library/steel_sections.py
new file mode 100644
index 00000000..3c4cd660
--- /dev/null
+++ b/sectionproperties/pre/library/steel_sections.py
@@ -0,0 +1,1203 @@
+import numpy as np
+from shapely.geometry import Polygon
+from sectionproperties.pre.geometry import Geometry
+import sectionproperties.pre.pre as pre
+from sectionproperties.pre.library.utils import draw_radius, rotate
+
+
+def circular_hollow_section(
+    d: float, t: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a circular hollow section (CHS) centered at the origin *(0, 0)*, with diameter *d* and
+    thickness *t*, using *n* points to construct the inner and outer circles.
+
+    :param float d: Outer diameter of the CHS
+    :param float t: Thickness of the CHS
+    :param int n: Number of points discretising the inner and outer circles
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a CHS discretised with 64 points, with a diameter of 48 and
+    thickness of 3.2, and generates a mesh with a maximum triangular area of 1.0::
+
+        from sectionproperties.pre.library.steel_sections import circular_hollow_section
+
+        geometry = circular_hollow_section(d=48, t=3.2, n=64)
+        geometry.create_mesh(mesh_sizes=[1.0])
+
+    ..  figure:: ../images/sections/chs_geometry.png
+        :align: center
+        :scale: 75 %
+
+        CHS geometry.
+
+    ..  figure:: ../images/sections/chs_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points_inner = []
+    points_outer = []
+    # loop through each point of the CHS
+    for i in range(n):
+        # determine polar angle
+        theta = i * 2 * np.pi * 1.0 / n
+
+        # calculate location of outer and inner points
+        x_outer = 0.5 * d * np.cos(theta)
+        y_outer = 0.5 * d * np.sin(theta)
+        x_inner = (0.5 * d - t) * np.cos(theta)
+        y_inner = (0.5 * d - t) * np.sin(theta)
+
+        # append the current points to the points list
+        points_outer.append([x_outer, y_outer])
+        points_inner.append([x_inner, y_inner])
+
+    inner_circle = Polygon(points_inner)
+    outer_circle = Polygon(points_outer)
+    return Geometry(outer_circle - inner_circle, material)
+
+
+def elliptical_hollow_section(
+    d_y: float,
+    d_x: float,
+    t: float,
+    n: int,
+    material: pre.Material = pre.DEFAULT_MATERIAL,
+) -> Geometry:
+    """Constructs an elliptical hollow section (EHS) centered at the origin *(0, 0)*, with outer vertical
+    diameter *d_y*, outer horizontal diameter *d_x*, and thickness *t*, using *n* points to
+    construct the inner and outer ellipses.
+
+    :param float d_y: Diameter of the ellipse in the y-dimension
+    :param float d_x: Diameter of the ellipse in the x-dimension
+    :param float t: Thickness of the EHS
+    :param int n: Number of points discretising the inner and outer ellipses
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a EHS discretised with 30 points, with a outer vertical diameter
+    of 25, outer horizontal diameter of 50, and thickness of 2.0, and generates a mesh with a
+    maximum triangular area of 0.5::
+
+        from sectionproperties.pre.library.steel_sections import elliptical_hollow_section
+
+        geometry = elliptical_hollow_section(d_y=25, d_x=50, t=2.0, n=64)
+        geometry.create_mesh(mesh_sizes=[0.5])
+
+    ..  figure:: ../images/sections/ehs_geometry.png
+        :align: center
+        :scale: 75 %
+
+        EHS geometry.
+
+    ..  figure:: ../images/sections/ehs_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points_inner = []
+    points_outer = []
+    # loop through each point of the EHS
+    for i in range(n):
+        # determine polar angle
+        theta = i * 2 * np.pi * 1.0 / n
+
+        # calculate location of outer and inner points
+        x_outer = 0.5 * d_x * np.cos(theta)
+        y_outer = 0.5 * d_y * np.sin(theta)
+        x_inner = ((0.5 * d_x) - t) * np.cos(theta)
+        y_inner = ((0.5 * d_y) - t) * np.sin(theta)
+
+        # append the current points to the points list
+        points_outer.append([x_outer, y_outer])
+        points_inner.append([x_inner, y_inner])
+
+    outer = Polygon(points_outer)
+    inner = Polygon(points_inner)
+    return Geometry(outer - inner, material)
+
+
+def rectangular_hollow_section(
+    b: float,
+    d: float,
+    t: float,
+    r_out: float,
+    n_r: int,
+    material: pre.Material = pre.DEFAULT_MATERIAL,
+) -> Geometry:
+    """Constructs a rectangular hollow section (RHS) centered at *(b/2, d/2)*, with depth *d*, width *b*,
+    thickness *t* and outer radius *r_out*, using *n_r* points to construct the inner and outer
+    radii. If the outer radius is less than the thickness of the RHS, the inner radius is set to
+    zero.
+
+    :param float d: Depth of the RHS
+    :param float b: Width of the RHS
+    :param float t: Thickness of the RHS
+    :param float r_out: Outer radius of the RHS
+    :param int n_r: Number of points discretising the inner and outer radii
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates an RHS with a depth of 100, a width of 50, a thickness of 6 and
+    an outer radius of 9, using 8 points to discretise the inner and outer radii. A mesh is
+    generated with a maximum triangular area of 2.0::
+
+        from sectionproperties.pre.library.steel_sections import rectangular_hollow_section
+
+        geometry = rectangular_hollow_section(d=100, b=50, t=6, r_out=9, n_r=8)
+        geometry.create_mesh(mesh_sizes=[2.0])
+
+    ..  figure:: ../images/sections/rhs_geometry.png
+        :align: center
+        :scale: 75 %
+
+        RHS geometry.
+
+    ..  figure:: ../images/sections/rhs_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points_inner = []
+    points_outer = []
+    # calculate internal radius
+    r_in = max(r_out - t, 0)
+    # construct the outer radius points
+    points_outer += draw_radius([r_out, r_out], r_out, np.pi, n_r)
+    points_outer += draw_radius([b - r_out, r_out], r_out, 1.5 * np.pi, n_r)
+    points_outer += draw_radius([b - r_out, d - r_out], r_out, 0, n_r)
+    points_outer += draw_radius([r_out, d - r_out], r_out, 0.5 * np.pi, n_r)
+
+    points_inner += draw_radius([t + r_in, t + r_in], r_in, np.pi, n_r)
+    points_inner += draw_radius([b - t - r_in, t + r_in], r_in, 1.5 * np.pi, n_r)
+    points_inner += draw_radius([b - t - r_in, d - t - r_in], r_in, 0, n_r)
+    points_inner += draw_radius([t + r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r)
+
+    outer = Polygon(points_outer)
+    inner = Polygon(points_inner)
+    return Geometry(outer - inner, material)
+
+
+def polygon_hollow_section(
+    d, t, n_sides, r_in=0, n_r=1, rot=0, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a regular hollow polygon section centered at *(0, 0)*, with a pitch circle
+    diameter of bounding polygon *d*, thickness *t*, number of sides *n_sides* and an optional
+    inner radius *r_in*, using *n_r* points to construct the inner and outer radii (if radii is
+    specified).
+
+    :param float d: Pitch circle diameter of the outer bounding polygon (i.e. diameter of circle
+        that passes through all vertices of the outer polygon)
+    :param float t: Thickness of the polygon section wall
+    :param float r_in: Inner radius of the polygon corners. By default, if not specified, a polygon
+        with no corner radii is generated.
+    :param int n_r: Number of points discretising the inner and outer radii, ignored if no inner
+        radii is specified
+    :param rot: Initial counterclockwise rotation in degrees. By default bottom face is aligned
+        with x axis.
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+    :raises Exception: Number of sides in polygon must be greater than or equal to 3
+
+    The following example creates an Octagonal section (8 sides) with a diameter of 200, a
+    thickness of 6 and an inner radius of 20, using 12 points to discretise the inner and outer
+    radii. A mesh is generated with a maximum triangular area of 5::
+
+        from sectionproperties.pre.library.steel_sections import polygon_hollow_section
+
+        geometry = polygon_hollow_section(d=200, t=6, n_sides=8, r_in=20, n_r=12)
+        geometry.create_mesh(mesh_sizes=[5])
+
+    ..  figure:: ../images/sections/polygon_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Octagonal section geometry.
+
+    ..  figure:: ../images/sections/polygon_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    outer_points = []
+    inner_points = []
+
+    if n_sides < 3:
+        msg = "n_sides required to be greater than 3 for polygon_section()"
+        raise Exception(msg)
+
+    # initial rotation
+    rot = rot * np.pi / 180  # radians
+
+    # determine triangular segment angle
+    alpha = 2 * np.pi / n_sides  # radians
+
+    # determine distance from origin to point perpendicular on face of side
+    a_out = d / 2 * np.cos(alpha / 2)
+    a_in = a_out - t
+
+    # determine side length for outer & inner faces neglecting radii
+    side_length_out = d * np.sin(alpha / 2)
+    side_length_in = a_in / a_out * side_length_out
+
+    # check limit on internal radii, if exceeded then radii merge to circle
+    if r_in > a_in:
+        r_in = a_in
+        circle = True
+    else:
+        circle = False
+
+    # calculate external radius, if r_in is zero, r_out also is zero
+    if r_in == 0:
+        r_out = 0
+        n_r = 1
+    else:
+        r_out = r_in + t
+
+    # equivalent side length of half the corner radii triangular segment
+    c_out = r_out * (side_length_out / 2) / a_out
+    c_in = r_in * (side_length_in / 2) / a_in
+
+    # determine straight side length between corner radii (if present)
+    side_length_straight_out = side_length_out - (2 * c_out)
+    side_length_straight_in = side_length_in - (2 * c_in)
+
+    # temp list for repeating geometry
+    outer_base_points = []
+    inner_base_points = []
+
+    # start at bottom face, constructing one corner radii, then rotate by initial rotation +
+    # alpha and repeat for n_side number of times to form full section perimeter
+
+    # construct the first radius (bottom right)
+    for i in range(n_r):
+        # determine polar angle
+        theta = 1 / 2 * np.pi + i * 1.0 / max(1, n_r - 1) * alpha
+
+        # calculate location of inner and outer points
+        x_outer = side_length_straight_out / 2 - r_out * np.cos(theta)
+        y_outer = -a_out + r_out - r_out * np.sin(theta)
+        x_inner = side_length_straight_in / 2 - r_in * np.cos(theta)
+        y_inner = -a_in + r_in - r_in * np.sin(theta)
+
+        # append the current temporary points to the temporary points list
+        outer_base_points.append([x_outer, y_outer])
+        inner_base_points.append([x_inner, y_inner])
+
+    for i in range(n_sides):
+        for point in outer_base_points:
+            point_new = rotate(point, alpha * i + rot)
+            outer_points.append(point_new)
+
+        for point in inner_base_points:
+            point_new = rotate(point, alpha * i + rot)
+            inner_points.append(point_new)
+
+    outer_polygon = Polygon(outer_points)
+    inner_polygon = Polygon(inner_points)
+    return Geometry(outer_polygon - inner_polygon, material)
+
+
+def i_section(
+    d: float,
+    b: float,
+    t_f: float,
+    t_w: float,
+    r: float,
+    n_r: int,
+    material: pre.Material = pre.DEFAULT_MATERIAL,
+) -> Geometry:  # More specific description and less ambiguous? e.g. not an "S" section.
+    """Constructs an I-section centered at *(b/2, d/2)*, with depth *d*, width *b*, flange
+    thickness *t_f*, web thickness *t_w*, and root radius *r*, using *n_r* points to construct the
+    root radius.
+
+    :param float d: Depth of the I-section
+    :param float b: Width of the I-section
+    :param float t_f: Flange thickness of the I-section
+    :param float t_w: Web thickness of the I-section
+    :param float r: Root radius of the I-section
+    :param int n_r: Number of points discretising the root radius
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates an I-section with a depth of 203, a width of 133, a flange
+    thickness of 7.8, a web thickness of 5.8 and a root radius of 8.9, using 16 points to
+    discretise the root radius. A mesh is generated with a maximum triangular area of 3.0::
+
+        from sectionproperties.pre.library.steel_sections import i_section
+
+        geometry = i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16)
+        geometry.create_mesh(mesh_sizes=[3.0])
+
+    ..  figure:: ../images/sections/isection_geometry.png
+        :align: center
+        :scale: 75 %
+
+        I-section geometry.
+
+    ..  figure:: ../images/sections/isection_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points = []
+
+    # add first three points
+    points.append([0, 0])
+    points.append([b, 0])
+    points.append([b, t_f])
+
+    # construct the bottom right radius
+    pt = [b * 0.5 + t_w * 0.5 + r, t_f + r]
+    points += draw_radius(pt, r, 1.5 * np.pi, n_r, False)
+
+    # construct the top right radius
+    pt = [b * 0.5 + t_w * 0.5 + r, d - t_f - r]
+    points += draw_radius(pt, r, np.pi, n_r, False)
+
+    # add the next four points
+    points.append([b, d - t_f])
+    points.append([b, d])
+    points.append([0, d])
+    points.append([0, d - t_f])
+
+    # construct the top left radius
+    pt = [b * 0.5 - t_w * 0.5 - r, d - t_f - r]
+    points += draw_radius(pt, r, 0.5 * np.pi, n_r, False)
+
+    # construct the bottom left radius
+    pt = [b * 0.5 - t_w * 0.5 - r, t_f + r]
+    points += draw_radius(pt, r, 0, n_r, False)
+
+    # # add the last point
+    points.append([0, t_f])
+    i_section = Polygon(points)
+    return Geometry(i_section, material)
+
+
+def mono_i_section(
+    d, b_t, b_b, t_fb, t_ft, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a monosymmetric I-section centered at *(max(b_t, b_b)/2, d/2)*, with depth *d*,
+    top flange width *b_t*, bottom flange width *b_b*, top flange thickness *t_ft*, top flange
+    thickness *t_fb*, web thickness *t_w*, and root radius *r*, using *n_r* points to construct the
+    root radius.
+
+    :param float d: Depth of the I-section
+    :param float b_t: Top flange width
+    :param float b_b: Bottom flange width
+    :param float t_ft: Top flange thickness of the I-section
+    :param float t_fb: Bottom flange thickness of the I-section
+    :param float t_w: Web thickness of the I-section
+    :param float r: Root radius of the I-section
+    :param int n_r: Number of points discretising the root radius
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a monosymmetric I-section with a depth of 200, a top flange width
+    of 50, a top flange thickness of 12, a bottom flange width of 130, a bottom flange thickness of
+    8, a web thickness of 6 and a root radius of 8, using 16 points to discretise the root radius.
+    A mesh is generated with a maximum triangular area of 3.0::
+
+        from sectionproperties.pre.library.steel_sections import mono_i_section
+
+        geometry = mono_i_section(
+            d=200, b_t=50, b_b=130, t_ft=12, t_fb=8, t_w=6, r=8, n_r=16
+        )
+        geometry.create_mesh(mesh_sizes=[3.0])
+
+    ..  figure:: ../images/sections/monoisection_geometry.png
+        :align: center
+        :scale: 75 %
+
+        I-section geometry.
+
+    ..  figure:: ../images/sections/monoisection_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points = []
+    # calculate central axis
+    x_central = max(b_t, b_b) * 0.5
+
+    # add first three points
+    points.append([x_central - b_b * 0.5, 0])
+    points.append([x_central + b_b * 0.5, 0])
+    points.append([x_central + b_b * 0.5, t_fb])
+
+    # construct the bottom right radius
+    pt = [x_central + t_w * 0.5 + r, t_fb + r]
+    points += draw_radius(pt, r, 1.5 * np.pi, n_r, False)
+
+    # construct the top right radius
+    pt = [x_central + t_w * 0.5 + r, d - t_ft - r]
+    points += draw_radius(pt, r, np.pi, n_r, False)
+
+    # add the next four points
+    points.append([x_central + b_t * 0.5, d - t_ft])
+    points.append([x_central + b_t * 0.5, d])
+    points.append([x_central - b_t * 0.5, d])
+    points.append([x_central - b_t * 0.5, d - t_ft])
+
+    # construct the top left radius
+    pt = [x_central - t_w * 0.5 - r, d - t_ft - r]
+    points += draw_radius(pt, r, 0.5 * np.pi, n_r, False)
+
+    # construct the bottom left radius
+    pt = [x_central - t_w * 0.5 - r, t_fb + r]
+    points += draw_radius(pt, r, 0, n_r, False)
+
+    # add the last point
+    points.append([x_central - b_b * 0.5, t_fb])
+
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
+
+
+def tapered_flange_i_section(
+    d, b, t_f, t_w, r_r, r_f, alpha, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a Tapered Flange I-section centered at *(b/2, d/2)*, with depth *d*, width *b*,
+    mid-flange thickness *t_f*, web thickness *t_w*, root radius *r_r*, flange radius *r_f* and
+    flange angle *alpha*, using *n_r* points to construct the radii.
+
+    :param float d: Depth of the Tapered Flange I-section
+    :param float b: Width of the Tapered Flange I-section
+    :param float t_f: Mid-flange thickness of the Tapered Flange I-section (measured at the point
+        equidistant from the face of the web to the edge of the flange)
+    :param float t_w: Web thickness of the Tapered Flange I-section
+    :param float r_r: Root radius of the Tapered Flange I-section
+    :param float r_f: Flange radius of the Tapered Flange I-section
+    :param float alpha: Flange angle of the Tapered Flange I-section (degrees)
+    :param int n_r: Number of points discretising the radii
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a Tapered Flange I-section with a depth of 588, a width of 191, a
+    mid-flange thickness of 27.2, a web thickness of 15.2, a root radius of 17.8, a flange radius
+    of 8.9 and a flange angle of 8°, using 16 points to discretise the radii. A mesh is generated
+    with a maximum triangular area of 20.0::
+
+        from sectionproperties.pre.library.steel_sections import tapered_flange_i_section
+
+        geometry = tapered_flange_i_section(
+            d=588, b=191, t_f=27.2, t_w=15.2, r_r=17.8, r_f=8.9, alpha=8, n_r=16
+        )
+        geometry.create_mesh(mesh_sizes=[20.0])
+
+    ..  figure:: ../images/sections/taperedisection_geometry.png
+        :align: center
+        :scale: 75 %
+
+        I-section geometry.
+
+    ..  figure:: ../images/sections/taperedisection_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points = []
+
+    # calculate alpha in radians
+    alpha_rad = np.pi * alpha / 180
+
+    # calculate the height of the flange toe and dimensions of the straight
+    x1 = b * 0.25 - t_w * 0.25 - r_f * (1 - np.sin(alpha_rad))
+    y1 = x1 * np.tan(alpha_rad)
+    x2 = b * 0.25 - t_w * 0.25 - r_r * (1 - np.sin(alpha_rad))
+    y2 = x2 * np.tan(alpha_rad)
+    y_t = t_f - y1 - r_f * np.cos(alpha_rad)
+
+    # add first two points
+    points.append([0, 0])
+    points.append([b, 0])
+
+    # construct the bottom right flange toe radius
+    if r_f == 0:
+        points.append([b, y_t])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+
+            # calculate the locations of the radius points
+            x = b - r_f + r_f * np.cos(theta)
+            y = y_t + r_f * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the bottom right root radius
+    if r_r == 0:
+        points.append([b * 0.5 + t_w * 0.5, t_f + y2])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = (3.0 / 2 * np.pi - alpha_rad) - (
+                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+            )
+
+            # calculate the locations of the radius points
+            x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta)
+            y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the top right root radius
+    if r_r == 0:
+        points.append([b * 0.5 + t_w * 0.5, d - t_f - y2])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+
+            # calculate the locations of the radius points
+            x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta)
+            y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the top right flange toe radius
+    if r_f == 0:
+        points.append([b, d - y_t])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = (3.0 * np.pi / 2 + alpha_rad) + i * 1.0 / max(1, n_r - 1) * (
+                np.pi * 0.5 - alpha_rad
+            )
+
+            # calculate the locations of the radius points
+            x = b - r_f + r_f * np.cos(theta)
+            y = d - y_t + r_f * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # add the next two points
+    points.append([b, d])
+    points.append([0, d])
+
+    # construct the top left flange toe radius
+    if r_f == 0:
+        points.append([0, d - y_t])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = np.pi + (i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad))
+
+            # calculate the locations of the radius points
+            x = r_f + r_f * np.cos(theta)
+            y = d - y_t + r_f * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the top left root radius
+    if r_r == 0:
+        points.append([b * 0.5 - t_w * 0.5, d - t_f - y2])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = (np.pi * 0.5 - alpha_rad) - (
+                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+            )
+
+            # calculate the locations of the radius points
+            x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta)
+            y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the bottom left root radius
+    if r_r == 0:
+        points.append([b * 0.5 - t_w * 0.5, t_f + y2])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = -i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+
+            # calculate the locations of the radius points
+            x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta)
+            y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the bottom left flange toe radius
+    if r_f == 0:
+        points.append([0, y_t])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = (np.pi * 0.5 + alpha_rad) + (
+                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+            )
+
+            # calculate the locations of the radius points
+            x = r_f + r_f * np.cos(theta)
+            y = y_t + r_f * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
+
+
+def channel_section(
+    d, b, t_f, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a parallel-flange channel (PFC) section with the bottom left corner at the origin *(0, 0)*, with depth *d*,
+    width *b*, flange thickness *t_f*, web  thickness *t_w* and root radius *r*, using *n_r* points
+    to construct the root radius.
+
+    :param float d: Depth of the PFC section
+    :param float b: Width of the PFC section
+    :param float t_f: Flange thickness of the PFC section
+    :param float t_w: Web thickness of the PFC section
+    :param float r: Root radius of the PFC section
+    :param int n_r: Number of points discretising the root radius
+    :param shift: Vector that shifts the cross-section by *(x, y)*
+    :type shift: list[float, float]
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a PFC section with a depth of 250, a width of 90, a flange
+    thickness of 15, a web thickness of 8 and a root radius of 12, using 8 points to discretise the
+    root radius. A mesh is generated with a maximum triangular area of 5.0::
+
+        from sectionproperties.pre.library.steel_sections import channel_section
+
+        geometry = channel_section(d=250, b=90, t_f=15, t_w=8, r=12, n_r=8)
+        geometry.create_mesh(mesh_sizes=[5.0])
+
+    ..  figure:: ../images/sections/pfc_geometry.png
+        :align: center
+        :scale: 75 %
+
+        PFC geometry.
+
+    ..  figure:: ../images/sections/pfc_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points = []
+
+    # add first three points
+    points.append([0, 0])
+    points.append([b, 0])
+    points.append([b, t_f])
+
+    # construct the bottom right radius
+    pt = [t_w + r, t_f + r]
+    points += draw_radius(pt, r, 1.5 * np.pi, n_r, False)
+
+    # construct the top right radius
+    pt = [t_w + r, d - t_f - r]
+    points += draw_radius(pt, r, np.pi, n_r, False)
+
+    # add last three points
+    points.append([b, d - t_f])
+    points.append([b, d])
+    points.append([0, d])
+
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
+
+
+def tapered_flange_channel(
+    d, b, t_f, t_w, r_r, r_f, alpha, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a Tapered Flange Channel section with the bottom left corner at the origin
+    *(0, 0)*, with depth *d*, width *b*, mid-flange thickness *t_f*, web thickness *t_w*, root
+    radius *r_r*, flange radius *r_f* and flange angle *alpha*, using *n_r* points to construct the
+    radii.
+
+    :param float d: Depth of the Tapered Flange Channel section
+    :param float b: Width of the Tapered Flange Channel section
+    :param float t_f: Mid-flange thickness of the Tapered Flange Channel section (measured at the
+        point equidistant from the face of the web to the edge of the flange)
+    :param float t_w: Web thickness of the Tapered Flange Channel section
+    :param float r_r: Root radius of the Tapered Flange Channel section
+    :param float r_f: Flange radius of the Tapered Flange Channel section
+    :param float alpha: Flange angle of the Tapered Flange Channel section (degrees)
+    :param int n_r: Number of points discretising the radii
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a Tapered Flange Channel section with a depth of 10, a width of
+    3.5, a mid-flange thickness of 0.575, a web thickness of 0.475, a root radius of 0.575, a
+    flange radius of 0.4 and a flange angle of 8°, using 16 points to discretise the radii. A mesh
+    is generated with a maximum triangular area of 0.02::
+
+        from sectionproperties.pre.library.steel_sections import tapered_flange_channel
+
+        geometry = tapered_flange_channel(
+            d=10, b=3.5, t_f=0.575, t_w=0.475, r_r=0.575, r_f=0.4, alpha=8, n_r=16
+        )
+        geometry.create_mesh(mesh_sizes=[0.02])
+
+    ..  figure:: ../images/sections/taperedchannel_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Tapered flange channel geometry.
+
+    ..  figure:: ../images/sections/taperedchannel_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points = []
+
+    # calculate alpha in radians
+    alpha_rad = np.pi * alpha / 180
+
+    # calculate the height of the flange toe and dimensions of the straight
+    x1 = b * 0.5 - t_w * 0.5 - r_f * (1 - np.sin(alpha_rad))
+    y1 = x1 * np.tan(alpha_rad)
+    x2 = b * 0.5 - t_w * 0.5 - r_r * (1 - np.sin(alpha_rad))
+    y2 = x2 * np.tan(alpha_rad)
+    y_t = t_f - y1 - r_f * np.cos(alpha_rad)
+
+    # add first two points
+    points.append([0, 0])
+    points.append([b, 0])
+
+    # construct the bottom right flange toe radius
+    if r_f == 0:
+        points.append([b, y_t])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+
+            # calculate the locations of the radius points
+            x = b - r_f + r_f * np.cos(theta)
+            y = y_t + r_f * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the bottom right root radius
+    if r_r == 0:
+        points.append([t_w, t_f + y2])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = (3.0 / 2 * np.pi - alpha_rad) - (
+                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+            )
+
+            # calculate the locations of the radius points
+            x = t_w + r_r + r_r * np.cos(theta)
+            y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the top right root radius
+    if r_r == 0:
+        points.append([t_w, d - t_f - y2])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+
+            # calculate the locations of the radius points
+            x = t_w + r_r + r_r * np.cos(theta)
+            y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # construct the top right flange toe radius
+    if r_f == 0:
+        points.append([b, d - y_t])
+    else:
+        for i in range(n_r):
+            # determine polar angle
+            theta = (3.0 * np.pi / 2 + alpha_rad) + (
+                i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)
+            )
+
+            # calculate the locations of the radius points
+            x = b - r_f + r_f * np.cos(theta)
+            y = d - y_t + r_f * np.sin(theta)
+
+            # append the current points to the points list
+            points.append([x, y])
+
+    # add the final two points
+    points.append([b, d])
+    points.append([0, d])
+
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
+
+
+def tee_section(
+    d, b, t_f, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a Tee section with the top left corner at *(0, d)*, with depth *d*, width *b*,
+    flange thickness *t_f*, web thickness *t_w* and root radius *r*, using *n_r* points to
+    construct the root radius.
+
+    :param float d: Depth of the Tee section
+    :param float b: Width of the Tee section
+    :param float t_f: Flange thickness of the Tee section
+    :param float t_w: Web thickness of the Tee section
+    :param float r: Root radius of the Tee section
+    :param int n_r: Number of points discretising the root radius
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a Tee section with a depth of 200, a width of 100, a flange
+    thickness of 12, a web thickness of 6 and a root radius of 8, using 8 points to discretise the
+    root radius. A mesh is generated with a maximum triangular area of 3.0::
+
+        from sectionproperties.pre.library.steel_sections import tee_section
+
+        geometry = tee_section(d=200, b=100, t_f=12, t_w=6, r=8, n_r=8)
+        geometry.create_mesh(mesh_sizes=[3.0])
+
+    ..  figure:: ../images/sections/tee_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Tee section geometry.
+
+    ..  figure:: ../images/sections/tee_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    points = []
+    # add first two points
+    points.append([b * 0.5 - t_w * 0.5, 0])
+    points.append([b * 0.5 + t_w * 0.5, 0])
+
+    # construct the top right radius
+    pt = [b * 0.5 + t_w * 0.5 + r, d - t_f - r]
+    points += draw_radius(pt, r, np.pi, n_r, False)
+
+    # add next four points
+    points.append([b, d - t_f])
+    points.append([b, d])
+    points.append([0, d])
+    points.append([0, d - t_f])
+
+    # construct the top left radius
+    pt = [b * 0.5 - t_w * 0.5 - r, d - t_f - r]
+    points += draw_radius(pt, r, 0.5 * np.pi, n_r, False)
+
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
+
+
+def angle_section(
+    d, b, t, r_r, r_t, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs an angle section with the bottom left corner at the origin *(0, 0)*, with depth
+    *d*, width *b*, thickness *t*, root radius *r_r* and toe radius *r_t*, using *n_r* points to
+    construct the radii.
+
+    :param float d: Depth of the angle section
+    :param float b: Width of the angle section
+    :param float t: Thickness of the angle section
+    :param float r_r: Root radius of the angle section
+    :param float r_t: Toe radius of the angle section
+    :param int n_r: Number of points discretising the radii
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates an angle section with a depth of 150, a width of 100, a thickness
+    of 8, a root radius of 12 and a toe radius of 5, using 16 points to discretise the radii. A
+    mesh is generated with a maximum triangular area of 2.0::
+
+        from sectionproperties.pre.library.steel_sections import angle_section
+
+        geometry = angle_section(d=150, b=100, t=8, r_r=12, r_t=5, n_r=16)
+        geometry.create_mesh(mesh_sizes=[2.0])
+
+    ..  figure:: ../images/sections/angle_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Angle section geometry.
+
+    ..  figure:: ../images/sections/angle_mesh.png
+        :align: center
+        :scale: 75 %
+    """
+    if r_t > t:
+        raise ValueError(
+            "The radius of the toe (r_t) cannot be larger than the toe thickness (t)."
+        )
+
+    points = []
+
+    # add first two points
+    points.append([0, 0])
+    points.append([b, 0])
+
+    # construct the bottom toe radius
+    pt = [b - r_t, t - r_t]
+    points += draw_radius(pt, r_t, 0, n_r)
+
+    # construct the root radius
+    pt = [t + r_r, t + r_r]
+    points += draw_radius(pt, r_r, 1.5 * np.pi, n_r, False)
+
+    # construct the top toe radius
+    pt = [t - r_t, d - r_t]
+    points += draw_radius(pt, r_t, 0, n_r)
+
+    # add the next point
+    points.append([0, d])
+
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
+
+
+def cee_section(
+    d, b, l, t, r_out, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a Cee section (typical of cold-formed steel) with the bottom left corner at the
+    origin *(0, 0)*, with depth *d*, width *b*, lip *l*, thickness *t* and outer radius *r_out*,
+    using *n_r* points to construct the radius. If the outer radius is less than the thickness
+    of the Cee Section, the inner radius is set to zero.
+
+    :param float d: Depth of the Cee section
+    :param float b: Width of the Cee section
+    :param float l: Lip of the Cee section
+    :param float t: Thickness of the Cee section
+    :param float r_out: Outer radius of the Cee section
+    :param int n_r: Number of points discretising the outer radius
+    :raises Exception: Lip length must be greater than the outer radius
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a Cee section with a depth of 125, a width of 50, a lip of 30, a
+    thickness of 1.5 and an outer radius of 6, using 8 points to discretise the radius. A mesh is
+    generated with a maximum triangular area of 0.25::
+
+        from sectionproperties.pre.library.steel_sections import cee_section
+
+        geometry = cee_section(d=125, b=50, l=30, t=1.5, r_out=6, n_r=8)
+        geometry.create_mesh(mesh_sizes=[0.25])
+
+    ..  figure:: ../images/sections/cee_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Cee section geometry.
+
+    ..  figure:: ../images/sections/cee_mesh.png
+        :align: center
+        :scale: 75 %
+    """
+    # ensure the lip length is greater than the outer radius
+    if l < r_out:
+        raise Exception("Lip length must be greater than the outer radius")
+
+    points = []
+
+    # calculate internal radius
+    r_in = max(r_out - t, 0)
+
+    # construct the outer bottom left radius
+    points += draw_radius([r_out, r_out], r_out, np.pi, n_r)
+
+    # construct the outer bottom right radius
+    points += draw_radius([b - r_out, r_out], r_out, 1.5 * np.pi, n_r)
+
+    if r_out != l:
+        # add next two points
+        points.append([b, l])
+        points.append([b - t, l])
+
+    # construct the inner bottom right radius
+    points += draw_radius([b - t - r_in, t + r_in], r_in, 0, n_r, False)
+
+    # construct the inner bottom left radius
+    points += draw_radius([t + r_in, t + r_in], r_in, 1.5 * np.pi, n_r, False)
+
+    # construct the inner top left radius
+    points += draw_radius([t + r_in, d - t - r_in], r_in, np.pi, n_r, False)
+
+    # construct the inner top right radius
+    points += draw_radius([b - t - r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r, False)
+
+    if r_out != l:
+        # add next two points
+        points.append([b - t, d - l])
+        points.append([b, d - l])
+
+    # construct the outer top right radius
+    points += draw_radius([b - r_out, d - r_out], r_out, 0, n_r)
+
+    # construct the outer top left radius
+    points += draw_radius([r_out, d - r_out], r_out, 0.5 * np.pi, n_r)
+
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
+
+
+def zed_section(
+    d, b_l, b_r, l, t, r_out, n_r, material: pre.Material = pre.DEFAULT_MATERIAL
+) -> Geometry:
+    """Constructs a zed section with the bottom left corner at the origin *(0, 0)*, with depth *d*,
+    left flange width *b_l*, right flange width *b_r*, lip *l*, thickness *t* and outer radius
+    *r_out*, using *n_r* points to construct the radius. If the outer radius is less than the
+    thickness of the Zed Section, the inner radius is set to zero.
+
+    :param float d: Depth of the zed section
+    :param float b_l: Left flange width of the Zed section
+    :param float b_r: Right flange width of the Zed section
+    :param float l: Lip of the Zed section
+    :param float t: Thickness of the Zed section
+    :param float r_out: Outer radius of the Zed section
+    :param int n_r: Number of points discretising the outer radius
+    :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry
+
+    The following example creates a zed section with a depth of 100, a left flange width of 40, a
+    right flange width of 50, a lip of 20, a thickness of 1.2 and an outer radius of 5, using 8
+    points to discretise the radius. A mesh is generated with a maximum triangular area of 0.15::
+
+        from sectionproperties.pre.library.steel_sections import zed_section
+
+        geometry = zed_section(d=100, b_l=40, b_r=50, l=20, t=1.2, r_out=5, n_r=8)
+        geometry.create_mesh(mesh_sizes=[0.15])
+
+    ..  figure:: ../images/sections/zed_geometry.png
+        :align: center
+        :scale: 75 %
+
+        zed section geometry.
+
+    ..  figure:: ../images/sections/zed_mesh.png
+        :align: center
+        :scale: 75 %
+    """
+    # ensure the lip length is greater than the outer radius
+    if l < r_out:
+        raise Exception("Lip length must be greater than the outer radius")
+
+    points = []
+
+    # calculate internal radius
+    r_in = max(r_out - t, 0)
+
+    # construct the outer bottom left radius
+    points += draw_radius([r_out, r_out], r_out, np.pi, n_r)
+
+    # construct the outer bottom right radius
+    points += draw_radius([b_r - r_out, r_out], r_out, 1.5 * np.pi, n_r)
+
+    if r_out != l:
+        # add next two points
+        points.append([b_r, l])
+        points.append([b_r - t, l])
+
+    # construct the inner bottom right radius
+    points += draw_radius([b_r - t - r_in, t + r_in], r_in, 0, n_r, False)
+
+    # construct the inner bottom left radius
+    points += draw_radius([t + r_in, t + r_in], r_in, 1.5 * np.pi, n_r, False)
+
+    # construct the outer top right radius
+    points += draw_radius([t - r_out, d - r_out], r_out, 0, n_r)
+
+    # construct the outer top left radius
+    points += draw_radius([t - b_l + r_out, d - r_out], r_out, 0.5 * np.pi, n_r)
+
+    if r_out != l:
+        # add the next two points
+        points.append([t - b_l, d - l])
+        points.append([t - b_l + t, d - l])
+
+    # construct the inner top left radius
+    points += draw_radius([2 * t - b_l + r_in, d - t - r_in], r_in, np.pi, n_r, False)
+
+    # construct the inner top right radius
+    points += draw_radius([-r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r, False)
+    polygon = Polygon(points)
+    return Geometry(polygon, material)
+
+
+def box_girder_section(
+    d, b_t, b_b, t_ft, t_fb, t_w, material: pre.Material = pre.DEFAULT_MATERIAL
+):
+    """Constructs a box girder section centered at at *(max(b_t, b_b)/2, d/2)*, with depth *d*, top
+    width *b_t*, bottom width *b_b*, top flange thickness *t_ft*, bottom flange thickness *t_fb*
+    and web thickness *t_w*.
+
+    :param float d: Depth of the Box Girder section
+    :param float b_t: Top width of the Box Girder section
+    :param float b_b: Bottom width of the Box Girder section
+    :param float t_ft: Top flange thickness of the Box Girder section
+    :param float t_fb: Bottom flange thickness of the Box Girder section
+    :param float t_w: Web thickness of the Box Girder section
+
+    The following example creates a Box Girder section with a depth of 1200, a top width of 1200, a
+    bottom width of 400, a top flange thickness of 16, a bottom flange thickness of 12 and a web
+    thickness of 8. A mesh is generated with a maximum triangular area of 5.0::
+
+        from sectionproperties.pre.library.steel_sections import box_girder_section
+
+        geometry = box_girder_section(d=1200, b_t=1200, b_b=400, t_ft=100, t_fb=80, t_w=50)
+        geometry.create_mesh(mesh_sizes=[200.0])
+
+    ..  figure:: ../images/sections/box_girder_geometry.png
+        :align: center
+        :scale: 75 %
+
+        Box Girder geometry.
+
+    ..  figure:: ../images/sections/box_girder_mesh.png
+        :align: center
+        :scale: 75 %
+
+        Mesh generated from the above geometry.
+    """
+    outer_points = []
+    inner_points = []
+
+    # calculate central axis
+    x_c = max(b_t, b_b) * 0.5
+
+    # determine side wall angle
+    if b_t < b_b:
+        phi_b = np.arctan2(d, 0.5 * (b_b - b_t))
+        phi_t = np.pi - phi_b
+    else:
+        phi_t = np.arctan2(d, 0.5 * (b_t - b_b))
+        phi_b = np.pi - phi_t
+
+    # determine inner wall x-offsets
+    x_bot = t_fb / np.tan(np.pi - phi_b)
+    x_top = t_ft / np.tan(np.pi - phi_t)
+    web_x = abs(t_w / np.sin(np.pi - phi_b))
+
+    # add outer points
+    outer_points.append([x_c - 0.5 * b_b, 0])
+    outer_points.append([x_c + 0.5 * b_b, 0])
+    outer_points.append([x_c + 0.5 * b_t, d])
+    outer_points.append([x_c - 0.5 * b_t, d])
+
+    # add inner points
+    inner_points.append([x_c - 0.5 * b_b - x_bot + web_x, t_fb])
+    inner_points.append([x_c + 0.5 * b_b + x_bot - web_x, t_fb])
+    inner_points.append([x_c + 0.5 * b_t + x_top - web_x, d - t_ft])
+    inner_points.append([x_c - 0.5 * b_t - x_top + web_x, d - t_ft])
+
+    outer_polygon = Polygon(outer_points)
+    inner_polygon = Polygon(inner_points)
+
+    return Geometry(outer_polygon - inner_polygon, material)
diff --git a/sectionproperties/pre/library/utils.py b/sectionproperties/pre/library/utils.py
new file mode 100644
index 00000000..495f2316
--- /dev/null
+++ b/sectionproperties/pre/library/utils.py
@@ -0,0 +1,54 @@
+import numpy as np
+
+
+def draw_radius(pt: list, r: float, theta: float, n, ccw: bool = True):
+    """Adds a quarter radius of points to the points list - centered at point *pt*, with radius
+    *r*, starting at angle *theta*, with *n* points. If r = 0, adds pt only.
+
+    :param pt: Centre of radius *(x,y)*
+    :type pt: list[float, float]
+    :param float r: Radius
+    :param float theta: Initial angle
+    :param int n: Number of points
+    :param bool ccw: Counter-clockwise rotation?
+    """
+    points = []
+    if r == 0:
+        points.append(pt)
+        return points
+
+    if ccw:
+        mult = 1
+    else:
+        mult = -1
+
+    # calculate radius of points
+    for i in range(n):
+        # determine angle
+        t = theta + mult * i * 1.0 / max(1, n - 1) * np.pi * 0.5
+
+        x = pt[0] + r * np.cos(t)
+        y = pt[1] + r * np.sin(t)
+        points.append([x, y])
+    return points
+
+
+def rotate(point, angle: float):
+    """
+    Rotate a point counterclockwise by a given angle around origin [0, 0]
+
+    :param list point: Point coordinates to be rotated
+    :param float angle: Angle to rotate point coordinates
+    :return: Coordinates of rotated point
+    :rtype: list[float, float]
+    """
+
+    pt_x, pt_y = point
+
+    c = np.cos(angle)
+    s = np.sin(angle)
+
+    new_x = c * pt_x - s * pt_y
+    new_y = s * pt_x + c * pt_y
+
+    return [new_x, new_y]


Test patch:
diff --git a/sectionproperties/tests/test_offset.py b/sectionproperties/tests/test_offset.py
index b4211a41..7830bf86 100644
--- a/sectionproperties/tests/test_offset.py
+++ b/sectionproperties/tests/test_offset.py
@@ -1,9 +1,10 @@
 import pytest_check as check
 import numpy as np
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.standard_sections as sections
+import sectionproperties.pre.library.steel_sections as steel_sections
+from sectionproperties.analysis.section import Section
 from shapely.geometry import Polygon
-from sectionproperties.pre.sections import Geometry
+from sectionproperties.pre.geometry import Geometry
 
 
 r_tol = 1e-3
@@ -31,7 +32,7 @@ def test_rectangular_offset():
 
 def test_box_offset():
     # exterior negative offset
-    box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
+    box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
     box = box.offset_perimeter(amount=-5, where="exterior")
     box.create_mesh([50])
     section = Section(box)
@@ -40,7 +41,7 @@ def test_box_offset():
     check.almost_equal(section.get_area(), area, rel=r_tol)
 
     # exterior positve offset
-    box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
+    box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
     box = box.offset_perimeter(amount=5, where="exterior")
     box.create_mesh([50])
     section = Section(box)
@@ -49,7 +50,7 @@ def test_box_offset():
     check.almost_equal(section.get_area(), area, rel=r_tol)
 
     # interior negative offset
-    box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
+    box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
     box = box.offset_perimeter(amount=-5, where="interior")
     box.create_mesh([50])
     section = Section(box)
@@ -58,7 +59,7 @@ def test_box_offset():
     check.almost_equal(section.get_area(), area, rel=r_tol)
 
     # interior positive offset
-    box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
+    box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
     box = box.offset_perimeter(amount=5, where="interior")
     box.create_mesh([50])
     section = Section(box)
@@ -67,7 +68,7 @@ def test_box_offset():
     check.almost_equal(section.get_area(), area, rel=r_tol)
 
     # all negative offset
-    box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
+    box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
     box = box.offset_perimeter(amount=-2.5, where="all")
     box.create_mesh([50])
     section = Section(box)
@@ -76,7 +77,7 @@ def test_box_offset():
     check.almost_equal(section.get_area(), area, rel=r_tol)
 
     # all positive offset
-    box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
+    box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1)
     box = box.offset_perimeter(amount=5, where="all")
     box.create_mesh([50])
     section = Section(box)
@@ -105,7 +106,7 @@ def test_compound_rectangular_isection_offset_corrode():
     r = 12
     b_p = 250
     t_p = 16
-    ub = sections.i_section(d=d, b=b, t_f=tf, t_w=tw, r=r, n_r=16)
+    ub = steel_sections.i_section(d=d, b=b, t_f=tf, t_w=tw, r=r, n_r=16)
     plate = (
         sections.rectangular_section(b=b_p, d=t_p)
         .align_center(ub)
@@ -117,7 +118,7 @@ def test_compound_rectangular_isection_offset_corrode():
     section_test = Section(geom_test)
     section_test.calculate_geometric_properties()
 
-    ub_corroded = sections.mono_i_section(
+    ub_corroded = steel_sections.mono_i_section(
         d=298, b_t=146, b_b=146, t_ft=8, t_fb=6, t_w=4, r=14, n_r=16
     )
     plate_corroded1 = (
@@ -154,7 +155,7 @@ def test_compound_stiffened_isection():
     Tests that plates 1 and 2 can be eroded to nothing and a valid Section can
     still be generated without errors.
     """
-    uc = sections.i_section(d=400, b=400, t_f=25, t_w=25, r=30, n_r=8)
+    uc = steel_sections.i_section(d=400, b=400, t_f=25, t_w=25, r=30, n_r=8)
     plate1 = (
         sections.rectangular_section(b=500, d=10).align_center(uc).align_to(uc, "top")
     )
diff --git a/sectionproperties/tests/test_perimeter.py b/sectionproperties/tests/test_perimeter.py
index 8426240d..3258575c 100644
--- a/sectionproperties/tests/test_perimeter.py
+++ b/sectionproperties/tests/test_perimeter.py
@@ -1,7 +1,9 @@
 import pytest_check as check
 import numpy as np
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+import sectionproperties.pre.library.standard_sections as sections
+import sectionproperties.pre.library.steel_sections as steel_sections
+from sectionproperties.pre.geometry import Geometry
+from sectionproperties.analysis.section import Section
 
 
 r_tol = 1e-3
@@ -16,7 +18,9 @@ def test_rectangular_perimeter():
 
 
 def test_i_section():
-    i_section = sections.i_section(d=308, b=305, t_f=15.4, t_w=9.9, r=16.5, n_r=16)
+    i_section = steel_sections.i_section(
+        d=308, b=305, t_f=15.4, t_w=9.9, r=16.5, n_r=16
+    )
     i_section.create_mesh([100])
     section = Section(i_section)
     section.calculate_geometric_properties()
@@ -31,7 +35,7 @@ def test_i_section():
 
 
 def test_box_girder_perimeter():
-    box_girder = sections.box_girder_section(
+    box_girder = steel_sections.box_girder_section(
         d=400, b_t=700, b_b=100, t_ft=20, t_fb=20, t_w=12
     )
     box_girder.create_mesh([100])
@@ -44,7 +48,7 @@ def test_custom_geometry_perimeter():
     points = [[0, 0], [5, 0], [11, 8], [3, 2], [0, 2]]
     facets = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]]
     control_points = [[5, 5]]
-    custom = sections.Geometry.from_points(points, facets, control_points, holes=None)
+    custom = Geometry.from_points(points, facets, control_points, holes=None)
     custom.create_mesh([100])
     section = Section(custom)
     section.calculate_geometric_properties()
@@ -77,7 +81,7 @@ def test_compound_rectangular_isection_perimeter1():
     r = 12
     b_p = 250
     t_p = 16
-    ub = sections.i_section(d=d, b=b, t_f=tf, t_w=tw, r=r, n_r=16)
+    ub = steel_sections.i_section(d=d, b=b, t_f=tf, t_w=tw, r=r, n_r=16)
     plate = (
         sections.rectangular_section(b=b_p, d=t_p)
         .align_center(ub)
@@ -101,7 +105,9 @@ def test_compound_rectangular_isection_perimeter1():
 
 
 def test_compound_rectangular_isection_perimeter2():
-    i_section = sections.i_section(d=308, b=305, t_f=15.4, t_w=9.9, r=16.5, n_r=16)
+    i_section = steel_sections.i_section(
+        d=308, b=305, t_f=15.4, t_w=9.9, r=16.5, n_r=16
+    )
     rect1 = (
         sections.rectangular_section(d=330, b=16)
         .align_center(i_section)
@@ -126,7 +132,7 @@ def test_compound_rhs_isection_perimeter():
     r = 15
     b_p = 250
     t_p = 16
-    rhs = sections.rectangular_hollow_section(d=d, b=b, t=t, r_out=r, n_r=16)
+    rhs = steel_sections.rectangular_hollow_section(d=d, b=b, t=t, r_out=r, n_r=16)
     plate1 = (
         sections.rectangular_section(b=b_p, d=t_p)
         .align_center(rhs)
diff --git a/sectionproperties/tests/test_rectangle.py b/sectionproperties/tests/test_rectangle.py
index cd7713d9..a5520c42 100644
--- a/sectionproperties/tests/test_rectangle.py
+++ b/sectionproperties/tests/test_rectangle.py
@@ -1,15 +1,15 @@
 import pytest_check as check
 
 # import unittest
-import sectionproperties.pre.sections as sections
+import sectionproperties.pre.library.standard_sections as standard_sections
 import sectionproperties.pre.pre as pre
-from sectionproperties.analysis.cross_section import Section
+from sectionproperties.analysis.section import Section
 from sectionproperties.tests.helper_functions import validate_properties
 
-import sectionproperties.analysis.cross_section as file
+import sectionproperties.analysis.section as file
 
 # Rectangle section setup
-rectangle_geometry = sections.rectangular_section(b=50, d=100)
+rectangle_geometry = standard_sections.rectangular_section(b=50, d=100)
 rectangle_geometry.create_mesh(mesh_sizes=100)
 rectangle_section = Section(rectangle_geometry)
 rectangle_section.calculate_geometric_properties()
diff --git a/sectionproperties/tests/test_sections.py b/sectionproperties/tests/test_sections.py
index 4bc2c3c4..5b42bf4e 100644
--- a/sectionproperties/tests/test_sections.py
+++ b/sectionproperties/tests/test_sections.py
@@ -1,9 +1,11 @@
 import pathlib
 import pytest
 
-from sectionproperties.pre.sections import *
-from sectionproperties.pre.nastran_sections import *
-from sectionproperties.analysis.cross_section import Section
+from sectionproperties.pre.geometry import *
+from sectionproperties.pre.library.standard_sections import *
+from sectionproperties.pre.library.steel_sections import *
+from sectionproperties.pre.library.nastran_sections import *
+from sectionproperties.analysis.section import Section
 from sectionproperties.pre.pre import Material
 from sectionproperties.pre.rhino import load_3dm, load_brep_encoding
 from shapely.geometry import (
diff --git a/sectionproperties/tests/test_validation.py b/sectionproperties/tests/test_validation.py
index 7f122504..c09bc4d3 100644
--- a/sectionproperties/tests/test_validation.py
+++ b/sectionproperties/tests/test_validation.py
@@ -1,12 +1,14 @@
 import pytest_check as check
 from shapely.geometry import Polygon
-import sectionproperties.pre.sections as sections
-from sectionproperties.analysis.cross_section import Section
+from sectionproperties.pre.geometry import Geometry
+import sectionproperties.pre.library.standard_sections as sections
+import sectionproperties.pre.library.steel_sections as steel_sections
+from sectionproperties.analysis.section import Section
 from sectionproperties.tests.helper_functions import validate_properties
 
 
 # Setup for angle section
-angle = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
+angle = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8)
 angle.create_mesh(mesh_sizes=2.5)
 angle_section = Section(angle)
 angle_section.calculate_geometric_properties()
@@ -85,7 +87,7 @@ def test_angle_all_properties():
     [45, 10],
     [-10, 10],
 ]
-custom_geom = sections.Geometry(Polygon(custom_geom_points))
+custom_geom = Geometry(Polygon(custom_geom_points))
 custom_geom.create_mesh(mesh_sizes=5)
 custom_section = Section(custom_geom)
 custom_section.calculate_geometric_properties()