planar_geo
A Rust library for 2D geometry: geometric objects, algorithms and visualization.
Overview
This library is based on the basic "point" [f64; 2] type, whose first element
represents its x-coordinate and the second element represents its y-coordinate.
Building upon this, a variety of [Primitive] and [Composite] types are
defined:
This image was created with examples/type_overview.rs
The "segment" types are so-called [Primitive]s: Simple straight
(LineSegment) or arc (ArcSegment) connections between two points. They
form the basis for the [Composite] types SegmentChain, Contour (a
closed segment chain) and Shape (composed of one or more contours).
For these types, this crate offers the following features:
- Property calculation (e.g. length, surface area, centroids),
- [
Transformation] (scaling, shifting, rotation, mirroring), - Intersection calculation between all combinations of the aforementioned types,
see the [
Primitive] and [Composite] traits.
If the corresponding features are activated, it is also possible to serialize and deserialize (using [serde]) and to visualize (using gtk-rs) these types. See the Features section for more.
One distinct feature of this library is the treatment of arcs: Arcs are not approximated as polylines (i.e. a connected series of line segments), but instead being represented as "true" arcs (see e.g. the examples for surface area calculation below). In fact, this is the reason why this library was written in the first place.
Since the "point" type is defined using the floating-point type f64, a lot of
operations (i.e. intersection calculation) are prone to rounding-errors. These
operations therefore require specifying an absolute tolerance epsilon and a
maximum units in last place tolerance max_ulps, which are usually as inputs
for ulps_eq (from the approxim crate) to e.g. determine whether two points
are approximately equal. It is recommended to use the "default" tolerances
DEFAULT_EPSILON and DEFAULT_MAX_ULPS unless there is a good reason to
use other values.
The following paragraphs will provide some examples for the aforementioned features.
Construction and property calculation
The following code snippet shows how to construct the shape shown in the image
below and calculate some of its properties, e.g. centroid and surface area. The
image itself has been created by running examples/shape.rs.
use *;
use ;
use approx;
// For brevity
let e = DEFAULT_EPSILON;
let m = DEFAULT_MAX_ULPS;
// Construct an arc, a line and another arc using various constructors. These
// constructors can fail for invalid input data, see the expect() strings.
let first_arc =
from_center_radius_start_offset_angle
.expect;
let line = new
.expect;
let second_arc = from_start_center_angle
.expect;
// Build a segment chain from these three segments
let mut chain = new;
// Initially, the chain is empty (has no segments)
assert_eq!;
// Now add the three segments
chain.push_back;
chain.push_back;
chain.push_back;
assert_eq!;
// Create a contour out of the chain. If start and end of the chain are not
// identical, a line segment is automatically added.
let contour = new;
// During the conversion to a contour, a line segment has been added which closes the chain
assert_eq!;
// Create a second contour by creating multiple line segments directly from vertices.
let hole = new;
// First element of the vector is interpreted as outer contour, all further
// elements are holes. The resulting shape is visualized below the code snippet.
let shape = new.expect;
// Calculate the surface area: Area of outer contour minus hole area
let quarter_circle_area = 0.25 * PI * .powi;
let center_rect_area = 1.5 * 2.0;
let hole_area = 1.1 * 2.0;
// Exact match except for floating point rounding errors (arcs are not
// approximated as polylines)
assert_abs_diff_eq!;
// Length of the hole contour
assert_abs_diff_eq!;
// Length of the first arc -> Is the first segment of the contour
// 0.5 * 1.5 * PI = Quarter circle circumference times radius.
assert_abs_diff_eq!;
// Centroid of the hole
assert_abs_diff_eq!;
Transformation
The [Transformation] trait allows translating, rotating, scaling and mirroring
of all [Primitive] and [Composite] types:
use *;
use PI;
// For brevity
let e = DEFAULT_EPSILON;
let m = DEFAULT_MAX_ULPS;
// Translate a point
let mut pt = ;
pt.translate;
assert_eq!;
// Rotate a line segment
let mut ls = new.expect;
ls.rotate;
assert_abs_diff_eq!;
assert_abs_diff_eq!;
// Scale a segment chain
let mut chain = from_points;
chain.scale;
let mut pts = chain.points;
assert_eq!;
assert_eq!;
assert_eq!;
// Mirror a contour
let mut contour = new;
contour.line_reflection;
let mut pts = chain.points;
assert_eq!;
assert_eq!;
assert_eq!;
Intersections
A major feature of this crate are the various methods available to find collisions and intersections between different geometric types.
For example, the following code shows intersections between the segments shown in this image:
This image was created with examples/intersection_segments.rs
use *;
use PI;
// Abbreviated to make examples more concise
let e = DEFAULT_EPSILON;
let m = DEFAULT_MAX_ULPS;
let line_1: Segment = new
.expect.into;
let line_2: Segment = new
.expect.into;
let arc: Segment = from_center_radius_start_offset_angle.expect.into;
// Are the following points part of the respective segment?
let pt1 = ;
let pt2 = ;
let pt3 = ;
assert!;
assert!;
assert!;
assert!;
// Find intersections between the segments. The order doesn't matter, i.e.
// line_1.intersections_primitive(&line_2) produces the same result as
// line_2.intersections_primitive(&line_1).
// line_1 and line_2 intersect once in point (2, 0)
assert_eq!;
// line_1 and arc intersect twice (in (0.5, 0.0) and (1.5, 0.0))
assert_eq!;
// line_2 and arc don't intersect at all
assert_eq!;
It is also possible to calculate the intersections between composite types, as
shown in examples/intersection_composites.rs:
Features
Serialization and deserialization
When the serde feature is enabled, all geometric objects can be serialized and
deserialized using the serde crate.
Visualization
When the cairo feature is enabled, all geometric objects have a draw
method which can be used to draw them onto a
cairo Context.
See the [module-level documentation](link to module) for more. All images used
in the documentation were created using this functionality.
Documentation
The full API documentation is available at https://docs.rs/planar_geo/0.1.0/planar_geo/.