std1.0.0-beta-7 SafeC docs

Source gui/gui_path.h

View in the repository

#pragma once
// SafeC Standard Library — GUI: 2D geometry for the vector canvas.
//
// GuiMatrix (2x3 affine transforms), GuiRect, and GuiPath — a vector path
// of move/line/quadratic/cubic/close segments with the usual builders
// (arcs, rounded rectangles, ellipses, SVG path data). Paths are plain
// data in user coordinates: gui_canvas.h fills, strokes and clips with
// them, gui_text.h produces glyph outlines as them.
//
//   struct GuiPath p = GuiPath::new();
//   p.move_to(10.0f, 10.0f);
//   p.cubic_to(40.0f, 0.0f, 60.0f, 40.0f, 90.0f, 10.0f);
//   p.rounded_rect(10.0f, 50.0f, 80.0f, 30.0f, 6.0f);
//   canvas.fill_path(&p);
//   p.free();
//
// Angles are in radians, y points down (screen coordinates), so a positive
// angle turns clockwise on screen — the HTML canvas convention.

#include <std/collections/vec.h>

// GuiPathSeg.verb
#define GUI_PATH_MOVE  0
#define GUI_PATH_LINE  1
#define GUI_PATH_QUAD  2
#define GUI_PATH_CUBIC 3
#define GUI_PATH_CLOSE 4

namespace std {

struct GuiPoint {
    float x;
    float y;
};

struct GuiRect {
    float x;
    float y;
    float w;
    float h;

    static struct GuiRect new(float x, float y, float w, float h);
    int contains(float px, float py) const;
    // The overlap of two rects (w/h 0 if they don't overlap) / the
    // smallest rect holding both.
    struct GuiRect intersect(struct GuiRect o) const;
    struct GuiRect unite(struct GuiRect o) const;
    int is_empty() const;
};

// x' = a*x + c*y + e
// y' = b*x + d*y + f
struct GuiMatrix {
    float a; float b;
    float c; float d;
    float e; float f;

    static struct GuiMatrix identity();
    static struct GuiMatrix translation(float tx, float ty);
    static struct GuiMatrix scaling(float sx, float sy);
    static struct GuiMatrix rotation(float radians);
    static struct GuiMatrix new(float a, float b, float c, float d, float e, float f);

    // 'self' applied after 'inner': (self * inner)(p) = self(inner(p)).
    struct GuiMatrix mul(struct GuiMatrix inner) const;
    // self * T/S/R — i.e. the new transform first translates/scales/
    // rotates points, then applies self (how a canvas' translate() etc.
    // compose).
    struct GuiMatrix translate(float tx, float ty) const;
    struct GuiMatrix scale(float sx, float sy) const;
    struct GuiMatrix rotate(float radians) const;
    // 1 and the inverse in 'out', or 0 if the matrix is singular.
    int  invert(&GuiMatrix out) const;
    float apply_x(float x, float y) const;
    float apply_y(float x, float y) const;
    // The transformed bounding box of 'r'.
    struct GuiRect apply_rect(struct GuiRect r) const;
    // sqrt(|det|): how much the matrix scales areas, per axis on average.
    float scale_factor() const;
    int  is_identity() const;
    int  is_translation() const;     // only e/f differ from identity
    int  is_axis_aligned() const;    // no rotation/skew (b == c == 0)
};

struct GuiPathSeg {
    int verb;          // GUI_PATH_*
    float x1; float y1;   // LINE/MOVE: the point; QUAD: control; CUBIC: control 1
    float x2; float y2;   // QUAD: end point; CUBIC: control 2
    float x3; float y3;   // CUBIC: end point
};

struct GuiPath {
    struct Vec<struct GuiPathSeg> segs;
    float curX; float curY;       // current point
    float startX; float startY;   // start of the current subpath
    int hasCurrent;

    static struct GuiPath new();

    void move_to(float x, float y);
    void line_to(float x, float y);
    void quad_to(float cx, float cy, float x, float y);
    void cubic_to(float c1x, float c1y, float c2x, float c2y, float x, float y);
    // Closes the current subpath (a straight line back to its start).
    void close();

    // Circular arc around (cx,cy) from angle a0 to a1, clockwise on screen
    // unless 'ccw'; joined to the current point with a line (HTML canvas'
    // arc()). Approximated with cubics (error < 0.01% of the radius).
    void arc(float cx, float cy, float r, float a0, float a1, int ccw);
    // A rounded corner from the current point toward (x1,y1), then toward
    // (x2,y2), with radius r (HTML canvas' arcTo()).
    void arc_to(float x1, float y1, float x2, float y2, float r);
    // An elliptic arc (rotated by 'rotation') — HTML canvas' ellipse().
    void ellipse_arc(float cx, float cy, float rx, float ry, float rotation, float a0, float a1, int ccw);
    // SVG's elliptical arc command from the current point to (x,y).
    void svg_arc_to(float rx, float ry, float xAxisRotation, int largeArc, int sweep, float x, float y);

    // Closed shapes, each its own subpath, clockwise on screen.
    void rect(float x, float y, float w, float h);
    void rounded_rect(float x, float y, float w, float h, float r);
    // Per-corner radii: top-left, top-right, bottom-right, bottom-left.
    void rounded_rect4(float x, float y, float w, float h, float tl, float tr, float br, float bl);
    void ellipse(float cx, float cy, float rx, float ry);
    void circle(float cx, float cy, float r);
    // A closed polygon through n points (xy pairs: pts[0..2n)).
    void polygon([]const float pts);
    // internal: the (reference, length) core of polygon()
    void polygon_n_(const &float pts, int n);

    // Parses SVG path data ("M10 10 h 20 q 5 5 0 10 z ..." — every command
    // of SVG 1.1, absolute and relative) and appends it. Returns 1, or 0 at
    // the first malformed command (what came before it stays).
    int  add_svg(const &char d);

    // Appends 'other' transformed by 'm'.
    void append(const &GuiPath other, struct GuiMatrix m);
    // Transforms every point of this path in place.
    void transform(struct GuiMatrix m);

    // Bounding box of the points (control points included: may be a bit
    // larger than the curve).
    struct GuiRect bounds() const;
    int  is_empty() const;
    unsigned long length() const;   // number of segments
    void clear();
    void drop();
    void free() consume;   // = drop()
};

} // namespace std