######### BuildLine ######### BuildLine is a python context manager that is used to create one dimensional objects - objects with the property of length but not area - that are typically used as part of a BuildSketch sketch or a BuildPart path. The complete API for BuildLine is located at the end of this section. ******************* Basic Functionality ******************* The following is a simple BuildLine example: .. literalinclude:: objects_1d.py :start-after: [Ex. 1] :end-before: [Ex. 1] The ``with`` statement creates the ``BuildLine`` context manager with the identifier ``example_1``. The objects and operations that are within the scope (i.e. indented) of this context will contribute towards the object being created by the context manager. For ``BuildLine``, this object is ``line`` and it's referenced as ``example_1.line``. The first object in this example is a ``Line`` object which is used to create a straight line from coordinates (0,0) to (2,0) on the default XY plane. The second object is a ``ThreePointArc`` that starts and ends at the two ends of the line. .. image:: assets/buildline_example_1.svg :align: center *********** Constraints *********** Building with constraints enables the designer to capture design intent and add a high degree of robustness to their designs. The following sections describe creating positional and tangential constraints as well as using object attributes to enable this type of design. @ ``position_at`` Operator =========================== In the previous example, the ``ThreePointArc`` started and ended at the two ends of the ``Line`` but this was done by referring to the same point ``(0,0)`` and ``(2,0)``. This can be improved upon by specifying constraints that lock the arc to those two end points, as follows: .. literalinclude:: objects_1d.py :start-after: [Ex. 2] :end-before: [Ex. 2] Here instance variables ``l1`` and ``l2`` are assigned to the two BuildLine objects and the ``ThreePointArc`` references the beginning of the straight line with ``l1 @ 0`` and the end with ``l1 @ 1``. The ``@`` operator takes a float (or integer) parameter between 0 and 1 and determines a position at this fractional position along the line's length. This example can be improved on further by calculating the mid-point of the arc as follows: .. literalinclude:: objects_1d.py :start-after: [Ex. 3] :end-before: [Ex. 3] Here ``l1 @ 0.5`` finds the center of ``l1`` while ``l1 @ 0.5 + (0, 1)`` does a vector addition to generate the point ``(1,1)``. To make the design even more parametric, the height of the arc can be calculated from ``l1`` as follows: .. literalinclude:: objects_1d.py :start-after: [Ex. 4] :end-before: [Ex. 4] The arc height is now calculated as ``(0, l1.length / 2)`` by using the ``length`` property of ``Edge`` and ``Wire`` shapes. At this point the ``ThreePointArc`` is fully parametric and able to generate the same shape for any horizontal line. % ``tangent_at`` Operator ========================= The other operator that is commonly used within BuildLine is ``%`` the tangent at operator. Here is another example: .. literalinclude:: objects_1d.py :start-after: [Ex. 5] :end-before: [Ex. 5] which generates (note that the circles show line junctions): .. image:: assets/buildline_example_5.svg :align: center The ``JernArc`` has the following parameters: * ``start=l2 @ 1`` - start the arc at the end of line ``l2``, * ``tangent=l2 % 1`` - the tangent of the arc at the start point is equal to the ``l2``\'s, tangent at its end (shown as a dashed line) * ``radius=0.5`` - the radius of the arc, and * ``arc_size=90`` the angular size of the arc. The final line starts at the end of ``l3`` and ends at a point calculated from the length of ``l2`` and the radius of arc ``l3``. Building with constraints as shown here will ensure that your designs both fully represent design intent and are robust to design changes. ************************ BuildLine to BuildSketch ************************ As mentioned previously, one of the two primary reasons to create BuildLine objects is to use them in BuildSketch. When a BuildLine context manager exits and is within the scope of a BuildSketch context manager it will transfer the generated line to BuildSketch. The BuildSketch :meth:`~operations_sketch.make_face` or :meth:`~operations_sketch.make_hull` operations are then used to transform the line (specifically a list of Edges) into a Face - the native BuildSketch objects. Here is an example of using BuildLine to create an object that otherwise might be difficult to create: .. literalinclude:: objects_1d.py :start-after: [Ex. 6] :end-before: [Ex. 6] which generates: .. image:: assets/buildline_example_6.svg :align: center .. note:: SVG import to BuildLine The BuildLine code used in this example was generated by translating a SVG file into BuildLine source code with the :func:`~importers.import_svg_as_buildline_code` function. For example: .. code:: svg_code, builder_name = import_svg_as_buildline_code("club.svg") would translate the "club.svg" image file's paths into BuildLine code much like that shown above. From there it's easy for a user to add constraints or otherwise enhance the original image and use it in their design. ********************** BuildLine to BuildPart ********************** The other primary reasons to use BuildLine is to create paths for BuildPart :meth:`~operations_generic.sweep` operations. Here some curved and straight segments define a path: .. literalinclude:: objects_1d.py :start-after: [Ex. 7] :end-before: [Ex. 7] which generates: .. image:: assets/buildline_example_7.svg :align: center There are few things to note from this example: * The @ and % operators are used to create a plane normal to the beginning of the path with which to create the circular section used by the sweep operation (this plane is not one of the ordinal planes). * Both the path generated by BuildLine and the section generated by BuildSketch have been transferred to BuildPart when each of them exit. * The BuildPart ``Sweep`` operation is using the path and section previously transferred to it (as "pending" objects) as parameters of the sweep. The ``Sweep`` operation "consumes" these pending objects as to not interfere with subsequence operations. *********************** Working on other Planes *********************** So far all of the examples were created on ``Plane.XY`` - the default plane - which is equivalent to global coordinates. Sometimes it's convenient to work on another plane, especially when creating paths for BuildPart ``Sweep`` operations. .. literalinclude:: objects_1d.py :start-after: [Ex. 8] :end-before: [Ex. 8] which generates: .. image:: assets/buildline_example_8.svg :align: center Here the BuildLine object is created on ``Plane.YZ`` just by specifying the working plane during BuildLine initialization. There are three rules to keep in mind when working with alternate planes in BuildLine: #. ``BuildLine`` accepts a single ``Plane`` to work with as opposed to other Builders that accept more than one workplane. #. Values entered as tuples such as ``(1, 2)`` or ``(1, 2, 3)`` will be localized to the current workplane. This rule applies to points and to the use of tuples to modify locations calculated with the ``@`` and ``%`` operators such as ``l1 @ 1 + (1, 1)``. For example, if the workplane is ``Plane.YZ`` the local value of ``(1, 2)`` would be converted to ``(0, 1, 2)`` in global coordinates. Three tuples are converted as well - ``(1, 2, 3)`` on ``Plane.YZ`` would be ``(3, 1, 2)`` in global coordinates. Providing values in local coordinates allows the designer to automate such conversions. #. Values entered using the ``Vector`` class or those generated by the ``@`` operator are considered global values and are not localized. For example: ``Line(Vector(1, 2, 3), Vector(4, 5, 6))`` will generate the same line independent of the current workplane. It's unlikely that users will need to use ``Vector`` values but the option is there. Finally, BuildLine's workplane need not be one of the predefined ordinal planes, it could be one created from a surface of a BuildPart part that is currently under construction. ********* Reference ********* .. py:module:: build_line .. autoclass:: BuildLine :members: