laser-util-api


Namelaser-util-api JSON
Version 0.2.1 PyPI version JSON
download
home_pageNone
SummaryA simple Python API for the Laser Utility project
upload_time2024-09-05 04:33:41
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT License Copyright (c) 2024 Matthew Jarvis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Python API for Laser Utility

This is a public Python API for the *Laser Utility* program.

When running, *Laser Utility* hosts a local JSON-RPC over TCP server bound to a local port on the loopback address.  This API provides a series of constructs which allow you to work with the internal state of the software with a native feel in Python.  Internally, the various API objects are maintaining state in order to provide the appearance of a shared application domain, while instead transforming actions into discrete JSON-RPC calls.

## Installation

Install the `laser-util-api` package from PyPi.  For example, using `pip`:

```bash
pip install laser-util-api
```

## General Connection and Client Settings
To connect to the API, the *Laser Utility* program must be running.  In the lower left corner of the software, the RPC server port will be displayed next to a green circle.  The default port is 5000, but concurrent open windows will take the next available port in ascending order.

If no arguments are supplied, the client will default to port 5000 and length units of millimeters.

```python
from laser_util_api import ApiClient

client = ApiClient()
```

Alternatively, port and units can be specified.

```python
from laser_util_api import ApiClient, Units

client = ApiClient(port=5001, units=Units.INCHES)
```

## Project-Level Functions

Project level functions allow things like saving, loading, and creating new projects, and finding the project name and path.

Saving a project:

```python 
from laser_util_api import ApiClient
from pathlib import Path

save_dir = Path("D:\\temp\\laser")

client = ApiClient()

# This will add the correct extension if the path does not end with it already
client.project.save_as(save_dir / "test")
```

Loading a project.  *Be warned, the API will not check to see if you want to discard unsaved changes before throwing away the current session*.

```python 
save_dir = Path("D:\\temp\\laser")
client = ApiClient()

client.project.open(save_dir / "test.lsrwk")
```

Creating a new project.  *Be warned, the API will not check to see if you want to discard unsaved changes before throwing away the current session*.

```python 
client = ApiClient()

client.project.new()
```

We can also check the name and the path of the currently open project.

```python 
client = ApiClient()

print(client.project.path())
print(client.project.name())
```

## Work Settings Functions

Work settings functions control things like the selected material, the kerf, and fonts.  They are accessed through the `work_settings` category of the client.

### Materials

The options in the material library can be retrieved and examined.

```python
from laser_util_api import ApiClient, Units

client = ApiClient(units=Units.INCHES)

options = client.work_settings.material_options()
for mat in options:
    print(mat)
    print(f" {mat.category}, {mat.material}, {mat.thickness:0.3f}, {mat.kerf:0.3f}")
```

The active material can be retrieved.

```python
from laser_util_api import ApiClient, Units

client = ApiClient(units=Units.INCHES)
active = client.work_settings.active_material()
print(active)
```

Finally, any material option object can be set as active.

```python
from laser_util_api import ApiClient, Units

client = ApiClient(units=Units.INCHES)

options = client.work_settings.material_options()

# Just set the last one active, as an example.
options[-1].set_active()
```

### Kerf

The kerf is the width of the cut made by the laser.  Boundaries are offset by half of the kerf width before they're cut.  The kerf is a property of the active material option, but it can be overridden in the software to make small adjustments.  A larger kerf makes a larger part, while a smaller kerf makes a smaller part.

The kerf can be read directly, and will come through in the client's units.

```python
client = ApiClient(units=Units.INCHES)

print(client.work_settings.kerf)
```

The kerf override can be read and set as if it were a property of `client.work_settings`.

```python
client = ApiClient(units=Units.INCHES)

print(client.work_settings.kerf_override)

client.work_settings.kerf_override = True
```

The kerf can only be set if it is overridden.  Setting the kerf is straightforward, but will throw an exception if the kerf override is not active.

```python
client = ApiClient(units=Units.INCHES)

# This will throw an exception if the kerf override is not on
client.work_settings.kerf = 0.1
```

### Fonts

In the work settings there is a library of fonts used for etching.  Each font has an integer ID number, a font family, and a font size.  Fonts are referenced by their ID when creating a text etch element, allowing all text with that font ID to be adjusted at once.  Fonts can be examined, modified, added, and removed through the API.

Getting a list of the active font options is done as follows:

