-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
599 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] |
Oops, something went wrong.