Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
srush committed Aug 18, 2024
1 parent ca60357 commit fddaeb1
Show file tree
Hide file tree
Showing 5 changed files with 599 additions and 0 deletions.
76 changes: 76 additions & 0 deletions chalk/arrowheads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from colour import Color

import chalk.transform as tx
from chalk.path import Path, from_list_of_tuples
from chalk.types import Diagram

black = Color("black")


def tri() -> Diagram:
from chalk.core import Empty

return (
from_list_of_tuples(
[(1.0, 0), (0.0, -1.0), (-1.0, 0), (1.0, 0)], closed=True
)
# .remove_scale()
.stroke()
.rotate_by(-0.25)
.fill_color(Color("black"))
.center_xy()
.align_r()
.line_width(0)
.with_envelope(Empty())
)


def dart(cut: float = 0.2) -> Diagram:
from chalk.core import Empty

pts = tx.np.stack(
[
tx.P2(0, -cut),
tx.P2(1.0, cut),
tx.P2(0.0, -1.0 - cut),
tx.P2(-1.0, +cut),
tx.P2(0, -cut),
]
)
pts = (
tx.rotation_angle(-90)
@ tx.translation(tx.V2(1.5 * cut, 1 + 3 * cut))
@ pts
)

return (
Path.from_array(
pts,
closed=True,
)
.remove_scale()
.stroke()
.fill_color(Color("black"))
# .rotate_by(-0.25)
# .center_xy()
# .align_r()
.line_width(0)
.with_envelope(Empty())
)


# @dataclass(unsafe_hash=True, frozen=True)
# class ArrowHead(Shape):
# """Arrow Head."""

# arrow_shape: Diagram

# def get_bounding_box(self) -> BoundingBox:
# # Arrow head don't have a bounding box since we can't accurately know
# # the size until rendering
# eps = 1e-4
# self.bb = BoundingBox(tx.origin, tx.origin + P2(eps, eps))
# return self.bb

# def accept(self, visitor: ShapeVisitor[C], **kwargs: Any) -> C:
# return visitor.visit_arrowhead(self, **kwargs)
56 changes: 56 additions & 0 deletions chalk/backend/matplotlib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from __future__ import annotations

from typing import List, Optional

import matplotlib.axes
import matplotlib.collections
import matplotlib.patches
import matplotlib.pyplot as plt
from matplotlib.path import Path

import chalk.transform as tx
from chalk.backend.patch import Patch, order_patches
from chalk.style import StyleHolder
from chalk.types import Diagram

EMPTY_STYLE = StyleHolder.empty()


def render_patches(patches: List[Patch], ax: matplotlib.axes.Axes) -> None:
ps = []
for ind, patch, style_new in order_patches(patches):
ps.append(
matplotlib.patches.PathPatch(
Path(patch.vert[ind] * [1, -1], patch.command[ind]),
**style_new,
)
)

collection = matplotlib.collections.PatchCollection(
ps, match_original=True
)
ax.add_collection(collection)


def patches_to_file(
patches: List[Patch], path: str, height: tx.IntLike, width: tx.IntLike
) -> None:
fig, ax = plt.subplots()
render_patches(patches, ax)
ax.set_xlim((0, width))
ax.set_ylim((-height, 0))
ax.set_aspect("equal")
plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
ax.set_axis_off()
fig.savefig(path, dpi=400)


def render(
self: Diagram,
path: str,
height: int = 128,
width: Optional[int] = None,
draw_height: Optional[int] = None,
) -> None:
prims, h, w = self.layout(height, width, draw_height)
patches_to_file(prims, path, h, w) # type: ignore
116 changes: 116 additions & 0 deletions chalk/path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import Iterable, List, Optional, Tuple

from chalk import transform as tx
from chalk.segment import Segment
from chalk.trail import Located, Trail
from chalk.transform import Batched, P2_t, Transformable
from chalk.types import BatchDiagram


@dataclass(frozen=True)
class Text:
text: tx.Array

def to_str(self) -> str:
return self.text.tostring().decode("utf-8") # type: ignore


@dataclass(unsafe_hash=True)
class Path(Transformable, tx.Batchable):
"""Path class."""

loc_trails: Tuple[Located, ...]
text: Optional[Text] = None
scale_invariant: Optional[tx.Mask] = None

@property
def shape(self) -> Tuple[int, ...]:
if not self.loc_trails:
return ()
return self.loc_trails[0].trail.segments.angles.shape[:-3]

def remove_scale(self) -> Path:
return Path(self.loc_trails, self.text, tx.np.array(True))

def located_segments(self) -> Segment:
ls = Segment.empty()
for loc_trail in self.loc_trails:
if ls is None: # type: ignore
ls = loc_trail.located_segments()
else:
ls += loc_trail.located_segments()
return ls

# Monoid - compose
@staticmethod
def empty() -> Path:
return Path(())

def __add__(self: BatchPath, other: BatchPath) -> BatchPath:
return Path(self.loc_trails + other.loc_trails)

def apply_transform(self: BatchPath, t: tx.Affine) -> BatchPath:
return Path(
tuple(
[loc_trail.apply_transform(t) for loc_trail in self.loc_trails]
)
)

def points(self) -> Iterable[P2_t]:
for loc_trails in self.loc_trails:
for pt in loc_trails.points():
yield pt

def stroke(self: BatchPath) -> BatchDiagram:
"Returns a primitive diagram from a path"

from chalk.core import Primitive

return Primitive.from_path(self)

# Constructors
@staticmethod
def from_array(points: P2_t, closed: bool = False) -> Path:
l = points.shape[0]
if l == 0:
return Path.empty()
offsets = points[tx.np.arange(1, l)] - points[tx.np.arange(0, l - 1)]
trail = Trail.from_array(offsets, closed)
return Path(tuple([trail.at(points[0])]))

# Constructors


def from_points(points: List[P2_t], closed: bool = False) -> Path:
return Path.from_array(tx.np.stack(points))


def from_point(point: P2_t) -> Path:
return from_points([point])


def from_text(s: str) -> Path:
return Path((), Text(tx.np.array(list(s), dtype="S1")))


def from_pairs(segs: List[Tuple[P2_t, P2_t]], closed: bool = False) -> Path:
if not segs:
return Path.empty()
ls = [segs[0][0]]
for seg in segs:
assert seg[0] == ls[-1]
ls.append(seg[1])
return from_points(ls, closed)


def from_list_of_tuples(
coords: List[Tuple[tx.Floating, tx.Floating]], closed: bool = False
) -> Path:
points = list([tx.P2(x, y) for x, y in coords])
return from_points(points, closed)


BatchPath = Batched[Path, "*#B"]
Loading

0 comments on commit fddaeb1

Please sign in to comment.