```python
client = ApiClient()

fonts = client.work_settings.fonts()
for font in fonts:
    print(font)
```

Each font item allows the family and size to be edited.  The family is set as a string of the family name, if the family name does not exist on the system setting it will throw an exception.

```python
client = ApiClient()

font = client.work_settings.fonts()[0]
font.size = 16
font.family = "Courier New"
```

The list of valid font family names on the system can be retrieved as shown:

```python
client = ApiClient()

for name in client.work_settings.get_system_font_families():
    print(name)
```

A new font can be created using the `create_font` method, and then edited the same way as any other font.

```python
client = ApiClient()

font = client.work_settings.create_font()
font.size = 20
```

A font can be located by its ID.  If the ID does not exist, an exception will be thrown.

```python
client = ApiClient()

font = client.work_settings.find_font(2)
```

A font can be deleted if it is not the last font left.

```python
client = ApiClient()

font = client.work_settings.find_font(2)
font.delete()
```

## Project Tree Functions

The project tree is the bar on the left side of the *Laser Utility* GUI which shows the different entities in the project.  A subset of these entities can be interacted with through the Python API using the `tree` category of the client.

Project tree items which can be interacted with are the ones based on the common workspace entity format.  Most project items which have a name, an origin, visibility, for-construction, etc, can be worked with through the API.

### Listing and Finding Project Tree Items

You can iterate directly through the `.tree` category.

```python
client = ApiClient()

for item in client.tree:
    print(item)
```

You can also index into the client tree.  Using an integer will return the item by position, specifying a `UUID` or a string that converts into a `UUID` will directly search the tree using an API call.  Finally, if given a string that can't be converted into a `UUID`, the client will check every project item to see if it's ID starts with the specified text.

```python
client = ApiClient()

# Get the first item in the tree
item = client.tree[0]

# Get the item with the specified ID
item = client.tree["384b9cdd-14bb-4099-82ed-3df3a16015c5"]
item = client.tree[UUID("384b9cdd-14bb-4099-82ed-3df3a16015c5")]

# Search for the item with an ID starting with the following text
item = client.tree["384b9"]
```

Finally, project items can be retrieved based on tags.

```python
client = ApiClient()

# Get a list of project items that have the given tag.
items = client.tree.with_tag("my tag")
```

### Editing Tags

Tags are a feature to help Python scripts label and track project items.  They do not currently appear in the UI.

Tags can be added or removed from items using the following methods:

```python
client = ApiClient()

# Get the first item in the tree, just for demonstration purposes
item = client.tree[0]

# Add a tag
item.add_tag("TEST")
print(item.tags)

# Remove the tag
item.remove_tag("TEST")
print(item.tags)
```

### Editing Basic Properties

Special project tree items have additional properties, but most items have at least the following.

Setting the name, visibility, drag lock, and construction states of an item.

```python
client = ApiClient()
item = client.tree[0]

# Retrieve and set the name
print(item.name)
item.name = "Name Changed from API"

# Retrieve and set the visibility
print(item.visible)
item.visible = False

# Retrieve and set the drag lock
print(item.drag_locked)
item.drag_locked = True

# Retrieve and set the for-construction (suppression) property
print(item.for_construction)
item.for_construction = True
```

The origin X-Y-R can also be set.  The rotation is always in radians.

```python
import math
from laser_util_api import ApiClient, Xyr

client = ApiClient()
item = client.tree[0]

# Change the value of its origin position
item.origin = Xyr(100, 200, math.pi / 2)
```

The origin parent can be set to another project item, or set back to `None` to reference the workspace origin.

```python
import math
from laser_util_api import ApiClient, Xyr

client = ApiClient()
item = client.tree[0]       # Grab the first item in the tree
parent = client.tree[-1]    # Grab the last item in the tree

# Set the parent of the origin to the last item in the list 
item.origin_parent = parent

# Set the origin parent back to the workspace origin
item.origin_parent = None
```

### Deleting

Items can be deleted through acquiring their handle and using the `.delete()` method.

```python
client = ApiClient()
item = client.tree[0]

item.delete()
```

## The Scratch Workspaces

There are two scratch workspaces where you can create boundary loops and bodies.  These workspaces are created when the client connects to the application and are disposed when the client disconnects.  Things created in the scratch workspaces are unique to the client and not preserved between sessions.

Items in the scratch workspace can be used to create project items.

#### Loops

