kopia lustrzana https://github.com/inkstitch/inkstitch
82 wiersze
2.9 KiB
Python
82 wiersze
2.9 KiB
Python
# Authors: see git history
|
|
#
|
|
# Copyright (c) 2023 Authors
|
|
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
|
|
|
from shapely.geometry import MultiPolygon, Polygon
|
|
from shapely.validation import make_valid
|
|
|
|
from ..elements import EmbroideryElement
|
|
from ..utils import ensure_multi_polygon
|
|
from .tags import SVG_GROUP_TAG, SVG_PATH_TAG
|
|
|
|
|
|
def get_clips(node):
|
|
clips = []
|
|
for element in node.iterancestors(SVG_GROUP_TAG):
|
|
if element.clip is not None:
|
|
clips.append(element.clip)
|
|
return clips
|
|
|
|
|
|
def get_clip_path(node):
|
|
# get clip and apply node transform
|
|
clip = _clip_paths(node)
|
|
for group in node.iterancestors(SVG_GROUP_TAG):
|
|
group_clip = _clip_paths(group)
|
|
if clip and group_clip:
|
|
clip = clip.intersection(group_clip)
|
|
elif group_clip:
|
|
clip = group_clip
|
|
if clip:
|
|
return ensure_multi_polygon(clip)
|
|
|
|
|
|
def _clip_paths(node_or_group):
|
|
clip = node_or_group.clip
|
|
if clip is None:
|
|
return
|
|
transform = node_or_group.composed_transform()
|
|
clip.transform = transform
|
|
clip_element = EmbroideryElement(clip)
|
|
path_effect = _get_path_effects(node_or_group)
|
|
clip_paths = None
|
|
if path_effect == 'ignore':
|
|
return
|
|
elif path_effect == 'inverse':
|
|
for path in clip.iterdescendants(SVG_PATH_TAG):
|
|
if path.get('class', None) == 'powerclip':
|
|
original_transform = path.transform
|
|
path.transform @= transform
|
|
clip_element = EmbroideryElement(path)
|
|
clip_paths = [path for path in clip_element.paths if len(path) > 3]
|
|
path.transform = original_transform
|
|
break
|
|
else:
|
|
clip_paths = [path for path in clip_element.paths if len(path) > 3]
|
|
|
|
if clip_paths:
|
|
clip_paths.sort(key=lambda point_list: Polygon(point_list).area, reverse=True)
|
|
return make_valid(MultiPolygon([(clip_paths[0], clip_paths[1:])]))
|
|
|
|
|
|
def _get_path_effects(node):
|
|
path_effects = node.get('inkscape:path-effect', None)
|
|
if path_effects is not None:
|
|
path_effects = path_effects.split(';')
|
|
for path_effect in path_effects:
|
|
effect = node.getroottree().getroot().getElementById(path_effect[1:])
|
|
if effect.get('effect', None) == 'powerclip':
|
|
if effect.get('hide_clip', 'false') in ['1', 'true', 'True']:
|
|
# The clip is inactive
|
|
return 'ignore'
|
|
elif effect.get('flatten', 'false') in ['1', 'true', 'True']:
|
|
# Clipping is already calculated into the path.
|
|
# This means we can ignore the clip.
|
|
return 'ignore'
|
|
elif effect.get('inverse', 'false') in ['1', 'true', 'True']:
|
|
return 'inverse'
|
|
else:
|
|
return 'effect'
|
|
return 'standard'
|