Skip to content

Commit

Permalink
Add clockwise=False option to control outermost contour direction
Browse files Browse the repository at this point in the history
Fixes #30
  • Loading branch information
anthrotype committed Sep 27, 2020
1 parent b30b511 commit 41a136e
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 18 deletions.
18 changes: 15 additions & 3 deletions src/python/pathops/_pathops.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,12 @@ cdef class Path:

cpdef reverse(self)

cpdef simplify(self, bint fix_winding=*, bint keep_starting_points=*)
cpdef simplify(
self,
bint fix_winding=*,
bint keep_starting_points=*,
bint clockwise=*,
)

cpdef convertConicsToQuads(self, float tolerance=*)

Expand Down Expand Up @@ -279,7 +284,7 @@ cdef int path_is_inside(const SkPath& self, const SkPath& other) except -1
cpdef int restore_starting_points(Path path, list points) except -1


cpdef bint winding_from_even_odd(Path path, bint truetype=*) except False
cpdef bint winding_from_even_odd(Path path, bint clockwise=*) except False


cdef list _decompose_quadratic_segment(tuple points)
Expand Down Expand Up @@ -309,10 +314,16 @@ cpdef Path op(
SkPathOp operator,
bint fix_winding=*,
bint keep_starting_points=*,
bint clockwise=*,
)


cpdef Path simplify(Path path, bint fix_winding=*, bint keep_starting_points=*)
cpdef Path simplify(
Path path,
bint fix_winding=*,
bint keep_starting_points=*,
bint clockwise=*,
)


cdef class OpBuilder:
Expand All @@ -321,6 +332,7 @@ cdef class OpBuilder:
cdef bint fix_winding
cdef bint keep_starting_points
cdef list first_points
cdef bint clockwise

cpdef add(self, Path path, SkPathOp operator)

Expand Down
41 changes: 29 additions & 12 deletions src/python/pathops/_pathops.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -345,14 +345,19 @@ cdef class Path:
skpath.addPath(contour.path)
self.path = skpath

cpdef simplify(self, bint fix_winding=True, bint keep_starting_points=True):
cpdef simplify(
self,
bint fix_winding=True,
bint keep_starting_points=True,
bint clockwise=False,
):
cdef list first_points
if keep_starting_points:
first_points = self.firstPoints
if not Simplify(self.path, &self.path):
raise PathOpsError("simplify operation did not succeed")
if fix_winding:
winding_from_even_odd(self)
winding_from_even_odd(self, clockwise)
if keep_starting_points:
restore_starting_points(self, first_points)

Expand Down Expand Up @@ -1116,23 +1121,23 @@ DEF DEBUG_WINDING = False

@cython.wraparound(False)
@cython.boundscheck(False)
cpdef bint winding_from_even_odd(Path path, bint truetype=False) except False:
cpdef bint winding_from_even_odd(Path path, bint clockwise=False) except False:
""" Take a simplified path (without overlaps) and set the contours
directions according to the non-zero winding fill type.
The outermost contours are set to counter-clockwise direction, unless
'truetype' is True.
'clockwise' is True.
"""
# TODO re-enable this once the new feature is stabilized in upstream skia
# https://github.com/fonttools/skia-pathops/issues/10
# if AsWinding(path.path, &path.path):
# if path.clockwise ^ truetype:
# if path.clockwise ^ clockwise:
# path.reverse()
# return True
#
# # in the unlikely event the built-in method fails, try our naive approach

cdef int i, j
cdef bint inverse = not truetype
cdef bint inverse = not clockwise
cdef bint is_clockwise, is_even
cdef Path contour, other

Expand Down Expand Up @@ -1375,7 +1380,8 @@ cpdef Path op(
Path two,
SkPathOp operator,
bint fix_winding=True,
bint keep_starting_points=True
bint keep_starting_points=True,
bint clockwise=False,
):
cdef list first_points
if keep_starting_points:
Expand All @@ -1384,32 +1390,43 @@ cpdef Path op(
if not Op(one.path, two.path, operator, &result.path):
raise PathOpsError("operation did not succeed")
if fix_winding:
winding_from_even_odd(result)
winding_from_even_odd(result, clockwise)
if keep_starting_points:
restore_starting_points(result, first_points)
return result


cpdef Path simplify(Path path, bint fix_winding=True, bint keep_starting_points=True):
cpdef Path simplify(
Path path,
bint fix_winding=True,
bint keep_starting_points=True,
bint clockwise=False,
):
cdef list first_points
if keep_starting_points:
first_points = path.firstPoints
cdef Path result = Path()
if not Simplify(path.path, &result.path):
raise PathOpsError("operation did not succeed")
if fix_winding:
winding_from_even_odd(result)
winding_from_even_odd(result, clockwise)
if keep_starting_points:
restore_starting_points(result, first_points)
return result


cdef class OpBuilder:

def __init__(self, bint fix_winding=True, bint keep_starting_points=True):
def __init__(
self,
bint fix_winding=True,
bint keep_starting_points=True,
bint clockwise=False,
):
self.fix_winding = fix_winding
self.keep_starting_points = keep_starting_points
self.first_points = []
self.clockwise = clockwise

cpdef add(self, Path path, SkPathOp operator):
self.builder.add(path.path, operator)
Expand All @@ -1421,7 +1438,7 @@ cdef class OpBuilder:
if not self.builder.resolve(&result.path):
raise PathOpsError("operation did not succeed")
if self.fix_winding:
winding_from_even_odd(result)
winding_from_even_odd(result, self.clockwise)
if self.keep_starting_points:
restore_starting_points(result, self.first_points)
return result
Expand Down
21 changes: 18 additions & 3 deletions src/python/pathops/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@ def _draw(contours):
return path


def union(contours, outpen, fix_winding=True, keep_starting_points=True):
def union(
contours,
outpen,
fix_winding=True,
keep_starting_points=True,
clockwise=False,
):
if not contours:
return
path = _draw(contours)
path.simplify(
fix_winding=fix_winding,
keep_starting_points=keep_starting_points
keep_starting_points=keep_starting_points,
clockwise=clockwise,
)
path.draw(outpen)

Expand All @@ -37,10 +44,18 @@ def _do(
outpen,
fix_winding=True,
keep_starting_points=True,
clockwise=False,
):
one = _draw(subject_contours)
two = _draw(clip_contours)
result = op(one, two, operator, fix_winding, keep_starting_points)
result = op(
one,
two,
operator,
fix_winding=fix_winding,
keep_starting_points=keep_starting_points,
clockwise=clockwise,
)
result.draw(outpen)


Expand Down

0 comments on commit 41a136e

Please sign in to comment.