/- Copyright (c) 2025 Henrique Borges. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Davi Barreira, Henrique Borges -/ import Vizagrams.Geom import Vizagrams.Style /-! # Graphical Primitives for Vizagrams This module defines the core graphical primitive type `Prim`, which combines geometric shapes with styling attributes. It provides: - `Prim`: A geometric shape with associated styling (fill color, stroke color, etc.) - Transformation instances for applying geometric transformations and style modifications - Composition operations for combining multiple primitives ## Key Components - **Prim Structure**: Combines a `Geom` (geometric shape) with a `Style` (visual attributes) - **Geometric Transformations**: Apply `Mat2Vec2` transformations to primitives and arrays - **Style Transformations**: Apply `Style` modifications to primitives and arrays - **Composition Operations**: Combine primitives using the `⊕` operator -/ namespace GraphicalPrimitive open GeometricPrimitive open Sty open LinearAlgebra /-- A graphical primitive combining geometric shape with visual styling. This is the fundamental drawing unit in Vizagrams. -/ structure Prim where /-- The geometric shape (circle, line, polygon, etc.) -/ geom : Geom /-- The visual styling (colors, stroke width, etc.) -/ style : Style deriving Repr, Inhabited /-- A single primitive can be treated as an array containing just that primitive. -/ instance : Coe Prim (Array Prim) where coe p := #[p] /-- A primitive can be treated as its underlying geometry. -/ instance : Coe Prim Geom where coe p := p.geom /-- Apply a geometric transformation to a primitive. The transformation affects only the geometry, leaving the style unchanged. -/ instance : HMul Mat2Vec2 Prim Prim where hMul g p := { p with geom := g * p.geom } /-- Apply a geometric transformation to an array of primitives. Each primitive's geometry is transformed independently. -/ instance : HMul Mat2Vec2 (Array Prim) (Array Prim) where hMul g ps := ps.map (g * ·) /-- Apply a style modification to a primitive. The new style is composed with the existing style using the `Append` instance, where the new style takes precedence for conflicting attributes. -/ instance : HMul Style Prim Prim where hMul s p := { p with style := s ++ p.style } /-- Apply a style modification to an array of primitives. Each primitive's style is modified independently. -/ instance : HMul Style (Array Prim) (Array Prim) where hMul s ps := ps.map (s * ·) /-- Apply a style transformation to a single primitive. -/ def applyStyle (s : Style) (p : Prim) : Prim := s * p /-- Apply a style transformation to an array of primitives. -/ def applyStyleArray (s : Style) (ps : Array Prim) : Array Prim := s * ps /-- Apply a geometric transformation to a single primitive. -/ def applyTransform (g : Mat2Vec2) (p : Prim) : Prim := g * p /-- Apply a geometric transformation to an array of primitives. -/ def applyTransformArray (g : Mat2Vec2) (ps : Array Prim) : Array Prim := g * ps /-- Type class for composing graphical primitives into arrays. This enables the `⊕` operator for combining drawing elements. -/ class Compose (α : Type u) (β : Type v) where /-- Compose two graphical elements into an array of primitives. -/ compose : α → β → Array Prim /-- Compose two individual primitives. -/ instance : Compose Prim Prim where compose p₁ p₂ := #[p₁, p₂] /-- Compose a primitive with an array of primitives. -/ instance : Compose Prim (Array Prim) where compose p ps := #[p] ++ ps /-- Compose an array of primitives with a single primitive. -/ instance : Compose (Array Prim) Prim where compose ps p := ps ++ #[p] /-- Compose two arrays of primitives. -/ instance : Compose (Array Prim) (Array Prim) where compose ps₁ ps₂ := ps₁ ++ ps₂ /-- Composition operator for combining graphical primitives. This is the primary way to build complex drawings from simple parts. ## Examples ```lean let circle := Prim.mk (Geom.circle 1.0 ![0,0]) defaultStyle let square := Prim.mk (Geom.rect ![1,1] 2.0 2.0) defaultStyle let combined := circle ⊕ square ``` -/ infixr:80 " ⊕ " => Compose.compose /-- Create a primitive with default styling. -/ def mk (geom : Geom) (style : Style := {}) : Prim := ⟨geom, style⟩ /-- Create a circle primitive with specified radius, center, and optional style. -/ def Prim.circle (r : Float) (c : Vec2 := ![0,0]) (style : Style := {}) : Prim := mk (Geom.circle r c) style /-- Create a line primitive with specified endpoints and optional style. -/ def Prim.line (src trg : Vec2) (style : Style := {}) : Prim := mk (Geom.line src trg) style /-- Create a rectangle primitive with specified corner, dimensions, and optional style. -/ def Prim.rect (corner : Vec2) (width height : Float) (style : Style := {}) : Prim := mk (Geom.rect corner width height) style /-- Create a polygon primitive with specified vertices and optional style. -/ def Prim.polygon (points : Array Vec2) (style : Style := {}) : Prim := mk (Geom.polygon points) style /-- Create a text primitive with specified position, content, size, and optional style. -/ def Prim.text (pos : Vec2) (content : String) (size : Float := 1.0) (style : Style := {}) : Prim := mk (Geom.text pos content size) style end GraphicalPrimitive