Metadata-Version: 2.5
Name: frame-fit
Version: 0.1.0
Summary: Backend-independent 2D viewport algebra for fitting and comparing geometry.
Requires-Python: >=3.10
Requires-Dist: numpy>=1.23
Provides-Extra: test
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# frame_fit

A tiny backend-independent 2D viewport algebra for fitting, comparing, and tracking geometric objects, where scale and translation are independently resolvable across views.

The package does not plot or render. It returns numerical viewports that other systems can consume.

```python
import numpy as np

from frame_fit import Target2D, fit

points = np.array([[-2.0, -1.0], [2.0, 1.0]])

view = fit(points, target=Target2D(200, 100), padding=0.1)

view.xlim
view.ylim
view.scale
view.transform
```

## Core Ideas

```text
geometry or bounds
    -> viewport request
    -> optional scale constraints
    -> resolved viewport
    -> caller's plotting or graphics backend
```

The solver preserves isotropic scale by default. It does not independently stretch x and y.

## Convenience API

```python
from frame_fit import Bounds2D, Target2D, fit, fit_shared_scale, fit_union

source = Bounds2D(-2, 2, -1, 1)
mapped = Bounds2D(-2.1, 2.1, -1.2, 1.2)
target = Target2D(600, 600)

source_view = fit(source, target=target, padding=0.05)
overlay_view = fit_union([source, mapped], target=target, padding=0.05)
source_cmp, mapped_cmp = fit_shared_scale([source, mapped], target=target, padding=0.05)
```

## General Solver

```python
from frame_fit import Target2D, ViewRequest, resolve_views

views = resolve_views(
    [
        ViewRequest(
            id="source-comparison",
            geometry=source_points,
            target=Target2D(600, 600),
            scale_group="comparison",
        ),
        ViewRequest(
            id="mapped-comparison",
            geometry=mapped_points,
            target=Target2D(600, 600),
            scale_group="comparison",
        ),
    ]
)

assert views["source-comparison"].scale == views["mapped-comparison"].scale
```

## Windows

```python
from frame_fit import ParameterWindow, Selection, bounds

window = ParameterWindow(start=10.0, stop=20.0)
selected = Selection(points, window, parameters=t)

windowed_bounds = selected.bounds()
```

## Development Notes

The adaptive sampling layer for expensive mappings and variable-resolution curves is documented in:

```text
docs/adaptive_sampling_layer.md
```

Current resume status and pending work are documented in:

```text
docs/resume_status.md
```
