[][src]Crate lasy

A small library dedicated to LASER path optimisation.

The goal for the library is to provide a suite of useful tools for optimising linear vector images for galvanometer-based LASER projection. To allow lasy LASERs to get more done.

This crate implements the full suite of optimisations covered in Accurate and Efficient Drawing Method for Laser Projection by Purkhet Abderyim et al. These include Graph optimisation, draw order optimisation, blanking delays and sharp angle delays. See the paper for more details.

Optimising a Vector Image

Optimising a single frame of input_points is achieved by the following steps:

  1. Convert the list of points to a list of segments, tracking whether they are blank or lit.
  2. Convert the segments to a graph where the nodes are points. Only a single node for each unique position is stored.
  3. Convert the point graph to a euler graph, determining the minimum number of blanks necessary to do so.
  4. Find the optimal euler circuit within the euler graph. This represents the new path that the LASER should travel.
  5. Interpolate the euler circuit. This step will attempt to distribute the "target count" number of points across the euler circuit while accounting for blanking and sharp angle delays in accordance with the provided configuration.

In code, these steps look like so:

This example is not tested
let segs = points_to_segments(&input_points);
let pg = segments_to_point_graph(&input_points, segs);
let eg = point_graph_to_euler_graph(&pg);
let ec = euler_graph_to_euler_circuit(&input_points, &eg);
let output_points = interpolate_euler_circuit(&input_points, &ec, &eg, target_count, config);

Optimising Animation

It is worth keeping in mind that, if you are working with an animated stream of frames, some consideration must be taken in how to move from the end of one frame to the beginning of the next.

For the most part, this simply requires blanking from the last point of the previous frame to the first point of the current one (or in other words, the first point of the euler circuit for the current frame).

The blank_segment_points function can be useful for generating these points, as this same function is used for generating blank segment points during interpolation.

Point Types

In order to have your points be compatible with the functions provided by this crate, the Position, IsBlank, Weight, Blanked and Lerp traits should be implemented as necessary. Please see their respective documentation for more information.

Note that the optimisation steps above are intended to work with two different point types: an input point type describing the user's original frame and an output (or raw) point type representing the fully interpolated, optimised path. The main difference between these two types is that the output point type does not to store its weight, as point weighting is applied during the interpolation process. See the Weight docs for more details.

Graph Storage

The graphs used within the optimisation steps above will never store points directly, and instead will store indices into the original slice of input_points. This allows for a smaller memory footprint and to avoid complicated generics propagating up through the graph types.


pub use petgraph::Incoming;
pub use petgraph::Outgoing;



Capture a profile of each edge to assist the interpolation process.


Configuration options for eulerian circuit interpolation.


Represents a line segment over which the laser scanner will travel.


An iterator yielding all lit line segments.



Edge direction.


Edge profile data specific to the kind of edge.


describes whether a line segment between two points is blank or not.



For the blank ab: [a, a.blanked(), b.blanked(), (0..delay).map(|_| b.blanked())].



Point types that can produce a blanked copy of themselves.


Point types that can describe whether or not they are blank (black).


Types that can be linearly interpolated.


Point types that may describe position.


Point types that have a weight associated with them.



The number of points used per blank segment given the blank_delay_points from a config.


Returns the points used to blank between two given lit points a and b.


The number of points added at a lit corner given its angle and angular delay rate.


The minimum points for traversing a lit segment (not including end corner delays).


Given some Euler Circuit edge e and its direction d, return the index of the node that represents the end of the edge.


Given some Euler Circuit edge e and its direction d, return the index of the node that represents the start of the edge.


Produce an iterator yielding Segments representing the euler circuit's path through the euler graph.


Given a Euler Graph describing the vector image to be drawn, return the optimal Euler Circuit describing the path over which the laser should travel.


Interpolate the given EulerCircuit with the given configuration.


The same as interpolate_profiled_path, but performs the path profiling step internally prior to interpolation.


Interpolate the path described by the given edges.


The minimum number of points used for a lit segment of the given distance and end angle.


Returns the points that make up a lit segment between a and b including delay for the end corner.


Convert a point graph to a euler graph.


Create an iterator yielding segments from an iterator yielding points.


Traverse a path described by an iterator yielding edges, profiling the edges along the way.


Convert the given laser frame vector segments to a graph of points.

Type Definitions


A type used to represent a eulerian circuit through an eulerian graph.


A type used to represent a graph of points that contains at least one euler circuit.


A type used to represent graph describing the points in a frame and how they are joined.


An index into a slice of points.