Introduction
[dependencies]
The world is made up of facts about many things.
kurbo = "0.1.2"
Some of these facts are facts about curves and shapes.
piet = "0.0.1"
Some of these facts are facts about how to draw curves and shapes, among other things, on a surface so people can see them.
Shapes
pub trait Shape {
Shapes are a category of thing. You can create your own shape, if you say all the required facts about it.
The category is open-ended, a design choice. Another quite reasonable choice would have been to specify the fixed alternatives, eg enum Shape { Rectangle, Circle, ...}.
fn to_bez_path(&self) -> Self::BezPathIter
One of the facts that must be said about a shape is how to enumerate its segments as a bezier path.
type BezPathIter: Iterator<Item = PathEl>
Each type of shape has an associated iterator which provide its bezier path elements one at a time.
fn bounding_box(&self) -> Rect
Another of the facts that must be said about a shape is the smallest rectangle that encloses it.
The bounding box is especially important because it can be used to skip drawing a shape altogether if it's not visible, and other similar optimizations.
fn area(&self) -> f64
Another of the facts that must be said about a shape is its area.
fn perimeter(&self, accuracy: f64) -> f64
Another of the facts that must be said about a shape is the length of its perimeter, at least to a degree of approximation.
fn winding(&self, pt: Vec2) -> i32
Another of the facts that must be said about a shape is whether a point is inside or outside, or in the case of more complex shapes, the winding number with respect to the point.
fn as_line(&self) -> Option<Line> { None }
One fact that can be said about a shape is that it is a line. Then it is possible to know what line it is. If it is not said, it is assumed not to be a line.
This is basically Rust's way to express "isinstance" or downcasting. It is very important for rendering because special cases for simple shapes can be much more efficient than general paths.
fn as_rect(&self) -> Option<Rect> { None }
Similarly, one can say that a shape is a rectangle.
Other cases will be added. Those won't break semver because of the default.
(no &mut self methods)
A shape is immutable. More precisely, none of the methods which operate on a shape change the shape.
}
And that is all to be said about a shape.
Until we decide to add more methods, but that would break semver.
impl Shape for Rect
A rectangle is a shape.
A particularly important shape for Piet Mondrian, in fact.
impl Shape for BezPath
A Bezier path is a shape.
impl Shape for Line
A line is a shape.
A line is an example that shapes need not be closed.
Whereof one cannot speak, thereof one must be silent.