Remove trailing spaces (#2)
Co-authored-by: Alexey Vazhnov <vazhnov@boot-keys.org> Co-committed-by: Alexey Vazhnov <vazhnov@boot-keys.org>
This commit is contained in:
parent
a939774852
commit
28d25381e2
|
|
@ -9,7 +9,7 @@ class Animation:
|
||||||
"""
|
"""
|
||||||
A class representing an ILDA animation consisting of multiple frames (SVG files).
|
A class representing an ILDA animation consisting of multiple frames (SVG files).
|
||||||
It stores the default ILDA format (e.g. 0), company_name, and projector,
|
It stores the default ILDA format (e.g. 0), company_name, and projector,
|
||||||
which are used when creating sections for each frame.
|
which are used when creating sections for each frame.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
|
|
||||||
116
ilda/frame.py
116
ilda/frame.py
|
|
@ -49,16 +49,16 @@ class Frame:
|
||||||
# Public instance state: only normalized ILDA-format points and colors plus original svg size
|
# Public instance state: only normalized ILDA-format points and colors plus original svg size
|
||||||
points_list: List[List[PointI]] # each path -> list of (x,y,z) int16
|
points_list: List[List[PointI]] # each path -> list of (x,y,z) int16
|
||||||
colors_rgb: List[RGB] # per-path colors as 8-bit rgb
|
colors_rgb: List[RGB] # per-path colors as 8-bit rgb
|
||||||
colors_indexed: List[int] # per-path palette index (0-255)
|
colors_indexed: List[int] # per-path palette index (0-255)
|
||||||
svg_size: Tuple[float, float] # (width, height) of original SVG in user units (floats)
|
svg_size: Tuple[float, float] # (width, height) of original SVG in user units (floats)
|
||||||
point_cnt: int # total points of all paths
|
point_cnt: int # total points of all paths
|
||||||
point_cnt_simpl: int # total points of all paths simplified
|
point_cnt_simpl: int # total points of all paths simplified
|
||||||
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.points_list = []
|
self.points_list = []
|
||||||
self.colors_rgb = []
|
self.colors_rgb = []
|
||||||
self.colors_indexed = []
|
self.colors_indexed = []
|
||||||
self.svg_size = (0.0, 0.0)
|
self.svg_size = (0.0, 0.0)
|
||||||
self.point_cnt = 0
|
self.point_cnt = 0
|
||||||
self.point_cnt_simpl = 0
|
self.point_cnt_simpl = 0
|
||||||
|
|
@ -76,11 +76,11 @@ class Frame:
|
||||||
self.points_list: list of paths; each path is list of (x,y,z) int16 with z=0
|
self.points_list: list of paths; each path is list of (x,y,z) int16 with z=0
|
||||||
self.colors_rgb: per-path (r,g,b) tuples
|
self.colors_rgb: per-path (r,g,b) tuples
|
||||||
self.colors_indexed: per-path 8bit color index from DEFAULT_ilda_palette
|
self.colors_indexed: per-path 8bit color index from DEFAULT_ilda_palette
|
||||||
self.svg_size: (width, height) from svg attributes (floats)
|
self.svg_size: (width, height) from svg attributes (floats)
|
||||||
Notes:
|
Notes:
|
||||||
the viewbox passed to _path_to_points is (xmin, ymin, xmax, ymax) derived from svg size.
|
the viewbox passed to _path_to_points is (xmin, ymin, xmax, ymax) derived from svg size.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Helper: compare two polylines with tolerance
|
# Helper: compare two polylines with tolerance
|
||||||
def _poly_equal(a: List[Tuple[float, float]], b: List[Tuple[float, float]], eps: float = 1e-6) -> bool:
|
def _poly_equal(a: List[Tuple[float, float]], b: List[Tuple[float, float]], eps: float = 1e-6) -> bool:
|
||||||
if len(a) != len(b):
|
if len(a) != len(b):
|
||||||
|
|
@ -89,7 +89,7 @@ class Frame:
|
||||||
if abs(x1 - x2) > eps or abs(y1 - y2) > eps:
|
if abs(x1 - x2) > eps or abs(y1 - y2) > eps:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Helper: append one polyline (list of (x,y) floats) and its attributes to internal lists
|
# Helper: append one polyline (list of (x,y) floats) and its attributes to internal lists
|
||||||
def _append_poly_and_attr(poly: List[Tuple[float, float]], attr: Dict[str, str]) -> None:
|
def _append_poly_and_attr(poly: List[Tuple[float, float]], attr: Dict[str, str]) -> None:
|
||||||
# If poly too short, append empty placeholder and still record color info
|
# If poly too short, append empty placeholder and still record color info
|
||||||
|
|
@ -101,13 +101,13 @@ class Frame:
|
||||||
idx = self._find_best_palette_index(rgb)
|
idx = self._find_best_palette_index(rgb)
|
||||||
self.colors_indexed.append(idx)
|
self.colors_indexed.append(idx)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Simplify polyline using class RDP if requested
|
# Simplify polyline using class RDP if requested
|
||||||
if simplify:
|
if simplify:
|
||||||
processed = self._rdp(poly, tol)
|
processed = self._rdp(poly, tol)
|
||||||
else:
|
else:
|
||||||
processed = poly
|
processed = poly
|
||||||
|
|
||||||
if not processed or len(processed) < 2:
|
if not processed or len(processed) < 2:
|
||||||
self.points_list.append([])
|
self.points_list.append([])
|
||||||
color = self._extract_stroke(attr)
|
color = self._extract_stroke(attr)
|
||||||
|
|
@ -116,28 +116,28 @@ class Frame:
|
||||||
idx = self._find_best_palette_index(rgb)
|
idx = self._find_best_palette_index(rgb)
|
||||||
self.colors_indexed.append(idx)
|
self.colors_indexed.append(idx)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Normalize to ILDA coordinates (use svg_size width/height)
|
# Normalize to ILDA coordinates (use svg_size width/height)
|
||||||
width, height = self.svg_size
|
width, height = self.svg_size
|
||||||
ptsi = [self._normalize_point_to_ilda((x, y), width, height) for (x, y) in processed]
|
ptsi = [self._normalize_point_to_ilda((x, y), width, height) for (x, y) in processed]
|
||||||
ptsi3 = [(int(x), int(y), 0) for (x, y) in ptsi]
|
ptsi3 = [(int(x), int(y), 0) for (x, y) in ptsi]
|
||||||
self.points_list.append(ptsi3)
|
self.points_list.append(ptsi3)
|
||||||
|
|
||||||
# Color handling (duplicate original attr for this fragment)
|
# Color handling (duplicate original attr for this fragment)
|
||||||
color = self._extract_stroke(attr)
|
color = self._extract_stroke(attr)
|
||||||
rgb = self._parse_color_to_rgb(color)
|
rgb = self._parse_color_to_rgb(color)
|
||||||
self.colors_rgb.append(rgb)
|
self.colors_rgb.append(rgb)
|
||||||
idx = self._find_best_palette_index(rgb)
|
idx = self._find_best_palette_index(rgb)
|
||||||
self.colors_indexed.append(idx)
|
self.colors_indexed.append(idx)
|
||||||
|
|
||||||
# Update simplified point counter
|
# Update simplified point counter
|
||||||
self.point_cnt_simpl += len(processed)
|
self.point_cnt_simpl += len(processed)
|
||||||
|
|
||||||
# ---- main body ----
|
# ---- main body ----
|
||||||
paths, attribs, svg_attrib = svg2paths2(infile)
|
paths, attribs, svg_attrib = svg2paths2(infile)
|
||||||
width, height = self._extract_svg_size(svg_attrib)
|
width, height = self._extract_svg_size(svg_attrib)
|
||||||
self.svg_size = (width, height)
|
self.svg_size = (width, height)
|
||||||
|
|
||||||
# Reset internal lists and counters
|
# Reset internal lists and counters
|
||||||
self.points_list = []
|
self.points_list = []
|
||||||
self.colors_rgb = []
|
self.colors_rgb = []
|
||||||
|
|
@ -145,11 +145,11 @@ class Frame:
|
||||||
sample_step = max(0.5, tol / 3.0)
|
sample_step = max(0.5, tol / 3.0)
|
||||||
self.point_cnt = 0
|
self.point_cnt = 0
|
||||||
self.point_cnt_simpl = 0
|
self.point_cnt_simpl = 0
|
||||||
|
|
||||||
# Collect all polylines (after sampling+clipping) and their attributes
|
# Collect all polylines (after sampling+clipping) and their attributes
|
||||||
all_polylines: List[List[Tuple[float, float]]] = []
|
all_polylines: List[List[Tuple[float, float]]] = []
|
||||||
all_attrs: List[Dict[str, str]] = []
|
all_attrs: List[Dict[str, str]] = []
|
||||||
|
|
||||||
for i, path_obj in enumerate(paths):
|
for i, path_obj in enumerate(paths):
|
||||||
# Pass viewbox as (xmin, ymin, xmax, ymax) to _path_to_points
|
# Pass viewbox as (xmin, ymin, xmax, ymax) to _path_to_points
|
||||||
xmin, ymin = 0.0, 0.0
|
xmin, ymin = 0.0, 0.0
|
||||||
|
|
@ -161,19 +161,19 @@ class Frame:
|
||||||
for part in ptsf_parts:
|
for part in ptsf_parts:
|
||||||
all_polylines.append(part)
|
all_polylines.append(part)
|
||||||
all_attrs.append(attr)
|
all_attrs.append(attr)
|
||||||
|
|
||||||
# If nothing found, keep behavior: print and return
|
# If nothing found, keep behavior: print and return
|
||||||
if not all_polylines:
|
if not all_polylines:
|
||||||
print(f"Processing file: {infile} Points: {self.point_cnt} Points (simplified): {self.point_cnt_simpl}")
|
print(f"Processing file: {infile} Points: {self.point_cnt} Points (simplified): {self.point_cnt_simpl}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# optional order polylines to minimize blank travel
|
# optional order polylines to minimize blank travel
|
||||||
if mintravel:
|
if mintravel:
|
||||||
ordered_result = order_paths_greedy_with_2opt(all_polylines, start_point=None, do_2opt=True)
|
ordered_result = order_paths_greedy_with_2opt(all_polylines, start_point=None, do_2opt=True)
|
||||||
ordered_polylines = ordered_result.paths
|
ordered_polylines = ordered_result.paths
|
||||||
else:
|
else:
|
||||||
ordered_polylines = list(all_polylines)
|
ordered_polylines = list(all_polylines)
|
||||||
|
|
||||||
# Map ordered polylines back to original attributes by matching geometry (or reversed)
|
# Map ordered polylines back to original attributes by matching geometry (or reversed)
|
||||||
used_indices = set()
|
used_indices = set()
|
||||||
for poly in ordered_polylines:
|
for poly in ordered_polylines:
|
||||||
|
|
@ -191,7 +191,7 @@ class Frame:
|
||||||
# If no exact match found, use empty attr (rare)
|
# If no exact match found, use empty attr (rare)
|
||||||
matched_attr = {}
|
matched_attr = {}
|
||||||
_append_poly_and_attr(poly, matched_attr)
|
_append_poly_and_attr(poly, matched_attr)
|
||||||
|
|
||||||
print(f"Processing file: {infile} Points: {self.point_cnt} Points (simplified): {self.point_cnt_simpl}")
|
print(f"Processing file: {infile} Points: {self.point_cnt} Points (simplified): {self.point_cnt_simpl}")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -217,7 +217,7 @@ class Frame:
|
||||||
"""
|
"""
|
||||||
if format_code != 0:
|
if format_code != 0:
|
||||||
raise NotImplementedError("Only Format 0 (3D Indexed) is implemented")
|
raise NotImplementedError("Only Format 0 (3D Indexed) is implemented")
|
||||||
|
|
||||||
# helper creating a 32-byte header
|
# helper creating a 32-byte header
|
||||||
def _make_header(fmt: int, name: str, company: str, num_records: int,
|
def _make_header(fmt: int, name: str, company: str, num_records: int,
|
||||||
frame_number: int = 0, total_frames: int = 1, projector: int = 0) -> bytes:
|
frame_number: int = 0, total_frames: int = 1, projector: int = 0) -> bytes:
|
||||||
|
|
@ -233,17 +233,17 @@ class Frame:
|
||||||
b[28:30] = total_frames.to_bytes(2, byteorder='big', signed=False)
|
b[28:30] = total_frames.to_bytes(2, byteorder='big', signed=False)
|
||||||
b[30] = projector & 0xFF
|
b[30] = projector & 0xFF
|
||||||
return bytes(b)
|
return bytes(b)
|
||||||
|
|
||||||
# total number of records (each record = 8 bytes)
|
# total number of records (each record = 8 bytes)
|
||||||
total_points = 0
|
total_points = 0
|
||||||
for path in self.points_list:
|
for path in self.points_list:
|
||||||
total_points += max(0, len(path))
|
total_points += max(0, len(path))
|
||||||
|
|
||||||
if total_points == 0:
|
if total_points == 0:
|
||||||
# Note: a header with num_records=0 is treated as EOF — we do not want to include this
|
# Note: a header with num_records=0 is treated as EOF — we do not want to include this
|
||||||
# in the middle of the animation; we return an error so that Animation can skip this frame.
|
# in the middle of the animation; we return an error so that Animation can skip this frame.
|
||||||
raise ValueError("Frame contains no points; get_ilda() would produce EOF header")
|
raise ValueError("Frame contains no points; get_ilda() would produce EOF header")
|
||||||
|
|
||||||
records = bytearray()
|
records = bytearray()
|
||||||
# determine the index of the last point in this frame -> set the LastPoint bit at the last point of this section
|
# determine the index of the last point in this frame -> set the LastPoint bit at the last point of this section
|
||||||
last_path_idx = -1
|
last_path_idx = -1
|
||||||
|
|
@ -252,7 +252,7 @@ class Frame:
|
||||||
if path:
|
if path:
|
||||||
last_path_idx = pi
|
last_path_idx = pi
|
||||||
last_point_idx = len(path) - 1
|
last_point_idx = len(path) - 1
|
||||||
|
|
||||||
for pi, path in enumerate(self.points_list):
|
for pi, path in enumerate(self.points_list):
|
||||||
if not path:
|
if not path:
|
||||||
continue
|
continue
|
||||||
|
|
@ -267,7 +267,7 @@ class Frame:
|
||||||
records += int(fy).to_bytes(2, byteorder='big', signed=True)
|
records += int(fy).to_bytes(2, byteorder='big', signed=True)
|
||||||
records += int(fz).to_bytes(2, byteorder='big', signed=True)
|
records += int(fz).to_bytes(2, byteorder='big', signed=True)
|
||||||
records += bytes([status, ci])
|
records += bytes([status, ci])
|
||||||
|
|
||||||
# subsequent points (draw), set LastPoint to the last point of this frame/section
|
# subsequent points (draw), set LastPoint to the last point of this frame/section
|
||||||
for pti, (x, y, z) in enumerate(path):
|
for pti, (x, y, z) in enumerate(path):
|
||||||
status = 0
|
status = 0
|
||||||
|
|
@ -280,11 +280,11 @@ class Frame:
|
||||||
records += int(y).to_bytes(2, byteorder='big', signed=True)
|
records += int(y).to_bytes(2, byteorder='big', signed=True)
|
||||||
records += int(z).to_bytes(2, byteorder='big', signed=True)
|
records += int(z).to_bytes(2, byteorder='big', signed=True)
|
||||||
records += bytes([status, ci])
|
records += bytes([status, ci])
|
||||||
|
|
||||||
header = _make_header(format_code, frame_name, company_name, len(records) // 8,
|
header = _make_header(format_code, frame_name, company_name, len(records) // 8,
|
||||||
frame_number=frame_number, total_frames=total_frames, projector=projector)
|
frame_number=frame_number, total_frames=total_frames, projector=projector)
|
||||||
return header + bytes(records)
|
return header + bytes(records)
|
||||||
|
|
||||||
def write_ild(self, filename: str, format_code: int = 0,
|
def write_ild(self, filename: str, format_code: int = 0,
|
||||||
frame_name: str = '00000001', company_name: str = 'MIKLO',
|
frame_name: str = '00000001', company_name: str = 'MIKLO',
|
||||||
frame_number: int = 0, total_frames: int = 1, projector: int = 0) -> None:
|
frame_number: int = 0, total_frames: int = 1, projector: int = 0) -> None:
|
||||||
|
|
@ -314,13 +314,13 @@ class Frame:
|
||||||
b[28:30] = total_frames.to_bytes(2, byteorder='big', signed=False)
|
b[28:30] = total_frames.to_bytes(2, byteorder='big', signed=False)
|
||||||
b[30] = projector & 0xFF
|
b[30] = projector & 0xFF
|
||||||
return bytes(b)
|
return bytes(b)
|
||||||
|
|
||||||
eof_header = _make_eof_header(format_code, frame_name, company_name, frame_number=0, total_frames=0, projector=projector)
|
eof_header = _make_eof_header(format_code, frame_name, company_name, frame_number=0, total_frames=0, projector=projector)
|
||||||
with open(filename, 'wb') as f:
|
with open(filename, 'wb') as f:
|
||||||
f.write(section)
|
f.write(section)
|
||||||
f.write(eof_header)
|
f.write(eof_header)
|
||||||
|
|
||||||
|
|
||||||
def write_svg(self, outfile: str, canvas_size: Optional[Tuple[float, float]] = None) -> None:
|
def write_svg(self, outfile: str, canvas_size: Optional[Tuple[float, float]] = None) -> None:
|
||||||
"""
|
"""
|
||||||
Build an SVG with paths from internal ILDA-normalized integer coordinates.
|
Build an SVG with paths from internal ILDA-normalized integer coordinates.
|
||||||
|
|
@ -333,7 +333,7 @@ class Frame:
|
||||||
target_w, target_h = (ILDA_CANVAS, ILDA_CANVAS)
|
target_w, target_h = (ILDA_CANVAS, ILDA_CANVAS)
|
||||||
else:
|
else:
|
||||||
target_w, target_h = canvas_size
|
target_w, target_h = canvas_size
|
||||||
|
|
||||||
svg_attrs = {
|
svg_attrs = {
|
||||||
'xmlns': 'http://www.w3.org/2000/svg',
|
'xmlns': 'http://www.w3.org/2000/svg',
|
||||||
'width': str(target_w),
|
'width': str(target_w),
|
||||||
|
|
@ -341,10 +341,10 @@ class Frame:
|
||||||
'viewBox': f"0 0 {target_w} {target_h}"
|
'viewBox': f"0 0 {target_w} {target_h}"
|
||||||
}
|
}
|
||||||
root = Element('svg', svg_attrs)
|
root = Element('svg', svg_attrs)
|
||||||
|
|
||||||
scale_x = target_w / float(ILDA_CANVAS)
|
scale_x = target_w / float(ILDA_CANVAS)
|
||||||
scale_y = target_h / float(ILDA_CANVAS)
|
scale_y = target_h / float(ILDA_CANVAS)
|
||||||
|
|
||||||
for idx, pts in enumerate(self.points_list):
|
for idx, pts in enumerate(self.points_list):
|
||||||
if not pts:
|
if not pts:
|
||||||
continue
|
continue
|
||||||
|
|
@ -363,12 +363,12 @@ class Frame:
|
||||||
el.set('stroke', f"rgb({rgb[0]},{rgb[1]},{rgb[2]})")
|
el.set('stroke', f"rgb({rgb[0]},{rgb[1]},{rgb[2]})")
|
||||||
el.set('fill', 'none')
|
el.set('fill', 'none')
|
||||||
el.set('stroke-width', '1.0')
|
el.set('stroke-width', '1.0')
|
||||||
|
|
||||||
tree = ElementTree(root)
|
tree = ElementTree(root)
|
||||||
tree.write(outfile, encoding='utf-8', xml_declaration=True)
|
tree.write(outfile, encoding='utf-8', xml_declaration=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_svg_size(self, svg_attrib: Dict[str, str]) -> Tuple[float, float]:
|
def _extract_svg_size(self, svg_attrib: Dict[str, str]) -> Tuple[float, float]:
|
||||||
vb = svg_attrib.get('viewBox') or svg_attrib.get('viewbox')
|
vb = svg_attrib.get('viewBox') or svg_attrib.get('viewbox')
|
||||||
if vb:
|
if vb:
|
||||||
|
|
@ -396,7 +396,7 @@ class Frame:
|
||||||
if w and h:
|
if w and h:
|
||||||
return (w, h)
|
return (w, h)
|
||||||
return (ILDA_CANVAS, ILDA_CANVAS)
|
return (ILDA_CANVAS, ILDA_CANVAS)
|
||||||
|
|
||||||
def _extract_stroke(self, attr: Dict[str, str]) -> str:
|
def _extract_stroke(self, attr: Dict[str, str]) -> str:
|
||||||
if 'stroke' in attr and attr['stroke'].strip():
|
if 'stroke' in attr and attr['stroke'].strip():
|
||||||
return attr['stroke'].strip()
|
return attr['stroke'].strip()
|
||||||
|
|
@ -410,8 +410,8 @@ class Frame:
|
||||||
if k.strip() == 'stroke' and v.strip():
|
if k.strip() == 'stroke' and v.strip():
|
||||||
return v.strip()
|
return v.strip()
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
def _parse_color_to_rgb(self, color_str: str) -> RGB:
|
def _parse_color_to_rgb(self, color_str: str) -> RGB:
|
||||||
if not color_str:
|
if not color_str:
|
||||||
return (0, 0, 0)
|
return (0, 0, 0)
|
||||||
|
|
@ -451,7 +451,7 @@ class Frame:
|
||||||
if lc in named:
|
if lc in named:
|
||||||
return named[lc]
|
return named[lc]
|
||||||
return (0, 0, 0)
|
return (0, 0, 0)
|
||||||
|
|
||||||
def _path_to_points(self, path: Path, max_segment_length: float, viewbox: Optional[Tuple[float, float, float, float]] = None) -> List[List[PointF]]:
|
def _path_to_points(self, path: Path, max_segment_length: float, viewbox: Optional[Tuple[float, float, float, float]] = None) -> List[List[PointF]]:
|
||||||
"""
|
"""
|
||||||
Sample an svgpathtools Path into one or more polylines (list of point lists).
|
Sample an svgpathtools Path into one or more polylines (list of point lists).
|
||||||
|
|
@ -481,22 +481,22 @@ class Frame:
|
||||||
pts.append(endpt)
|
pts.append(endpt)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# If no clipping requested, return single polyline as single-item list (or empty list if too short)
|
# If no clipping requested, return single polyline as single-item list (or empty list if too short)
|
||||||
if not viewbox:
|
if not viewbox:
|
||||||
return [pts] if len(pts) >= 2 else []
|
return [pts] if len(pts) >= 2 else []
|
||||||
|
|
||||||
# Convert to (xmin,ymin,xmax,ymax) exactly (read_svg should provide this form)
|
# Convert to (xmin,ymin,xmax,ymax) exactly (read_svg should provide this form)
|
||||||
xmin, ymin, xmax, ymax = viewbox
|
xmin, ymin, xmax, ymax = viewbox
|
||||||
|
|
||||||
if len(pts) < 2:
|
if len(pts) < 2:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
pieces = self._clip_polyline_to_rect(pts, (xmin, ymin, xmax, ymax))
|
pieces = self._clip_polyline_to_rect(pts, (xmin, ymin, xmax, ymax))
|
||||||
return pieces
|
return pieces
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _sample_segment(self, seg: Any, max_segment_length: float) -> List[PointF]:
|
def _sample_segment(self, seg: Any, max_segment_length: float) -> List[PointF]:
|
||||||
try:
|
try:
|
||||||
seg_len = seg.length(error=1e-5)
|
seg_len = seg.length(error=1e-5)
|
||||||
|
|
@ -514,8 +514,8 @@ class Frame:
|
||||||
c = seg.point(t)
|
c = seg.point(t)
|
||||||
pts.append((c.real, c.imag))
|
pts.append((c.real, c.imag))
|
||||||
return pts
|
return pts
|
||||||
|
|
||||||
|
|
||||||
def _rdp(self, points: List[PointF], eps: float) -> List[PointF]:
|
def _rdp(self, points: List[PointF], eps: float) -> List[PointF]:
|
||||||
if len(points) < 3:
|
if len(points) < 3:
|
||||||
return points[:]
|
return points[:]
|
||||||
|
|
@ -541,8 +541,8 @@ class Frame:
|
||||||
return left[:-1] + right
|
return left[:-1] + right
|
||||||
else:
|
else:
|
||||||
return [points[0], points[-1]]
|
return [points[0], points[-1]]
|
||||||
|
|
||||||
|
|
||||||
def _normalize_point_to_ilda(self, p: PointF, svg_w: float, svg_h: float) -> Tuple[int, int]:
|
def _normalize_point_to_ilda(self, p: PointF, svg_w: float, svg_h: float) -> Tuple[int, int]:
|
||||||
x, y = p
|
x, y = p
|
||||||
if svg_w <= 0 or svg_h <= 0:
|
if svg_w <= 0 or svg_h <= 0:
|
||||||
|
|
@ -554,8 +554,8 @@ class Frame:
|
||||||
ix = max(INT16_MIN, min(INT16_MAX, ix))
|
ix = max(INT16_MIN, min(INT16_MAX, ix))
|
||||||
iy = max(INT16_MIN, min(INT16_MAX, iy))
|
iy = max(INT16_MIN, min(INT16_MAX, iy))
|
||||||
return (ix, iy)
|
return (ix, iy)
|
||||||
|
|
||||||
|
|
||||||
def _ilda_to_canvas_float(self, p3: PointI) -> Tuple[float, float]:
|
def _ilda_to_canvas_float(self, p3: PointI) -> Tuple[float, float]:
|
||||||
x_int, y_int, _ = p3
|
x_int, y_int, _ = p3
|
||||||
nx = (x_int / ILDA_CANVAS) + 0.5
|
nx = (x_int / ILDA_CANVAS) + 0.5
|
||||||
|
|
@ -563,8 +563,8 @@ class Frame:
|
||||||
fx = nx * ILDA_CANVAS
|
fx = nx * ILDA_CANVAS
|
||||||
fy = ny * ILDA_CANVAS
|
fy = ny * ILDA_CANVAS
|
||||||
return (float(fx), float(fy))
|
return (float(fx), float(fy))
|
||||||
|
|
||||||
|
|
||||||
def _points_to_path_d(self, points: List[Tuple[float, float]], closed: bool) -> str:
|
def _points_to_path_d(self, points: List[Tuple[float, float]], closed: bool) -> str:
|
||||||
if not points:
|
if not points:
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -594,8 +594,8 @@ class Frame:
|
||||||
best_idx = idx
|
best_idx = idx
|
||||||
# Ensure 0-255 range
|
# Ensure 0-255 range
|
||||||
return max(0, min(255, int(best_idx)))
|
return max(0, min(255, int(best_idx)))
|
||||||
|
|
||||||
|
|
||||||
def _clip_polyline_to_rect(self,
|
def _clip_polyline_to_rect(self,
|
||||||
poly: List[PointF],
|
poly: List[PointF],
|
||||||
rect: Tuple[float, float, float, float],
|
rect: Tuple[float, float, float, float],
|
||||||
|
|
@ -611,7 +611,7 @@ class Frame:
|
||||||
xmin, ymin, xmax, ymax = rect
|
xmin, ymin, xmax, ymax = rect
|
||||||
if not poly or xmin >= xmax or ymin >= ymax:
|
if not poly or xmin >= xmax or ymin >= ymax:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
if LineString is not None:
|
if LineString is not None:
|
||||||
# robust, uses geometric intersection
|
# robust, uses geometric intersection
|
||||||
ls = LineString(poly)
|
ls = LineString(poly)
|
||||||
|
|
@ -633,5 +633,3 @@ class Frame:
|
||||||
# ignore points etc.
|
# ignore points etc.
|
||||||
_extract_lines(inter)
|
_extract_lines(inter)
|
||||||
return parts
|
return parts
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue