diff --git a/doc/source/_static/thumbnails/add_design_material.PNG b/doc/source/_static/thumbnails/add_design_material.PNG new file mode 100644 index 0000000000..db25f560bb Binary files /dev/null and b/doc/source/_static/thumbnails/add_design_material.PNG differ diff --git a/doc/source/_static/thumbnails/dynamic_sketch_plane.png b/doc/source/_static/thumbnails/dynamic_sketch_plane.png index fb68ec9888..80dbf568d2 100644 Binary files a/doc/source/_static/thumbnails/dynamic_sketch_plane.png and b/doc/source/_static/thumbnails/dynamic_sketch_plane.png differ diff --git a/doc/source/_static/thumbnails/plate_with_hole.PNG b/doc/source/_static/thumbnails/plate_with_hole.PNG new file mode 100644 index 0000000000..7803762267 Binary files /dev/null and b/doc/source/_static/thumbnails/plate_with_hole.PNG differ diff --git a/doc/source/_static/thumbnails/tessellation_usage.PNG b/doc/source/_static/thumbnails/tessellation_usage.PNG new file mode 100644 index 0000000000..106108aae2 Binary files /dev/null and b/doc/source/_static/thumbnails/tessellation_usage.PNG differ diff --git a/doc/source/conf.py b/doc/source/conf.py index 12417cfc36..2f7252831d 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -120,9 +120,12 @@ ".mystnb": ["jupytext.reads", {"fmt": "mystnb"}], } nbsphinx_thumbnails = { - "examples/basic_usage": "_static/thumbnails/basic_usage.png", - "examples/dynamic_sketch_plane": "_static/thumbnails/dynamic_sketch_plane.png", - "examples/design_organization": "_static/thumbnails/design_organization.png", + "examples/basic/basic_usage": "_static/thumbnails/basic_usage.png", + "examples/design/dynamic_sketch_plane": "_static/thumbnails/dynamic_sketch_plane.png", + "examples/design/add_design_material": "_static/thumbnails/add_design_material.png", + "examples/design/plate_with_hole": "_static/thumbnails/plate_with_hole.png", + "examples/design/tessellation_usage": "_static/thumbnails/tessellation_usage.png", + "examples/design/design_organization": "_static/thumbnails/design_organization.png", } typehints_defaults = "comma" diff --git a/doc/source/examples.rst b/doc/source/examples.rst index f11051833b..9a5fbe0ecb 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -3,8 +3,24 @@ Examples All examples are collected in this page. +Math and sketch examples +------------------------ +This section demonstrates the math operations on geometric objects +and basic sketching capabilities in PyGeometry. + +.. nbgallery:: + + examples/basic/basic_usage.mystnb + +Service based examples +---------------------- + +This section demonstrates service based operations on PyGeometry. + .. nbgallery:: - examples/design_organization.mystnb - examples/dynamic_sketch_plane.mystnb - examples/basic_usage.mystnb + examples/design/add_design_material.mystnb + examples/design/plate_with_hole.mystnb + examples/design/dynamic_sketch_plane.mystnb + examples/design/tessellation_usage.mystnb + examples/design/design_organization.mystnb \ No newline at end of file diff --git a/doc/source/examples/basic_usage.mystnb b/doc/source/examples/basic/basic_usage.mystnb similarity index 100% rename from doc/source/examples/basic_usage.mystnb rename to doc/source/examples/basic/basic_usage.mystnb diff --git a/doc/source/examples/design/add_design_material.mystnb b/doc/source/examples/design/add_design_material.mystnb new file mode 100644 index 0000000000..d15e29ef2e --- /dev/null +++ b/doc/source/examples/design/add_design_material.mystnb @@ -0,0 +1,79 @@ +--- +jupytext: + text_representation: + extension: .mystnb + format_name: myst + format_version: 0.13 + jupytext_version: 1.14.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- +# Single body with material assignment + +In PyGeometry, a ``Body`` represents solids or surfaces organized within the ``Design`` assembly. +The current state of ``Sketch``, which is a client-side execution, can be used for the operations of +the geometric design assembly. The Geometry Service also provides data structures to create individual materials +and its properties, which are also exposed through PyGeometry. + +This example demonstrates how to create a single body from a sketch, by requesting its extrusion, +and how to assign a material to it. + +```{code-cell} ipython3 +from pint import Quantity + +from ansys.geometry.core import Modeler +from ansys.geometry.core.materials import Material, MaterialProperty, MaterialPropertyType +from ansys.geometry.core.math import UNITVECTOR3D_Z, Frame, Plane, Point2D, Point3D, UnitVector3D +from ansys.geometry.core.misc import UNITS +from ansys.geometry.core.sketch import Sketch +``` +## Defining the ``Sketch`` + +Create a basic ``circle`` sketch instance with radius 10mm in the default plane. + +```{code-cell} ipython3 +sketch = Sketch() +sketch.circle(Point2D([10, 10], UNITS.mm), Quantity(10, UNITS.mm)) +``` + +## Initiate the design in the server + +A server connection is established and a design has been initiated. +```{code-cell} ipython3 +modeler = Modeler() +design_name = "ExtrudeProfile" +design = modeler.create_design(design_name) +``` + +## Add materials to the design + +Adding materials and its properties to the design. Additional properties of +the material can be added at construction of the ``Material`` object or afterwards, +as it is shown in the code snippet. +```{code-cell} ipython3 +density = Quantity(125, 10 * UNITS.kg / (UNITS.m * UNITS.m * UNITS.m)) +poisson_ratio = Quantity(0.33, UNITS.dimensionless) +tensile_strength = Quantity(45) +material = Material( + "steel", + density, + [MaterialProperty(MaterialPropertyType.POISSON_RATIO, "PoissonRatio", poisson_ratio)], +) +material.add_property(MaterialPropertyType.TENSILE_STRENGTH, "TensileProp", Quantity(45)) +design.add_material(material) +``` +## Extrude the body from the sketch + +Extrude the sketch to create the body and assign a material to it. + +```{code-cell} ipython3 +# Extrude the sketch to create a Body +body = design.extrude_sketch("SingleBody", sketch, Quantity(10, UNITS.mm)) + +# Assign a material to a Body +body.assign_material(material) + +body.plot() +``` \ No newline at end of file diff --git a/doc/source/examples/design_organization.mystnb b/doc/source/examples/design/design_organization.mystnb similarity index 97% rename from doc/source/examples/design_organization.mystnb rename to doc/source/examples/design/design_organization.mystnb index b4b1bd76c9..5060206bc8 100644 --- a/doc/source/examples/design_organization.mystnb +++ b/doc/source/examples/design/design_organization.mystnb @@ -75,7 +75,7 @@ used sketch. double_nested_component = nested_component.add_component("DoubleNestedComponent") circle_surface_body = double_nested_component.create_surface("CircularSurfaceBody", circle_sketch) -circle_surface_body.translate(UNITVECTOR3D_X, Distance(-10, UNITS.mm)) +circle_surface_body.translate(UNITVECTOR3D_X, Distance(-35, UNITS.mm)) design.plot() ``` diff --git a/doc/source/examples/dynamic_sketch_plane.mystnb b/doc/source/examples/design/dynamic_sketch_plane.mystnb similarity index 100% rename from doc/source/examples/dynamic_sketch_plane.mystnb rename to doc/source/examples/design/dynamic_sketch_plane.mystnb diff --git a/doc/source/examples/design/plate_with_hole.mystnb b/doc/source/examples/design/plate_with_hole.mystnb new file mode 100644 index 0000000000..ba9c8f2236 --- /dev/null +++ b/doc/source/examples/design/plate_with_hole.mystnb @@ -0,0 +1,121 @@ +--- +jupytext: + text_representation: + extension: .mystnb + format_name: myst + format_version: 0.13 + jupytext_version: 1.14.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Extrude rectangular plate with multiple bodies + +Multiple bodies can be created from a single sketch by extruding the same sketch in different planes. + +The sketch is designed as an effective fluent-style API with all operations receiving 2D configurations. +To know more about the fluent API, see [Fluent based API in Sketch](../../user_guide/shapes.rst) + +In this example, a box is located in the center of the plate, with the default origin of a sketch plane (origin at (0, 0, 0)). +Four holes of equal radius are sketched at the corners of the plate. +The plate is then extruded, leading to the generation of the requested body. +The projection is at the center of the face. The default projection depth is through the entire part. + ++++ +First, let us import the fundamental objects: + +```{code-cell} ipython3 +import numpy as np +from pint import Quantity + +from ansys.geometry.core import Modeler +from ansys.geometry.core.math import Plane, Point3D, Point2D, UnitVector3D +from ansys.geometry.core.misc import UNITS +from ansys.geometry.core.sketch import Sketch +``` + +## Defining a ``Sketch`` profile for the proposed design + +The profile requires four ``Segments`` which constitute the outer limits of the design, +a ``Box`` on the center and a ``Circle`` at its four corners. + +A single sketch instance can be used for multiple design operations such as extruding a body, +projecting a profile, or imprinting curves. + +```{code-cell} ipython3 +sketch = Sketch() +(sketch.segment(Point2D([-4, 5], unit=UNITS.m), Point2D([4, 5], unit=UNITS.m)) + .segment_to_point(Point2D([4, -5], unit=UNITS.m)) + .segment_to_point(Point2D([-4, -5], unit=UNITS.m)) + .segment_to_point(Point2D([-4, 5], unit=UNITS.m)) + .box(Point2D([0,0], unit=UNITS.m), Quantity(3, UNITS.m), Quantity(3, UNITS.m)) + .circle(Point2D([3, 4], unit=UNITS.m), Quantity(0.5, UNITS.m)) + .circle(Point2D([-3, -4], unit=UNITS.m), Quantity(0.5, UNITS.m)) + .circle(Point2D([-3, 4], unit=UNITS.m), Quantity(0.5, UNITS.m)) + .circle(Point2D([3, -4], unit=UNITS.m), Quantity(0.5, UNITS.m)) +) +``` + +## Create the design by extruding sketch + +A server connection is established and the single sketch profile is used to extrude +the base component at Z axis. A named selection is then created from the +resulting list of bodies. +The design is going to extrude the four segments with desired thickness, just in three server calls. + +```{code-cell} ipython3 +modeler = Modeler() +design = modeler.create_design("ExtrudedPlate") + +body = design.extrude_sketch(f"PlateLayer", sketch, Quantity(2, UNITS.m)) + +board_named_selection = design.create_named_selection("Plate", bodies=[body]) +design.plot() +``` + +## Add new component with planar surface + +We have created a plate as a base component. Let's add a new component with a planar surface to it. +For that, create an instance ``sketch``, and create a surface in the design with that sketch. +For the sketch, we are creating an ellipse keeping the origin of the plane as its center. + +```{code-cell} ipython3 +# Add components to the design +planar_component = design.add_component("PlanarComponent") + +# Initiate ``Sketch`` to create the planar surface. +planar_sketch = Sketch() +planar_sketch.ellipse( + Point2D([0, 0], UNITS.m), Quantity(1, UNITS.m), Quantity(0.5, UNITS.m) + ) + +planar_body = planar_component.create_surface("PlanarComponentSurface", planar_sketch) + +comp_str = repr(planar_component) +design.plot() +``` + +## Extrude from face to create body + +It is possible to extrude a face profile by a given distance to create a new solid body. +There are no modifications against the body containing the source face. + +```{code-cell} ipython3 +longer_body = design.extrude_face( + "LongerEllipseFace", planar_body.faces[0], Quantity(5, UNITS.m) + ) +design.plot() +``` +## Translate the body with in the plane + +By using the translate method, we can move the body in a direction specified by a given distance. +It is also possible to move a sketch around the global coordinate system. See example +[Dynamic Sketch Plane](dynamic_sketch_plane.mystnb). + +```{code-cell} ipython3 +longer_body.translate(UnitVector3D([1, 0, 0]), Quantity(4, UNITS.m)) +design.plot() +``` + diff --git a/doc/source/examples/design/tessellation_usage.mystnb b/doc/source/examples/design/tessellation_usage.mystnb new file mode 100644 index 0000000000..482cce7c02 --- /dev/null +++ b/doc/source/examples/design/tessellation_usage.mystnb @@ -0,0 +1,101 @@ +--- +jupytext: + text_representation: + extension: .mystnb + format_name: myst + format_version: 0.13 + jupytext_version: 1.14.1 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Tessellation of two bodies + +Create two stacked bodies and return the tessellation as two merged bodies. + ++++ +Let's first import the fundamental objects: + +```{code-cell} ipython3 +from pint import Quantity + +from ansys.geometry.core import Modeler +from ansys.geometry.core.math import Point2D, Point3D, Plane +from ansys.geometry.core.misc import UNITS +from ansys.geometry.core.plotting import Plotter. +from ansys.geometry.core.sketch import Sketch + +``` + +## Creating the design + +Create the basic sketches to be tessellated, and extrude the sketch in the required plane. +[Extruded rectangular plate with multiple bodies](plate_with_hole.mystnb) +contains the working example of creating a component and extruding a sketch in the ``design``. + +Here is a typical situation in which two bodies, with different sketch planes, +merge each body into a single dataset. +This effectively combines all the faces of each individual +body into a single dataset without separating faces. + +```{code-cell} ipython3 +modeler = Modeler() + +sketch_1 = Sketch() +box = sketch_1.box( + Point2D([10, 10], unit=UNITS.m), width=Quantity(10, UNITS.m), height=Quantity(5, UNITS.m) +) +circle = sketch_1.circle( + Point2D([0, 0], unit=UNITS.m), radius=Quantity(25, UNITS.m) +) + +design = modeler.create_design("TessellationDesign") +comp = design.add_component("TessellationComponent") +body = comp.extrude_sketch("Body", sketch=sketch_1, distance=10 * UNITS.m) + +# Create the second body in a plane with a different origin +sketch_2 = Sketch(Plane([0, 0, 10])) +box = sketch_2.box(Point2D( + [10, 10], unit=UNITS.m), width=Quantity(10, UNITS.m), height=Quantity(5, UNITS.m) +) +circle = sketch_2.circle( + Point2D([0, 10], unit=UNITS.m), radius=Quantity(25, UNITS.m) +) + +body = comp.extrude_sketch("Body", sketch=sketch_2, distance=10 * UNITS.m) +``` +## Tessellation of the component as two merged bodies + +Tessellate the component and merge each body in to a single dataset, +This effectively combines all the faces of each individual body into a +single dataset without separating faces. + +```{code-cell} ipython3 +dataset = comp.tessellate(merge_bodies=True) +dataset +``` +If you want to tessellate the body and return the geometry as triangles, single body tessellation is also possible. +If you wish to merge the individual faces of the tessellation, enable the +``merge`` option so that the body is rendered into a single mesh. +This preserves the number of triangles and only merges the topology. + +Without merging the body: + +```{code-cell} ipython3 +dataset = body.tessellate() +dataset +``` +Merge the body: + +```{code-cell} ipython3 +mesh = body.tessellate(merge=True) +mesh +``` + +And finally plot to see the design. + +```{code-cell} ipython3 +design.plot() +``` \ No newline at end of file diff --git a/doc/source/user_guide/index.rst b/doc/source/user_guide/index.rst index f3e73d92bd..93479b3f7a 100644 --- a/doc/source/user_guide/index.rst +++ b/doc/source/user_guide/index.rst @@ -27,10 +27,8 @@ PyGeometry is a Python wrapper for the Ansys Geometry Service. The key features Simple interactive example ========================== - -1. Start the Geometry Service instance --------------------------------------- - +Start the Geometry Service instance +----------------------------------- The :class:`Modeler() ` class within the ``ansys-geometry-core`` library creates an instance of @@ -45,10 +43,8 @@ Now, you can start the service with: >>> from ansys.geometry.core import Modeler >>> modeler = Modeler() - -2. Create Geometry models -------------------------- - +Create Geometry models +---------------------- The Geometry Service is now active and you can start creating the geometry model by initializing the :ref:`Sketch ` and :ref:`Primitives `.