There are several ways of creating boundary loops in the scratch workspace.  Each will return a `LoopHandle` object, which will allow further modifications to the loop.

```python
from laser_util_api import ApiClient, Vector

client = ApiClient()

# Create a rectangle whose top-left corner is at x=1, y=2, with width=3 and height=4
rect = client.scratch.loops.rectangle(Vector(1, 2), 3, 4)

# Create a rounded rectangle of the same parameters, but with corner radius 0.25
rnd_rect = client.scratch.loops.rounded_rectangle(Vector(1, 2), 3, 4, 0.25)

# Create a circle at x=1, y=2, with radius=3
circle = client.scratch.loops.circle(Vector(1, 2), 3)

# Reverse the circle direction, turning it into a negative boundary
circle.reverse()

# Create an empty loop, then use the cursor to insert a pill shape.  Each element added to the boundary (segment or
# arc) has the *start* point defined, and will run until it hits the start point of the *next* element.  For arcs, the
# circle center must be equidistant from the arc start point and the start point of the next element.
pill = client.scratch.loops.create()
pill.insert_seg_abs(Vector(0, 0))
pill.insert_arc_abs(Vector(1, 0), Vector(1, 1), False)
pill.insert_seg_abs(Vector(1, 2))
pill.insert_arc_abs(Vector(0, 2), Vector(0, 1), False)
```

#### Bodies

A body can be created from an initial boundary loop (must be positive), and then modified through shape operations performed with more boundary loops.

To create a basic boundary loop, first let's use a circle.

```python
from laser_util_api import ApiClient, Vector

client = ApiClient()

# Create a circle boundary at 0, 0 with radius 1
circle = client.scratch.loops.circle(Vector(0, 0), 1)

# Now create a body from the circle.
body = client.scratch.bodies.create(circle)

# Now create a rectangular cut to take out of it.
cut0 = client.scratch.loops.rectangle(Vector(0, -0.5), 2, 1)
cut0.reverse()
body.operate(cut0)

# Now create a positive protrusion to add to the top
pos0 = client.scratch.loops.circle(Vector(0, 1), 0.375)
body.operate(pos0)
```

## Creating Project Items

For now, body and etch project items can be created through the API.  Both are accessible through the `create` category of the client.

### Body Project Item

Creating an actual project item from a body can be done using either a loop or a body.  Both will be immutable after creation, but will persist after the client program ends.

```python
client = ApiClient(units=Units.INCHES)

# Create a circle boundary at 0, 0 with radius 1
circle = client.scratch.loops.circle(Vector(0, 0), 1)

# Create a circle body project item from the circle loop.
circle_body = client.create.body(circle)
circle_body.name = "Body Item from Boundary Loop"

# Now we'll create a body with a cut from the circle and use it to create a more complex body project item
body = client.scratch.bodies.create(circle)
cut0 = client.scratch.loops.rectangle(Vector(0, -0.5), 2, 1)
cut0.reverse()
body.operate(cut0)

complex_body = client.create.body(body)
complex_body.name = "Body Item from Body"
```

### Creating and Editing an Etch Project Item

Etch project items can have text and lines.  The following is an example of creating graduated scale marks.

```python
from laser_util_api import import ApiClient, Vector, Units, HAlign, VAlign

client = ApiClient(units=Units.INCHES)

# Create the etch entity
etch = client.create.etch()
etch.name = "Example Etch Markings"

# From a corner at 1, 2 inches, we'll put marks every 1/2 inch
corner = Vector(1, 2)

for i in range(5):
    mark = corner + Vector(0.5, 0) * i

    # Create a vertical line starting at the mark point, 0.25 in tall, with a width of 0.01 inches
    etch.add_line(mark, mark + Vector(0, 0.25), 0.01)

    # Create a text item horizontally centered at the mark, up 0.25 inches. See the
    # function documentation for details
    etch.add_text(mark - Vector(0, 0.25), 0, f"{i + 1}", 1, VAlign.CENTER, HAlign.CENTER)
```

Adding a large amount of items to an etch feature can involve a lot of back and forth traffic and waiting while the user interface updates.  Transactions consisting of many batched etch entities can be created using the `with` syntax.  The transaction object (`t` in the example below) has the same features as the etch object in the example above, except that it is caching the operations instead of performing them.  When the context manager ends as the program exits the scope of the `with` block, a single large transaction will be performed creating all the cached elements at once.

