math/py-isosurfaces: New port: Construct isolines/isosurfaces over a 2D/3D scalar field

This commit is contained in:
Yuri Victorovich 2023-01-20 08:09:03 -08:00
parent 82f76307f2
commit 62fd95493e
5 changed files with 172 additions and 0 deletions

View File

@ -925,6 +925,7 @@
SUBDIR += py-intspan
SUBDIR += py-iohexperimenter
SUBDIR += py-ipyopt
SUBDIR += py-isosurfaces
SUBDIR += py-jax
SUBDIR += py-kahip
SUBDIR += py-keras

View File

@ -0,0 +1,30 @@
PORTNAME= isosurfaces
DISTVERSION= 0.1.0
CATEGORIES= math
MASTER_SITES= PYPI
PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX}
MAINTAINER= yuri@FreeBSD.org
COMMENT= Construct isolines/isosurfaces over a 2D/3D scalar field
WWW= https://github.com/jared-hughes/isosurfaces
LICENSE= MIT
RUN_DEPENDS= ${PYNUMPY}
TEST_DEPENDS= ${PYTHON_PKGNAMEPREFIX}cairo>0:graphics/py-cairo@${PY_FLAVOR} \
${PYNUMPY} \
xdg-open:devel/xdg-utils
USES= python
USE_PYTHON= distutils autoplist
NO_ARCH= yes
TEST_ENV= ${MAKE_ENV} PYTHONPATH=${STAGEDIR}${PYTHONPREFIX_SITELIBDIR}
do-test:
@cd ${TEST_WRKSRC} && \
${SETENV} ${TEST_ENV} ${PYTHON_CMD} ${FILESDIR}/isoline_demo.py && \
xdg-open ${TEST_WRKSRC}/demo.svg
.include <bsd.port.mk>

View File

@ -0,0 +1,3 @@
TIMESTAMP = 1674236137
SHA256 (isosurfaces-0.1.0.tar.gz) = fa1b44e5e59d2f429add49289ab89e36f8dcda49b7badd99e0beea273be331f4
SIZE (isosurfaces-0.1.0.tar.gz) = 10122

View File

@ -0,0 +1,133 @@
# from examples/isoline_demo.py
""" Code for demo-ing and experimentation. Prepare for a mess """
from isosurfaces import plot_isoline
from isosurfaces.isoline import (
Cell,
build_tree,
Triangulator,
CurveTracer,
)
import numpy as np
import cairo
min_depth = 5
pmin = np.array([-8, -6])
pmax = np.array([8, 6])
def f(x, y):
return y * (x - y) ** 2 - 4 * x - 8
# Here we directly use plot_implicit internals in order to see the quadtree
fn = lambda u: f(u[0], u[1])
tol = (pmax - pmin) / 1000
quadtree = build_tree(2, fn, pmin, pmax, min_depth, 5000, tol)
triangles = Triangulator(quadtree, fn).triangulate()
curves = CurveTracer(triangles, fn, tol).trace()
def g(x, y):
return x ** 3 - x - y ** 2
# Typical usage
curves1 = plot_isoline(
lambda u: g(u[0], u[1]),
pmin,
pmax,
min_depth=4,
max_quads=1000,
)
def h(x, y):
return x ** 4 + y ** 4 - np.sin(x) - np.sin(4 * y)
curves2 = plot_isoline(lambda u: h(u[0], u[1]), pmin, pmax, 4, 1000)
WIDTH = 640
HEIGHT = 480
def setup_context(c):
# reflection to change math units to screen units
scale = min(WIDTH / (pmax[0] - pmin[0]), HEIGHT / (pmax[1] - pmin[1]))
c.scale(scale, -scale)
c.translate(WIDTH / scale / 2, -HEIGHT / scale / 2)
c.set_line_join(cairo.LINE_JOIN_BEVEL)
def draw_axes(c):
c.save()
c.set_line_width(0.1)
c.move_to(0, -100)
c.line_to(0, 100)
c.stroke()
c.move_to(-100, 0)
c.line_to(100, 0)
c.stroke()
c.restore()
def draw_quad(c, quad: Cell):
width = 0
if quad.depth <= min_depth:
width = 0.02
elif quad.depth == min_depth + 1:
width = 0.01
else:
width = 0.005
c.set_line_width(0.5 * width)
if quad.children:
c.move_to(*((quad.vertices[0].pos + quad.vertices[1].pos) / 2))
c.line_to(*((quad.vertices[2].pos + quad.vertices[3].pos) / 2))
c.move_to(*((quad.vertices[0].pos + quad.vertices[2].pos) / 2))
c.line_to(*((quad.vertices[1].pos + quad.vertices[3].pos) / 2))
c.stroke()
for child in quad.children:
draw_quad(c, child)
def draw_quads(c):
c.save()
draw_quad(c, quadtree)
c.restore()
def draw_bg(c):
c.save()
c.set_source_rgb(1, 1, 1)
c.paint()
c.restore()
def draw_curves(c, curves_list, rgb):
print(
"drawing", sum(map(len, curves_list)), "segments in", len(curves_list), "curves"
)
c.set_source_rgb(*rgb)
# draw curves
c.save()
c.set_line_width(0.03)
for curve in curves_list:
c.move_to(*curve[0])
for v in curve:
c.line_to(*v)
c.stroke()
c.restore()
with cairo.SVGSurface("demo.svg", WIDTH, HEIGHT) as surface:
c = cairo.Context(surface)
setup_context(c)
draw_bg(c)
draw_axes(c)
# draw_quads(c)
draw_curves(c, curves, [0.1, 0.1, 0.8])
draw_curves(c, curves1, [0.8, 0.1, 0.1])
draw_curves(c, curves2, [0.1, 0.6, 0.1])

View File

@ -0,0 +1,5 @@
isosurfaces allows to construct isolines/isosurfaces of a 2D/3D scalar field
defined by a function, i.e. curves over which f(x,y)=0 or surfaces over which
f(x,y,z)=0. Most similar libraries use marching squares or similar over a
uniform grid, but this uses a quadtree to avoid wasting time sampling many far
from the implicit surface.