{ "cells": [ { "cell_type": "markdown", "id": "560e37d3", "metadata": { "tags": [] }, "source": [ "# Groove based workpiece data and geometry\n", "\n", "[<< PREVIOUS TUTORIAL](01_02_time_dependent_data.ipynb) | [NEXT TUTORIAL >>](01_04_coordinate_systems.ipynb)\n", "\n", "## Overview\n", "\n", "**This tutorial covers:**\n", "\n", "Working with workpiece related data that can be described by a 2 dimensional groove and a seam length \n", "\n", "**Requirements:**\n", "\n", "- Opening and navigating through WelDX files ([tutorial](01_01_introduction.ipynb))" ] }, { "cell_type": "code", "execution_count": null, "id": "d093c5f3", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false }, "nbsphinx": "hidden", "tags": [] }, "outputs": [], "source": [ "# download the example file for this tutorial\n", "\n", "from util import download_tutorial_input_file\n", "\n", "download_tutorial_input_file(print_status=False)" ] }, { "cell_type": "markdown", "id": "f70ce1c3", "metadata": { "tags": [] }, "source": [ "## Plotting the specimen's groove\n", "\n", "An important piece that will be part of most WelDX files is the specimen data.\n", "The complexity of a specimen can range from a single metal plate to complex 3 dimensional multi-part structures.\n", "In this tutorial, we will discuss specimen geometries based on a 2-dimensional cross-section that is extruded into 3d space.\n", "\n", "First we open the example file and examine the workpiece information." ] }, { "cell_type": "code", "execution_count": null, "id": "53db4790", "metadata": {}, "outputs": [], "source": [ "from weldx import WeldxFile\n", "\n", "wxfile = WeldxFile(\"single_pass_weld.wx\")" ] }, { "cell_type": "code", "execution_count": null, "id": "c17c9384", "metadata": {}, "outputs": [], "source": [ "wxfile.info(path=(\"workpiece\",))" ] }, { "cell_type": "markdown", "id": "67f00449", "metadata": {}, "source": [ "The workpiece data of this particular file consists of two parts:\n", "\n", "- `base_metal`\n", "- `geometry`\n", "\n", "The `base_metal` field contains information about the composition of the specimens material, which is not relevant for this tutorial.\n", "We are only interested in the `geometry` section that is further divided into: \n", "\n", "- `groove_shape`\n", "- `seam_length`\n", "\n", "`groove_shape` describes the 2 dimensional cross-section of the specimen.\n", "We can already see, that it is of type `VGroove`.\n", "This object is based on the V-Groove described by ISO 9692-1.\n", "The norm specifies the shape of the groove by different shape parameters.\n", "We could now inspect the different parameter values and look up what meaning they have.\n", "However, this would be rather tedious.\n", "A much simpler way is to use the `plot` method of the groove object:" ] }, { "cell_type": "code", "execution_count": null, "id": "86a372ed", "metadata": {}, "outputs": [], "source": [ "groove = wxfile[\"workpiece\"][\"geometry\"][\"groove_shape\"]\n", "groove.plot()" ] }, { "cell_type": "markdown", "id": "eb8569db", "metadata": {}, "source": [ "Apart from the visual representation, the plot also contains all relevant information like the groove's area and the ISO 9692-1 parameters.\n", "\n", "## Other cross-sections\n", "\n", "Not all specimens might have a cross-section that is described by a norm, or the norm it uses might simply be not considered in the WelDX API.\n", "For such cases, WelDX provides a more generalized class called `Profile`.\n", "It allows us to define arbitrary cross-sections based on simple geometric elements such as lines and arcs.\n", "So be aware, that you might get a `Profile` instead one of the available groove types out of a WelDX file.\n", "In fact, all groove types are based on the `Profile` class, and we can convert them with the `to_profile` method:" ] }, { "cell_type": "code", "execution_count": null, "id": "891f6e00", "metadata": {}, "outputs": [], "source": [ "profile = groove.to_profile()\n", "type(profile)" ] }, { "cell_type": "markdown", "id": "4934eff7", "metadata": {}, "source": [ "We can plot the content of a `Profile` the same way as we did before with the groove:" ] }, { "cell_type": "code", "execution_count": null, "id": "3e228db8", "metadata": {}, "outputs": [], "source": [ "profile.plot()" ] }, { "cell_type": "markdown", "id": "e9e6e106", "metadata": {}, "source": [ "The only difference here is that we don't get the additional, norm-related information." ] }, { "cell_type": "markdown", "id": "be0ece42", "metadata": {}, "source": [ "## 3d plot (matplotlib)\n", "\n", "We can also create a nice 3d plot from the groove and the seam length stored in the WelDX file.\n", "All we need for this is the `Geometry` class of WelDX.\n", "It can be created from a groove or profile and a length:" ] }, { "cell_type": "code", "execution_count": null, "id": "af4dbfd5", "metadata": {}, "outputs": [], "source": [ "from weldx import Geometry, LinearHorizontalTraceSegment, Trace\n", "\n", "t = Trace(LinearHorizontalTraceSegment(wxfile[\"workpiece\"][\"geometry\"][\"seam_length\"]))\n", "geometry = Geometry(groove, t)" ] }, { "cell_type": "markdown", "id": "01bab142", "metadata": {}, "source": [ "Now all that remains, you might have guessed it, is to call the plot method:\n", "\n", "> HINT: Uncomment the code in the next cell to enable interactive plots in jupyter notebooks" ] }, { "cell_type": "code", "execution_count": null, "id": "f3dfccb2", "metadata": {}, "outputs": [], "source": [ "# %matplotlib widget" ] }, { "cell_type": "code", "execution_count": null, "id": "65191790", "metadata": {}, "outputs": [], "source": [ "geometry.plot()" ] }, { "cell_type": "markdown", "id": "b709733d", "metadata": {}, "source": [ "By default, the `plot` method shows us the triangulatad data.\n", "But you can also choose to only plot the control points.\n", "This can be achieved by setting the `show_wireframe` parameter to `False`:" ] }, { "cell_type": "code", "execution_count": null, "id": "f4582e66", "metadata": {}, "outputs": [], "source": [ "geometry.plot(show_wireframe=False)" ] }, { "cell_type": "markdown", "id": "8b1138de", "metadata": {}, "source": [ "The density of the triangle mesh or the point cloud can be controlled py the parameters `profile_raster_width` and `trace_raster_width`.\n", "The first one sets the point density of the individual profiles, while the value of the second one influences, how many profiles are actually drawn.\n", "Both parameters need to be specified as `pint.Quantity`.\n", "You can simply import `Q_` from `weldx` to use quantities or write them as unit string.\n", "Both methods are depicted in the code section below:" ] }, { "cell_type": "code", "execution_count": null, "id": "6845d5a0", "metadata": {}, "outputs": [], "source": [ "from weldx import Q_\n", "\n", "geometry.plot(\n", " profile_raster_width=Q_(0.25, \"mm\"), trace_raster_width=\"17cm\", show_wireframe=False\n", ")" ] }, { "cell_type": "markdown", "id": "23a20417", "metadata": {}, "source": [ "As you can see, we now got only 3 densely rendered profiles.\n", "Try some other values to figure out which setting suits you most.\n", "\n", "The last command also demonstrates two different ways to provide a Quantity to function that expects.\n", "We can either construct a quantity from a value and a unit like `Q_(0.25, \"mm\")` or we can combine value and unit in a string as `17cm`.\n", "The second approach does not require us to import `Q_` but it is limited to scalar values and only works for function parameters.\n", "\n", "Another noteworthy thing we did in the last command is using length units of different magnitude (`mm` and `cm`).\n", "This is totally fine since `weldx` can handle all necessary conversions internally by utilizing the powerful [Python package `pint`](https://pint.readthedocs.io/en/stable/)\n" ] }, { "cell_type": "markdown", "id": "80b188c8", "metadata": {}, "source": [ "## 3d plot (k3d)\n", "\n", "In the previous section we learned how to generate simple 3d-plots from a groove and a seam length using the `plot` method.\n", "By default, `plot` relies on matplotlib as rendering backend.\n", "We have already mentioned before that this is not ideal for 3d renderings.\n", "Therefore, the `weldx` package offers an alternative for jupyter notebook users.\n", "You can select the `k3d` package as rendering backend as follows:\n" ] }, { "cell_type": "code", "execution_count": null, "id": "44309020", "metadata": {}, "outputs": [], "source": [ "geometry.plot(backend=\"k3d\")" ] }, { "cell_type": "markdown", "id": "439602f5", "metadata": {}, "source": [ "Now we got a nice 3d rendering of the geometry with a closed surface that we shift and turn as we like.\n", "However, because `k3d` uses equal axis scaling, we notice that the specimen appears to be rather slim.\n", "The reason for this is that the provided groove types only specify the shape of the groove and not the actual specimen width.\n", "But we can provide one during creation of the geometry using the `width` parameter.\n", "Note that this only works with groove types and not with a plain `Profile`." ] }, { "cell_type": "code", "execution_count": null, "id": "11aa5d7f", "metadata": {}, "outputs": [], "source": [ "geometry_2 = Geometry(groove, t, width=\"20cm\")" ] }, { "cell_type": "markdown", "id": "fd006d4d", "metadata": {}, "source": [ "Now lets plot the geometry again:" ] }, { "cell_type": "code", "execution_count": null, "id": "e871f6d2", "metadata": {}, "outputs": [], "source": [ "geometry_2.plot(profile_raster_width=\"5mm\", trace_raster_width=\"16cm\", backend=\"k3d\")" ] }, { "cell_type": "markdown", "id": "1193aded", "metadata": {}, "source": [ "## Export 3d geometry into a CAD file\n", "\n", "The `Geometry` class also features a `to_file` method.\n", "It allows you to export the 3d data to different file formats like `.ply` or `.stl`.\n", "Using this function, you can inspect the geometry in a CAD program or model viewer of your choice:" ] }, { "cell_type": "code", "execution_count": null, "id": "5ab72220", "metadata": {}, "outputs": [], "source": [ "geometry.to_file(\n", " \"weldx_geometry.stl\", profile_raster_width=\"5mm\", trace_raster_width=\"50mm\"\n", ")" ] }, { "cell_type": "markdown", "id": "1ca3ff56", "metadata": {}, "source": [ "The parameters `profile_raster_width` and `trace_raster_width` do have the exact same effect as in the `plot` method described before." ] }, { "cell_type": "markdown", "id": "b9d7cd9c", "metadata": {}, "source": [ "## Conclusion\n", "\n", "In this tutorial we have learned that WelDX can store geometrical data in form of a 2d-cross section and an extrusion length.\n", "The 2d cross-section can either be of a specialized groove type or a more general `Profile`.\n", "Both can be visualized using the `plot` function and turned into an actual 3d geometry using the `Geometry` class.\n", "The `Geometry` class itself can also be rendered in a 3d plot and exported to a CAD compatible file format.\n", "\n", "## Further Readings\n", "\n", "- [Supported Groove Types](https://weldx.readthedocs.io/en/latest/tutorials/groove_types_01.html)\n", "- [API tutorial: 3d Geometries](https://weldx.readthedocs.io/en/latest/tutorials/geometry_02_geometry.html)\n", "\n", "[<< PREVIOUS TUTORIAL](01_02_time_dependent_data.ipynb) | [NEXT TUTORIAL >>](01_04_coordinate_systems.ipynb)" ] }, { "cell_type": "code", "execution_count": null, "id": "ab3b4f72", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "", "language": "python", "name": "" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.5" } }, "nbformat": 4, "nbformat_minor": 5 }