geomcore 0.37.0

A pure, standalone geometric kernel for CAD-grade curves and surfaces: parametric evaluation, transformations, and curve-on-surface parametrization.
Documentation
# Viewer

Live [geomcore-viewer](https://github.com/geomcore/geomcore-viewer) instance
below — Babylon.js 3D pane plus a PixiJS 2D pane for parameter-space curves.
The demo scene shows an ellipse, a circle, a hyperbola and a line, with the points where they meet.

<iframe src="https://geomcore.github.io/geomcore-viewer/" width="100%" height="640" style="border: 1px solid #333; border-radius: 8px;" allow="fullscreen" title="geomcore-viewer live demo"></iframe>

## Install

=== "Python"

    ```sh
    pip install geomcore geomcore-viewer
    ```

    geomcore-viewer 0.3 has no dependencies and ships the built viewer
    in the wheel. It reads geomcore objects through their public
    getters rather than pinning a geomcore version, and works with
    geomcore 0.33 and later. Drawing result objects directly
    (projections, intersections, extrema) needs geomcore 0.36.

=== "Rust"

    ```toml
    [dependencies]
    geomcore = "0.36"
    geomcore-viewer = { version = "0.3", features = ["geomcore"] }
    ```

    The `geomcore` feature of geomcore-viewer 0.3 is built against
    geomcore 0.36. Paired with another geomcore minor version, Cargo
    pulls in both versions and the viewer does not accept the other
    version's types, so keep geomcore at 0.36 in code that uses the
    viewer until a viewer release supports a later one. The Rust client never starts the server:
    run `geomcore-viewer serve` from the Python package once.

## From your own code

The embedded page above is static. From a script, a debugger or a notebook, `view.add(...)` sends geomcore objects to a local viewer tab that updates live:

=== "Python"

    ```python
    from geomcore import Frame, Point, Vector
    from geomcore.curves import Circle, Ellipse
    import geomcore_viewer as gv

    view = gv.Viewer("Ellipse ∩ circle")          # starts the local viewer and opens a tab
    E = Ellipse.from_frame(Frame.world(), 3.0, 2.0)
    C = Circle(Point(2, 1, 0), Vector.unit_z(), 1.5)
    view.add(E, label="E")
    view.add(C, label="C")
    view.add(C.intersect(E), label="P")           # the result draws directly: hits P, operands faded
    ```

=== "Rust"

    ```rust
    use geomcore::{Circle, Cylinder, Point, Tolerance, Vector};
    use geomcore_viewer::{Geom, Opts, Viewer};

    let mut view = Viewer::new("A circle on a cylinder")?;
    let cylinder = Cylinder::new(Point::ORIGIN, Vector::Z, 2.0)?;
    let ring = Circle::new(Point::new(0.0, 0.0, 1.0), Vector::Z, 2.0)?;
    let s = view.add(Geom::from(&cylinder).window(None, Some([-2.0, 2.0])), Opts::new().label("S"))?;
    view.add(&ring, Opts::new().label("C"))?;
    view.pcurve(&ring.parametrize_on(cylinder, Tolerance::DEFAULT)?, &s, Opts::new().label("C in (u, v)"))?;
    ```

Protocol details: [protocol/SCENE.md](https://github.com/geomcore/geomcore-viewer/blob/main/protocol/SCENE.md).