소스 검색

render test charts, intent paper

Lukas Goldschmidt 23 시간 전
부모
커밋
26be5714d2
2개의 변경된 파일339개의 추가작업 그리고 0개의 파일을 삭제
  1. 173 0
      AstroChart_Source_Reference.md
  2. 166 0
      render_test_charts.py

+ 173 - 0
AstroChart_Source_Reference.md

@@ -0,0 +1,173 @@
+# AstroChart — Source Code Reference
+
+**Library**: AstroChart (a.k.a. AstroDraw)
+**Description**: A free and open-source JavaScript/TypeScript library for generating SVG charts to display planets in astrology.
+**Doc site**: https://astrodraw.github.io/
+**GitHub repo**: https://github.com/AstroDraw/AstroChart
+**Branch**: `main`
+
+---
+
+## Repository Structure
+
+The source code lives under `project/` (not `src/`). Build output (the bundle consumed end-users) is in `dist/`.
+
+```
+AstroChart/
+├── dist/
+│   ├── astrochart.js              # Webpack-bundled build (99KB) — what the docs site loads
+│   └── project/                   # Sub-bundle for project-mode imports
+├── project/
+│   ├── src/                       # TypeScript source
+│   │   ├── index.ts               (172B)   — Public API entry, re-exports Chart
+│   │   ├── chart.ts               (4KB)    — Chart class, public entry point
+│   │   ├── svg.ts                 (84KB)   — SVG drawing primitives + all planet/zodiac glyphs
+│   │   ├── radix.ts               (19KB)   — Radix chart composition (drawBg, drawUniverse, drawPoints...)
+│   │   ├── transit.ts             (13KB)   — Transit chart overlay
+│   │   ├── aspect.ts              (8KB)    — Aspect calculation engine
+│   │   ├── zodiac.ts              (10KB)   — Zodiac logic, dignities, retrograde
+│   │   ├── settings.ts            (8KB)    — Default config (colors, ratios, symbols, scale)
+│   │   ├── utils.ts               (12KB)   — Geometry: getPointPosition, getRulerPositions, collision
+│   │   ├── animation/
+│   │   │   ├── animator.ts        (5KB)    — Animated chart transitions
+│   │   │   └── timer.ts           (1KB)    — Animation timing helper
+│   │   └── *.test.ts              — Jest test suite
+│   ├── examples/                  — Usage examples
+│   └── __tests__/                 — Additional tests
+├── website/                       # Docusaurus doc site source (what renders astrodraw.github.io)
+├── docs/                          # Doc site content (markdown)
+├── doc/                           # Older documentation
+├── package.json
+├── tsconfig.json
+├── webpack.config.js
+└── jest.config.js
+```
+
+---
+
+## Chart Rendering Flow
+
+### Public API
+
+```typescript
+// project/src/chart.ts
+class Chart {
+  constructor(elementId: string, width: number, height: number, settings?: Partial<Settings>)
+  radix(data: AstroData): Radix      // Draw a natal/radix chart
+  transit(data: AstroData): Transit  // Draw a transit overlay
+  scale(factor: number): void        // Scale the chart
+  calibrate(): Chart                 // Debug overlay
+}
+```
+
+```typescript
+// project/src/index.ts — re-exports Chart as default
+```
+
+### Drawing Pipeline (inside `Radix`)
+
+Order of operations in `Radix` constructor + draw methods:
+
+| Step | Method | File | What it does |
+|------|--------|------|--------------|
+| 1 | `drawBg()` | `project/src/radix.ts` | Background hemisphere via `paper.segment()` |
+| 2 | `drawUniverse()` | `project/src/radix.ts` | 12 zodiac sign color segments + 12 zodiac symbol glyphs |
+| 3 | `drawRuler()` | `project/src/radix.ts` | Degree tick marks around the wheel |
+| 4 | `drawPoints()` | `project/src/radix.ts` | Planet symbols, pointer lines, degree/retro/dignity labels |
+| 5 | `drawCusps()` | `project/src/radix.ts` | 12 cusp lines (dashed around planets), house numbers |
+| 6 | `drawAxis()` | `project/src/radix.ts` | Asc/Ds/Ic/Mc axis lines with symbols |
+| 7 | `drawCircles()` | `project/src/radix.ts` | Outer, inner, indoor circle strokes |
+
+Aspects are drawn via `Radix.aspects()` which uses `project/src/aspect.ts`.
+
+---
+
+## Key Source Files (download URLs)
+
+### Core rendering
+
+| File | Description |
+|------|-------------|
+| [svg.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/svg.ts) | SVG primitives: `segment()`, `circle()`, `line()`, `text()`, and 50+ glyph methods (`sun()`, `moon()`, `aries()`, `taurus()`, ... `pluto()`, `chiron()`, `nnode()`, `fortune()`). The `<path d="...">` arc math lives at lines ~1468-1478. |
+| [radix.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/radix.ts) | Chart composition — orchestrates all SVG calls. `LocatedPoint` interface, `AstroData` type, collision avoidance via `assemble()`. |
+| [chart.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/chart.ts) | Public entry point. Creates `SVG`, delegates to `Radix` or `Transit`. |
+
+### Data + logic
+
+| File | Description |
+|------|-------------|
+| [settings.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/settings.ts) | Default constants: `COLORS_SIGNS`, `SYMBOL_SIGNS`, `INNER_CIRCLE_RADIUS_RATIO`, `INDOOR_CIRCLE_RADIUS_RATIO`, `RULER_RADIUS`, `SYMBOL_SCALE`, `PADDING`, etc. |
+| [utils.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/utils.ts) | `getPointPosition()`, `getRulerPositions()`, `getDashedLinesPositions()`, `getDescriptionPosition()`, `assemble()`, `validate()`, `radiansToDegree()`. |
+| [zodiac.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/zodiac.ts) | Zodiac sign boundaries, essential dignities (domicile, exaltation, detriment, fall), retrograde detection. |
+| [aspect.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/aspect.ts) | `AspectCalculator` class — computes aspects between planet points (conjunction, opposition, trine, square, sextile, etc.). |
+| [transit.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/transit.ts) | Transit chart — draws on top of an existing radix. |
+| [animation/animator.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/animation/animator.ts) | Animated chart transitions. |
+| [animation/timer.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/animation/timer.ts) | Animation timing helper. |
+| [index.ts](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/project/src/index.ts) | Public API barrel file. |
+
+### Built artifact
+
+| File | Description |
+|------|-------------|
+| [dist/astrochart.js](https://raw.githubusercontent.com/AstroDraw/AstroChart/main/dist/astrochart.js) | Webpack bundle — the file loaded by the doc site and distributed to end-users. |
+
+---
+
+## SVG Primitives API (svg.ts)
+
+| Method | Signature | Purpose |
+|--------|-----------|---------|
+| `segment()` | `(x, y, radius, a1, a2, thickness, lFlag?, sFlag?)` | Arc slice (used for sign segments, background) |
+| `circle()` | `(cx, cy, radius)` | Circle stroke (chart rings) |
+| `line()` | `(x1, y1, x2, y2)` | Straight line (cusps, pointers, ruler ticks) |
+| `text()` | `(txt, x, y, size, color)` | Symbol/text glyph |
+| `getSymbol()` | `(name, x, y)` | Dispatches to the correct glyph method |
+| `radialLine()` | — | Radial spoke from center to edge |
+
+**Key constants** (defined in `settings.ts`, used in `svg.ts` line ~1468):
+- `LARGE_ARC_FLAG = 1`
+- `SWEET_FLAG = 0`
+
+---
+
+## Doc Site (what renders the GitHub Pages UI)
+
+The documentation site that appears at https://astrodraw.github.io/ is built with **Docusaurus v2.3.1** (seen in `<meta name="generator">`).
+
+| File | Description |
+|------|-------------|
+| [website/](https://github.com/AstroDraw/AstroChart/tree/main/website) | Docusaurus source (docusaurus.config, sidebar, pages) |
+| [docs/](https://github.com/AstroDraw/AstroChart/tree/main/docs) | Doc content markdown |
+
+The homepage hero banner contains an inline SVG showing a React-like logo (unrelated to this library — it's Docusaurus template branding). The actual AstroChart demo rendering on the page uses the `Chart` class targeting `<div id="paper">`.
+
+---
+
+## Key Data Structures
+
+```typescript
+// From radix.ts
+export type Points = Record<string, number[]>
+export interface LocatedPoint {
+  name: string   // planet name, e.g. "Sun", "Moon"
+  x: number      // computed screen x
+  y: number      // computed screen y
+  r: number      // collision radius
+  angle: number  // shifted position in degrees
+  pointer?: number
+  index?: number
+}
+export interface AstroData {
+  planets: Points   // {"Sun":[120], "Moon":[45], ...}
+  cusps: number[]   // [300, 340, 30, 60, 75, 90, 116, 172, 210, 236, 250, 274]
+}
+```
+
+---
+
+## Notes
+
+- The library is **TypeScript** (compiled via webpack, not tsc).
+- No runtime dependencies — pure DOM SVG manipulation.
+- Tests use **Jest** (`jest.config.js`).
+- The `project/` subdirectory is the actual library source; the repo root contains build/config/docs.

+ 166 - 0
render_test_charts.py

@@ -0,0 +1,166 @@
+#!/usr/bin/env python3
+"""
+Render test charts for two celebrities and save to /home/shared/.
+
+Usage:
+    python3 render_test_charts.py [--format svg|png|jpg] [--size N]
+"""
+
+import argparse
+import asyncio
+import json
+import sys
+import os
+
+# Ensure src is on the path
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
+
+from astro_mcp.tools import calculate_natal_chart, render_natal_chart
+
+
+# ── Birth data ───────────────────────────────────────────────────────
+
+PEOPLE = {
+    "donald_trump": {
+        "birth_datetime": "1946-06-14T11:00:00-04:00",
+        "latitude": 40.70,
+        "longitude": -73.80,
+        "elevation": 10,
+    },
+    "chaka_khan": {
+        "birth_datetime": "1953-03-23T11:00:00-06:00",
+        "latitude": 41.88,
+        "longitude": -87.63,
+        "elevation": 180,
+    },
+}
+
+
+async def render_person(name: str, birth_data: dict, fmt: str, size: int) -> dict:
+    """Calculate and render a natal chart for one person.
+
+    Returns a summary dict with moon info and output path.
+    """
+    # 1. Calculate chart data
+    chart_data = await calculate_natal_chart(
+        birth_datetime=birth_data["birth_datetime"],
+        latitude=birth_data["latitude"],
+        longitude=birth_data["longitude"],
+        elevation=birth_data["elevation"],
+    )
+    if "error" in chart_data:
+        print(f"  ERROR calculating {name}: {chart_data['error']}")
+        return None
+
+    # 2. Render
+    result = await render_natal_chart(
+        birth_datetime=birth_data["birth_datetime"],
+        latitude=birth_data["latitude"],
+        longitude=birth_data["longitude"],
+        elevation=birth_data["elevation"],
+        color_mode="color",
+        size=size,
+        format=fmt,
+        title=f"Natal Chart: {name.replace('_', ' ').title()}",
+    )
+    if "error" in result:
+        print(f"  ERROR rendering {name}: {result['error']}")
+        return None
+
+    # 3. Save
+    ext = fmt
+    filename = f"{name}_natal.{ext}"
+    outdir = "/home/shared"
+    os.makedirs(outdir, exist_ok=True)
+    outpath = os.path.join(outdir, filename)
+
+    content = result["content"]
+    mode = "w" if isinstance(content, str) else "wb"
+    with open(outpath, mode) as f:
+        f.write(content)
+
+    # 4. Extract moon info
+    moon_info = None
+    for p in chart_data.get("planets", []):
+        if p.get("body") == "moon":
+            moon_info = {
+                "absolute_lon": p.get("absolute_lon"),
+                "degree_within_sign": p.get("degree_within_sign"),
+                "sign": p.get("sign"),
+                "house": p.get("house"),
+                "retrograde": p.get("retrograde"),
+            }
+            break
+
+    return {
+        "name": name,
+        "output": outpath,
+        "format": result["format"],
+        "content_type": result["content_type"],
+        "size_bytes": len(content) if isinstance(content, bytes) else len(content.encode("utf-8")),
+        "moon": moon_info,
+        "all_planets": [
+            {"body": p.get("body"), "absolute_lon": p.get("absolute_lon"),
+             "degree_within_sign": p.get("degree_within_sign"),
+             "sign": p.get("sign"), "house": p.get("house"),
+             "retrograde": p.get("retrograde")}
+            for p in chart_data.get("planets", [])
+        ],
+        "houses_count": len(chart_data.get("houses", [])),
+        "aspects_count": len(chart_data.get("aspects", [])),
+    }
+
+
+async def main():
+    parser = argparse.ArgumentParser(description="Render test natal charts")
+    parser.add_argument("--format", default="svg", choices=["svg", "png", "jpg"],
+                        help="Output format (default: svg)")
+    parser.add_argument("--size", type=int, default=600,
+                        help="Canvas size in pixels (default: 600)")
+    parser.add_argument("--color-mode", default="color", choices=["color", "bw", "dark"],
+                        help="Color theme (default: color)")
+    args = parser.parse_args()
+
+    print(f"Rendering test charts — format={args.format}, size={args.size}px, theme={args.color_mode}")
+    print(f"Output directory: /home/shared/")
+    print()
+
+    results = []
+    for name, birth_data in PEOPLE.items():
+        print(f"Processing {name.replace('_', ' ').title()}...")
+        print(f"  Birth: {birth_data['birth_datetime']} @ {birth_data['latitude']}, {birth_data['longitude']}")
+        result = await render_person(name, birth_data, args.format, args.size)
+        if result:
+            results.append(result)
+            print(f"  Saved: {result['output']} ({result['size_bytes']:,} bytes)")
+            if result["moon"]:
+                m = result["moon"]
+                print(f"  MOON: {m['sign']} {m['degree_within_sign']:.1f}° (lon={m['absolute_lon']:.2f}°, house {m['house']})")
+            else:
+                print(f"  MOON: not found in data!")
+            print(f"  Planets: {len(result['all_planets'])}, Houses: {result['houses_count']}, Aspects: {result['aspects_count']}")
+        else:
+            print(f"  FAILED")
+        print()
+
+    # Summary comparison
+    print("=" * 60)
+    print("MOON COMPARISON")
+    print("=" * 60)
+    for r in results:
+        m = r.get("moon", {})
+        if m:
+            print(f"  {r['name']:20s} | Moon in {m.get('sign','?'):12s} {m.get('degree_within_sign',0):5.1f}° | House {m.get('house','?')} | Retrograde: {m.get('retrograde',False)}")
+        else:
+            print(f"  {r['name']:20s} | Moon data MISSING")
+    print()
+
+    # Save JSON summary
+    summary_path = "/home/shared/test_charts_summary.json"
+    with open(summary_path, "w") as f:
+        json.dump(results, f, indent=2, default=str)
+    print(f"Summary saved to: {summary_path}")
+
+
+if __name__ == "__main__":
+    asyncio.run(main())