import math import pytest import shapely from shapely.geometry import Polygon, LineString, Point import geopandas as gpd import naramotion as nm from naramotion import ( Image, Context, Format, compute_center, get_center, get_centroid, Palette, tone_map_aces, tone_map_reinhard ) from naramotion.shapgeo import GeoCanvas, GeoTransform from naramotion.motion import Spring, DrawReveal, Typewriter, Stagger from naramotion.path import Path def test_compute_center_and_centroids(): # 1. Bounds tuple (minx, miny, maxx, maxy) bounds = (10.0, 20.0, 30.0, 40.0) cx, cy = compute_center(bounds) assert cx == 20.0 assert cy == 30.0 # 2. Shapely Polygon poly = Polygon([(0, 0), (10, 0), (10, 10), (0, 10)]) cx, cy = get_center(poly) assert math.isclose(cx, 5.0) assert math.isclose(cy, 5.0) # 3. GeoDataFrame gdf = gpd.GeoDataFrame({ "name": ["A", "B"], "geometry": [Point(0, 0), Point(10, 20)] }) cx, cy = get_centroid(gdf) assert math.isclose(cx, 5.0) assert math.isclose(cy, 10.0) # 4. Path p = Path() p.add_rect(100, 100, 200, 200) # (100, 100) to (300, 300) cx, cy = compute_center(p) assert math.isclose(cx, 200.0) assert math.isclose(cy, 200.0) def test_geocanvas_center_and_dynamic_stroke(): with GeoCanvas(width=800, height=600, bounds=(0, 0, 100, 100)) as canvas: cx, cy = canvas.center assert math.isclose(cx, 50.0) assert math.isclose(cy, 50.0) # Focus on a specific point canvas.focus_on((20.0, 30.0, 40.0, 50.0), zoom=2.0) fcx, fcy = canvas.center assert math.isclose(fcx, 30.0) assert math.isclose(fcy, 40.0) # Dynamic stroke test w = canvas._calc_stroke_width(2.0, dynamic_stroke=True) assert 0.25 <= w <= 12.0 def test_palettes_and_color_harmony(): # Built-in palette cyber = Palette.get("cyberpunk") assert len(cyber) >= 5 tokyo = Palette.get("tokyo_night") assert len(tokyo) >= 5 # Harmonic generator colors = Palette.generate(8, base_color="#00F0FF", mode="golden_ratio") assert len(colors) == 8 # Ensure distinct colors values = set(c.value for c in colors) assert len(values) == 8 def test_aces_tone_mapping_and_bloom(): img = Image(200, 200, Format.PRGB32) with Context(img) as ctx: ctx.fill_all("#FF007F") # Hot pink # Apply ACES tone mapping tone_map_aces(img, exposure=1.2) tone_map_reinhard(img, exposure=1.0) assert img.width == 200 def test_spring_and_declarative_actions(): # Spring physics spring = Spring(stiffness=200, damping=10) val_start = spring.evaluate(0.0) val_end = spring.evaluate(1.0) assert math.isclose(val_start, 0.0, abs_tol=0.01) assert math.isclose(val_end, 1.0, abs_tol=0.1) # Actions p = Path() p.add_circle(100, 100, 50) act1 = DrawReveal(p, duration=1.0, delay=0.2) act2 = Typewriter("TEST TEXT", x=50, y=50, duration=1.0) staggered = Stagger.create([act1, act2], delay_step=0.5) assert staggered[0].delay == 0.2 assert math.isclose(staggered[1].delay, 0.5) img = Image(400, 400, Format.PRGB32) with Context(img) as ctx: act1.render(0.5, ctx) act2.render(0.8, ctx)