```python
from laser_util_api import import ApiClient, Vector

client = ApiClient(units=Units.INCHES)

# Create the etch entity
etch = client.create.etch()
etch.name = "Example Etch Markings"

# We're going to create a grid pattern of hatch marks, spaced every inch.
with etch.transaction() as t:
    for i in range(10):
        for j in range(10):
            x = i + 0.5
            y = j + 0.5
            t.add_line(Vector(x - 0.125, y), Vector(x + 0.125, y), 0.02)
            t.add_line(Vector(x, y - 0.125), Vector(x, y + 0.125), 0.02)
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "laser-util-api",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": null,
    "author": null,
    "author_email": "Matt Jarvis <mattj23@gmail.com>",
    "download_url": null,
    "platform": null,
    "description": "# Python API for Laser Utility\n\nThis is a public Python API for the *Laser Utility* program.\n\nWhen running, *Laser Utility* hosts a local JSON-RPC over TCP server bound to a local port on the loopback address.  This API provides a series of constructs which allow you to work with the internal state of the software with a native feel in Python.  Internally, the various API objects are maintaining state in order to provide the appearance of a shared application domain, while instead transforming actions into discrete JSON-RPC calls.\n\n## Installation\n\nInstall the `laser-util-api` package from PyPi.  For example, using `pip`:\n\n```bash\npip install laser-util-api\n```\n\n## General Connection and Client Settings\nTo connect to the API, the *Laser Utility* program must be running.  In the lower left corner of the software, the RPC server port will be displayed next to a green circle.  The default port is 5000, but concurrent open windows will take the next available port in ascending order.\n\nIf no arguments are supplied, the client will default to port 5000 and length units of millimeters.\n\n```python\nfrom laser_util_api import ApiClient\n\nclient = ApiClient()\n```\n\nAlternatively, port and units can be specified.\n\n```python\nfrom laser_util_api import ApiClient, Units\n\nclient = ApiClient(port=5001, units=Units.INCHES)\n```\n\n## Project-Level Functions\n\nProject level functions allow things like saving, loading, and creating new projects, and finding the project name and path.\n\nSaving a project:\n\n```python \nfrom laser_util_api import ApiClient\nfrom pathlib import Path\n\nsave_dir = Path(\"D:\\\\temp\\\\laser\")\n\nclient = ApiClient()\n\n# This will add the correct extension if the path does not end with it already\nclient.project.save_as(save_dir / \"test\")\n```\n\nLoading a project.  *Be warned, the API will not check to see if you want to discard unsaved changes before throwing away the current session*.\n\n```python \nsave_dir = Path(\"D:\\\\temp\\\\laser\")\nclient = ApiClient()\n\nclient.project.open(save_dir / \"test.lsrwk\")\n```\n\nCreating a new project.  *Be warned, the API will not check to see if you want to discard unsaved changes before throwing away the current session*.\n\n```python \nclient = ApiClient()\n\nclient.project.new()\n```\n\nWe can also check the name and the path of the currently open project.\n\n```python \nclient = ApiClient()\n\nprint(client.project.path())\nprint(client.project.name())\n```\n\n## Work Settings Functions\n\nWork settings functions control things like the selected material, the kerf, and fonts.  They are accessed through the `work_settings` category of the client.\n\n### Materials\n\nThe options in the material library can be retrieved and examined.\n\n```python\nfrom laser_util_api import ApiClient, Units\n\nclient = ApiClient(units=Units.INCHES)\n\noptions = client.work_settings.material_options()\nfor mat in options:\n    print(mat)\n    print(f\" {mat.category}, {mat.material}, {mat.thickness:0.3f}, {mat.kerf:0.3f}\")\n```\n\nThe active material can be retrieved.\n\n```python\nfrom laser_util_api import ApiClient, Units\n\nclient = ApiClient(units=Units.INCHES)\nactive = client.work_settings.active_material()\nprint(active)\n```\n\nFinally, any material option object can be set as active.\n\n```python\nfrom laser_util_api import ApiClient, Units\n\nclient = ApiClient(units=Units.INCHES)\n\noptions = client.work_settings.material_options()\n\n# Just set the last one active, as an example.\noptions[-1].set_active()\n```\n\n### Kerf\n\nThe kerf is the width of the cut made by the laser.  Boundaries are offset by half of the kerf width before they're cut.  The kerf is a property of the active material option, but it can be overridden in the software to make small adjustments.  A larger kerf makes a larger part, while a smaller kerf makes a smaller part.\n\nThe kerf can be read directly, and will come through in the client's units.\n\n```python\nclient = ApiClient(units=Units.INCHES)\n\nprint(client.work_settings.kerf)\n```\n\nThe kerf override can be read and set as if it were a property of `client.work_settings`.\n\n```python\nclient = ApiClient(units=Units.INCHES)\n\nprint(client.work_settings.kerf_override)\n\nclient.work_settings.kerf_override = True\n```\n\nThe kerf can only be set if it is overridden.  Setting the kerf is straightforward, but will throw an exception if the kerf override is not active.\n\n```python\nclient = ApiClient(units=Units.INCHES)\n\n# This will throw an exception if the kerf override is not on\nclient.work_settings.kerf = 0.1\n```\n\n### Fonts\n\nIn the work settings there is a library of fonts used for etching.  Each font has an integer ID number, a font family, and a font size.  Fonts are referenced by their ID when creating a text etch element, allowing all text with that font ID to be adjusted at once.  Fonts can be examined, modified, added, and removed through the API.\n\nGetting a list of the active font options is done as follows:\n\n```python\nclient = ApiClient()\n\nfonts = client.work_settings.fonts()\nfor font in fonts:\n    print(font)\n```\n\nEach font item allows the family and size to be edited.  The family is set as a string of the family name, if the family name does not exist on the system setting it will throw an exception.\n\n```python\nclient = ApiClient()\n\nfont = client.work_settings.fonts()[0]\nfont.size = 16\nfont.family = \"Courier New\"\n```\n\nThe list of valid font family names on the system can be retrieved as shown:\n\n```python\nclient = ApiClient()\n\nfor name in client.work_settings.get_system_font_families():\n    print(name)\n```\n\nA new font can be created using the `create_font` method, and then edited the same way as any other font.\n\n```python\nclient = ApiClient()\n\nfont = client.work_settings.create_font()\nfont.size = 20\n```\n\nA font can be located by its ID.  If the ID does not exist, an exception will be thrown.\n\n```python\nclient = ApiClient()\n\nfont = client.work_settings.find_font(2)\n```\n\nA font can be deleted if it is not the last font left.\n\n```python\nclient = ApiClient()\n\nfont = client.work_settings.find_font(2)\nfont.delete()\n```\n\n## Project Tree Functions\n\nThe project tree is the bar on the left side of the *Laser Utility* GUI which shows the different entities in the project.  A subset of these entities can be interacted with through the Python API using the `tree` category of the client.\n\nProject tree items which can be interacted with are the ones based on the common workspace entity format.  Most project items which have a name, an origin, visibility, for-construction, etc, can be worked with through the API.\n\n### Listing and Finding Project Tree Items\n\nYou can iterate directly through the `.tree` category.\n\n```python\nclient = ApiClient()\n\nfor item in client.tree:\n    print(item)\n```\n\nYou can also index into the client tree.  Using an integer will return the item by position, specifying a `UUID` or a string that converts into a `UUID` will directly search the tree using an API call.  Finally, if given a string that can't be converted into a `UUID`, the client will check every project item to see if it's ID starts with the specified text.\n\n```python\nclient = ApiClient()\n\n# Get the first item in the tree\nitem = client.tree[0]\n\n# Get the item with the specified ID\nitem = client.tree[\"384b9cdd-14bb-4099-82ed-3df3a16015c5\"]\nitem = client.tree[UUID(\"384b9cdd-14bb-4099-82ed-3df3a16015c5\")]\n\n# Search for the item with an ID starting with the following text\nitem = client.tree[\"384b9\"]\n```\n\nFinally, project items can be retrieved based on tags.\n\n```python\nclient = ApiClient()\n\n# Get a list of project items that have the given tag.\nitems = client.tree.with_tag(\"my tag\")\n```\n\n### Editing Tags\n\nTags are a feature to help Python scripts label and track project items.  They do not currently appear in the UI.\n\nTags can be added or removed from items using the following methods:\n\n```python\nclient = ApiClient()\n\n# Get the first item in the tree, just for demonstration purposes\nitem = client.tree[0]\n\n# Add a tag\nitem.add_tag(\"TEST\")\nprint(item.tags)\n\n# Remove the tag\nitem.remove_tag(\"TEST\")\nprint(item.tags)\n```\n\n### Editing Basic Properties\n\nSpecial project tree items have additional properties, but most items have at least the following.\n\nSetting the name, visibility, drag lock, and construction states of an item.\n\n```python\nclient = ApiClient()\nitem = client.tree[0]\n\n# Retrieve and set the name\nprint(item.name)\nitem.name = \"Name Changed from API\"\n\n# Retrieve and set the visibility\nprint(item.visible)\nitem.visible = False\n\n# Retrieve and set the drag lock\nprint(item.drag_locked)\nitem.drag_locked = True\n\n# Retrieve and set the for-construction (suppression) property\nprint(item.for_construction)\nitem.for_construction = True\n```\n\nThe origin X-Y-R can also be set.  The rotation is always in radians.\n\n```python\nimport math\nfrom laser_util_api import ApiClient, Xyr\n\nclient = ApiClient()\nitem = client.tree[0]\n\n# Change the value of its origin position\nitem.origin = Xyr(100, 200, math.pi / 2)\n```\n\nThe origin parent can be set to another project item, or set back to `None` to reference the workspace origin.\n\n```python\nimport math\nfrom laser_util_api import ApiClient, Xyr\n\nclient = ApiClient()\nitem = client.tree[0]       # Grab the first item in the tree\nparent = client.tree[-1]    # Grab the last item in the tree\n\n# Set the parent of the origin to the last item in the list \nitem.origin_parent = parent\n\n# Set the origin parent back to the workspace origin\nitem.origin_parent = None\n```\n\n### Deleting\n\nItems can be deleted through acquiring their handle and using the `.delete()` method.\n\n```python\nclient = ApiClient()\nitem = client.tree[0]\n\nitem.delete()\n```\n\n## The Scratch Workspaces\n\nThere are two scratch workspaces where you can create boundary loops and bodies.  These workspaces are created when the client connects to the application and are disposed when the client disconnects.  Things created in the scratch workspaces are unique to the client and not preserved between sessions.\n\nItems in the scratch workspace can be used to create project items.\n\n#### Loops\n\nThere are several ways of creating boundary loops in the scratch workspace.  Each will return a `LoopHandle` object, which will allow further modifications to the loop.\n\n```python\nfrom laser_util_api import ApiClient, Vector\n\nclient = ApiClient()\n\n# Create a rectangle whose top-left corner is at x=1, y=2, with width=3 and height=4\nrect = client.scratch.loops.rectangle(Vector(1, 2), 3, 4)\n\n# Create a rounded rectangle of the same parameters, but with corner radius 0.25\nrnd_rect = client.scratch.loops.rounded_rectangle(Vector(1, 2), 3, 4, 0.25)\n\n# Create a circle at x=1, y=2, with radius=3\ncircle = client.scratch.loops.circle(Vector(1, 2), 3)\n\n# Reverse the circle direction, turning it into a negative boundary\ncircle.reverse()\n\n# Create an empty loop, then use the cursor to insert a pill shape.  Each element added to the boundary (segment or\n# arc) has the *start* point defined, and will run until it hits the start point of the *next* element.  For arcs, the\n# circle center must be equidistant from the arc start point and the start point of the next element.\npill = client.scratch.loops.create()\npill.insert_seg_abs(Vector(0, 0))\npill.insert_arc_abs(Vector(1, 0), Vector(1, 1), False)\npill.insert_seg_abs(Vector(1, 2))\npill.insert_arc_abs(Vector(0, 2), Vector(0, 1), False)\n```\n\n#### Bodies\n\nA body can be created from an initial boundary loop (must be positive), and then modified through shape operations performed with more boundary loops.\n\nTo create a basic boundary loop, first let's use a circle.\n\n```python\nfrom laser_util_api import ApiClient, Vector\n\nclient = ApiClient()\n\n# Create a circle boundary at 0, 0 with radius 1\ncircle = client.scratch.loops.circle(Vector(0, 0), 1)\n\n# Now create a body from the circle.\nbody = client.scratch.bodies.create(circle)\n\n# Now create a rectangular cut to take out of it.\ncut0 = client.scratch.loops.rectangle(Vector(0, -0.5), 2, 1)\ncut0.reverse()\nbody.operate(cut0)\n\n# Now create a positive protrusion to add to the top\npos0 = client.scratch.loops.circle(Vector(0, 1), 0.375)\nbody.operate(pos0)\n```\n\n## Creating Project Items\n\nFor now, body and etch project items can be created through the API.  Both are accessible through the `create` category of the client.\n\n### Body Project Item\n\nCreating an actual project item from a body can be done using either a loop or a body.  Both will be immutable after creation, but will persist after the client program ends.\n\n```python\nclient = ApiClient(units=Units.INCHES)\n\n# Create a circle boundary at 0, 0 with radius 1\ncircle = client.scratch.loops.circle(Vector(0, 0), 1)\n\n# Create a circle body project item from the circle loop.\ncircle_body = client.create.body(circle)\ncircle_body.name = \"Body Item from Boundary Loop\"\n\n# Now we'll create a body with a cut from the circle and use it to create a more complex body project item\nbody = client.scratch.bodies.create(circle)\ncut0 = client.scratch.loops.rectangle(Vector(0, -0.5), 2, 1)\ncut0.reverse()\nbody.operate(cut0)\n\ncomplex_body = client.create.body(body)\ncomplex_body.name = \"Body Item from Body\"\n```\n\n### Creating and Editing an Etch Project Item\n\nEtch project items can have text and lines.  The following is an example of creating graduated scale marks.\n\n```python\nfrom laser_util_api import import ApiClient, Vector, Units, HAlign, VAlign\n\nclient = ApiClient(units=Units.INCHES)\n\n# Create the etch entity\netch = client.create.etch()\netch.name = \"Example Etch Markings\"\n\n# From a corner at 1, 2 inches, we'll put marks every 1/2 inch\ncorner = Vector(1, 2)\n\nfor i in range(5):\n    mark = corner + Vector(0.5, 0) * i\n\n    # Create a vertical line starting at the mark point, 0.25 in tall, with a width of 0.01 inches\n    etch.add_line(mark, mark + Vector(0, 0.25), 0.01)\n\n    # Create a text item horizontally centered at the mark, up 0.25 inches. See the\n    # function documentation for details\n    etch.add_text(mark - Vector(0, 0.25), 0, f\"{i + 1}\", 1, VAlign.CENTER, HAlign.CENTER)\n```\n\nAdding a large amount of items to an etch feature can involve a lot of back and forth traffic and waiting while the user interface updates.  Transactions consisting of many batched etch entities can be created using the `with` syntax.  The transaction object (`t` in the example below) has the same features as the etch object in the example above, except that it is caching the operations instead of performing them.  When the context manager ends as the program exits the scope of the `with` block, a single large transaction will be performed creating all the cached elements at once.\n\n```python\nfrom laser_util_api import import ApiClient, Vector\n\nclient = ApiClient(units=Units.INCHES)\n\n# Create the etch entity\netch = client.create.etch()\netch.name = \"Example Etch Markings\"\n\n# We're going to create a grid pattern of hatch marks, spaced every inch.\nwith etch.transaction() as t:\n    for i in range(10):\n        for j in range(10):\n            x = i + 0.5\n            y = j + 0.5\n            t.add_line(Vector(x - 0.125, y), Vector(x + 0.125, y), 0.02)\n            t.add_line(Vector(x, y - 0.125), Vector(x, y + 0.125), 0.02)\n```\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2024 Matthew Jarvis  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "A simple Python API for the Laser Utility project",
    "version": "0.2.1",
    "project_urls": {
        "Homepage": "https://github.com/mattj23/laser-util-api",
        "Repository": "https://github.com/mattj23/laser-util-api.git"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a74e62d7c506b881c618a64272ec6869d2eabc8cd0511c581689d395bc7ba02d",
                "md5": "5f4d97a39715d60157d9650676cfcc90",
                "sha256": "be9e0456eaeda850bf4cfe9c7dc97a32dd76263b2d6c0db69cce9e52b3cb4cc9"
            },
            "downloads": -1,
            "filename": "laser_util_api-0.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5f4d97a39715d60157d9650676cfcc90",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 17624,
            "upload_time": "2024-09-05T04:33:41",
            "upload_time_iso_8601": "2024-09-05T04:33:41.812590Z",
            "url": "https://files.pythonhosted.org/packages/a7/4e/62d7c506b881c618a64272ec6869d2eabc8cd0511c581689d395bc7ba02d/laser_util_api-0.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-05 04:33:41",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "mattj23",
    "github_project": "laser-util-api",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "laser-util-api"
}
        
Elapsed time: 1.16545s