kopia lustrzana https://github.com/evil-mad/EggBot
Hatch Fill Fix
In this commit, I changed the way that hatches are created. Previously, the program would collect relevant Svg objects in recursivelyTraverseSvg and then later in the effect method generate hatches or crosshatches and detect interstices. This lead to bug when multiple complex shapes were selected at one time. To prevent these types of grouping bugs, I altered the recursivelyTraverseSvg file to create individualized hatches for Svg objects when they are found while parsing the tree. Then in the effect function these hatches are paired with their parent object via joinFillsWithNode. To accomplish this, I only needed to alter the structure of the program. The underlying functions which create the hatches haven't been changed. The largest looking change is the shift left I had to do to the majority of the effect function thanks to an if-statement that has been moved from the effect function to the recursivelyTraverseSvg functionpull/92/head
rodzic
f6c3729710
commit
27c06619f0
Plik binarny nie jest wyświetlany.
|
@ -33,7 +33,7 @@ Hatched figures will be grouped with their fills.
|
|||
<param name="holdBackSteps" type="float" min="0.1" max="10.0" _gui-text=" Inset distance (px) (default: 1)">1.0</param>
|
||||
<param name="tolerance" type="float" min="0.1" max="100" _gui-text=" Tolerance (default: 20)">20.0</param>
|
||||
<param name="footer" type="description" xml:space="preserve">
|
||||
(v2.0.1, December 23, 2016)</_param>
|
||||
(v2.1.0, December 8, 2017)</_param>
|
||||
|
||||
</page>
|
||||
<page name="info" _gui-text="More info...">
|
||||
|
|
|
@ -79,7 +79,16 @@
|
|||
# Added feature: Option to join hatch segments that are "nearby", to minimize pen lifts
|
||||
# The joins are made using cubic Bezier segments.
|
||||
# https://github.com/evil-mad/EggBot/issues/36
|
||||
#
|
||||
#
|
||||
# Updated by Nathan Depew, 12/6/2017
|
||||
# Modified hatch fill to create hatches as a relevant object it found on the SVG tree
|
||||
# This prevents extremely complex plots from generating glitches
|
||||
# Modifications are limited to recursivelyTraverseSvg and effect methods
|
||||
#
|
||||
# Current software version:
|
||||
# (v2.1.0, December 7, 2017)
|
||||
#
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
|
@ -778,8 +787,21 @@ class Eggbot_Hatch( inkex.Effect ):
|
|||
<defs>, <eggbot>, <metadata>, <namedview>, <pattern>
|
||||
|
||||
All other SVG elements trigger an error (including <text>)
|
||||
'''
|
||||
|
||||
Once a supported graphical element is found, we call functions to
|
||||
create a hatchfil specific to this element. These hatches and their
|
||||
corresponding transforms are stored in self.hatches and self.transforms
|
||||
These two dictionaries are used when we return to the effect method
|
||||
in joinFillsWithNode()
|
||||
|
||||
'''
|
||||
for node in aNodeList:
|
||||
'''
|
||||
Initialize dictionary for each new node
|
||||
This allows us to create hatch fills as if each
|
||||
object to be hatched has been selected individually
|
||||
|
||||
'''
|
||||
# Ignore invisible nodes
|
||||
v = node.get( 'visibility', parent_visibility )
|
||||
if v == 'inherit':
|
||||
|
@ -832,6 +854,19 @@ class Eggbot_Hatch( inkex.Effect ):
|
|||
path_data = node.get( 'd')
|
||||
if path_data:
|
||||
self.addPathVertices( path_data, node, matNew )
|
||||
# We now have a path we want to apply a (cross)hatch to
|
||||
# Apply appropriate functions
|
||||
bHaveGrid = self.makeHatchGrid( float( self.options.hatchAngle ),float( self.options.hatchSpacing ), True )
|
||||
if bHaveGrid:
|
||||
if self.options.crossHatch:
|
||||
self.makeHatchGrid( float( self.options.hatchAngle + 90.0 ),float( self.options.hatchSpacing ), False )
|
||||
# if self.options.crossHatch:
|
||||
# Now loop over our hatch lines looking for intersections
|
||||
for h in self.grid:
|
||||
interstices( self, (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.options.holdBackHatchFromEdges, self.options.holdBackSteps )
|
||||
# if bHaveGrid
|
||||
else:
|
||||
inkex.errormsg( ' Nothing to plot' )
|
||||
|
||||
elif node.tag == inkex.addNS( 'rect', 'svg' ) or node.tag == 'rect':
|
||||
|
||||
|
@ -860,7 +895,19 @@ class Eggbot_Hatch( inkex.Effect ):
|
|||
a.append( [' l ', [-w, 0]] )
|
||||
a.append( [' Z', []] )
|
||||
self.addPathVertices( simplepath.formatPath( a ), node, matNew )
|
||||
|
||||
# We now have a path we want to apply a (cross)hatch to
|
||||
# Apply appropriate functions
|
||||
bHaveGrid = self.makeHatchGrid( float( self.options.hatchAngle ),float( self.options.hatchSpacing ), True )
|
||||
if bHaveGrid:
|
||||
if self.options.crossHatch:
|
||||
self.makeHatchGrid( float( self.options.hatchAngle + 90.0 ),float( self.options.hatchSpacing ), False )
|
||||
# if self.options.crossHatch:
|
||||
# Now loop over our hatch lines looking for intersections
|
||||
for h in self.grid:
|
||||
interstices( self, (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.options.holdBackHatchFromEdges, self.options.holdBackSteps )
|
||||
# if bHaveGrid
|
||||
else:
|
||||
inkex.errormsg( ' Nothing to plot' )
|
||||
elif node.tag == inkex.addNS( 'line', 'svg' ) or node.tag == 'line':
|
||||
|
||||
# Convert
|
||||
|
@ -881,7 +928,19 @@ class Eggbot_Hatch( inkex.Effect ):
|
|||
a.append( ['M ', [x1, y1]] )
|
||||
a.append( [' L ', [x2, y2]] )
|
||||
self.addPathVertices( simplepath.formatPath( a ), node, matNew )
|
||||
|
||||
# We now have a path we want to apply a (cross)hatch to
|
||||
# Apply appropriate functions
|
||||
bHaveGrid = self.makeHatchGrid( float( self.options.hatchAngle ),float( self.options.hatchSpacing ), True )
|
||||
if bHaveGrid:
|
||||
if self.options.crossHatch:
|
||||
self.makeHatchGrid( float( self.options.hatchAngle + 90.0 ),float( self.options.hatchSpacing ), False )
|
||||
# if self.options.crossHatch:
|
||||
# Now loop over our hatch lines looking for intersections
|
||||
for h in self.grid:
|
||||
interstices( self, (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.options.holdBackHatchFromEdges, self.options.holdBackSteps )
|
||||
# if bHaveGrid
|
||||
else:
|
||||
inkex.errormsg( ' Nothing to plot' )
|
||||
elif node.tag == inkex.addNS( 'polyline', 'svg' ) or node.tag == 'polyline':
|
||||
|
||||
# Convert
|
||||
|
@ -901,7 +960,20 @@ class Eggbot_Hatch( inkex.Effect ):
|
|||
pa = pl.split()
|
||||
d = "".join( ["M " + pa[i] if i == 0 else " L " + pa[i] for i in range( 0, len( pa ) )] )
|
||||
self.addPathVertices( d, node, matNew )
|
||||
|
||||
# We now have a path we want to apply a (cross)hatch to
|
||||
# Apply appropriate functions
|
||||
bHaveGrid = self.makeHatchGrid( float( self.options.hatchAngle ),float( self.options.hatchSpacing ), True )
|
||||
if bHaveGrid:
|
||||
if self.options.crossHatch:
|
||||
self.makeHatchGrid( float( self.options.hatchAngle + 90.0 ),float( self.options.hatchSpacing ), False )
|
||||
# if self.options.crossHatch:
|
||||
# Now loop over our hatch lines looking for intersections
|
||||
for h in self.grid:
|
||||
interstices( self, (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.options.holdBackHatchFromEdges, self.options.holdBackSteps )
|
||||
# if bHaveGrid
|
||||
else:
|
||||
inkex.errormsg( ' Nothing to plot' )
|
||||
|
||||
elif node.tag == inkex.addNS( 'polygon', 'svg' ) or node.tag == 'polygon':
|
||||
# Convert
|
||||
#
|
||||
|
@ -921,6 +993,19 @@ class Eggbot_Hatch( inkex.Effect ):
|
|||
d = "".join( ["M " + pa[i] if i == 0 else " L " + pa[i] for i in range( 0, len( pa ) )] )
|
||||
d += " Z"
|
||||
self.addPathVertices( d, node, matNew )
|
||||
# We now have a path we want to apply a (cross)hatch to
|
||||
# Apply appropriate functions
|
||||
bHaveGrid = self.makeHatchGrid( float( self.options.hatchAngle ),float( self.options.hatchSpacing ), True )
|
||||
if bHaveGrid:
|
||||
if self.options.crossHatch:
|
||||
self.makeHatchGrid( float( self.options.hatchAngle + 90.0 ),float( self.options.hatchSpacing ), False )
|
||||
# if self.options.crossHatch:
|
||||
# Now loop over our hatch lines looking for intersections
|
||||
for h in self.grid:
|
||||
interstices( self, (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.options.holdBackHatchFromEdges, self.options.holdBackSteps )
|
||||
# if bHaveGrid
|
||||
else:
|
||||
inkex.errormsg( ' Nothing to plot' )
|
||||
|
||||
elif node.tag == inkex.addNS( 'ellipse', 'svg' ) or \
|
||||
node.tag == 'ellipse' or \
|
||||
|
@ -962,6 +1047,19 @@ class Eggbot_Hatch( inkex.Effect ):
|
|||
'A %f,%f ' % ( rx, ry ) + \
|
||||
'0 1 0 %f,%f' % ( x1, cy )
|
||||
self.addPathVertices( d, node, matNew )
|
||||
# We now have a path we want to apply a (cross)hatch to
|
||||
# Apply appropriate functions
|
||||
bHaveGrid = self.makeHatchGrid( float( self.options.hatchAngle ),float( self.options.hatchSpacing ), True )
|
||||
if bHaveGrid:
|
||||
if self.options.crossHatch:
|
||||
self.makeHatchGrid( float( self.options.hatchAngle + 90.0 ),float( self.options.hatchSpacing ), False )
|
||||
# if self.options.crossHatch:
|
||||
# Now loop over our hatch lines looking for intersections
|
||||
for h in self.grid:
|
||||
interstices( self, (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.options.holdBackHatchFromEdges, self.options.holdBackSteps )
|
||||
# if bHaveGrid
|
||||
else:
|
||||
inkex.errormsg( ' Nothing to plot' )
|
||||
|
||||
elif node.tag == inkex.addNS( 'pattern', 'svg' ) or node.tag == 'pattern':
|
||||
pass
|
||||
|
@ -1136,324 +1234,309 @@ class Eggbot_Hatch( inkex.Effect ):
|
|||
# Traverse the entire document
|
||||
self.recursivelyTraverseSvg( self.document.getroot(), self.docTransform )
|
||||
|
||||
# Build a grid of possible hatch lines
|
||||
bHaveGrid = self.makeHatchGrid( float( self.options.hatchAngle ),
|
||||
float( self.options.hatchSpacing ), True )
|
||||
# makeHatchGrid returns false if could not make grid - probably because bounding box is non-existent
|
||||
if bHaveGrid:
|
||||
if self.options.crossHatch:
|
||||
self.makeHatchGrid( float( self.options.hatchAngle + 90.0 ),
|
||||
float( self.options.hatchSpacing ), False )
|
||||
# if self.options.crossHatch:
|
||||
# After recursively traversing the svg, we will have a dictionary of transforms and hatches
|
||||
|
||||
# Now loop over our hatch lines looking for intersections
|
||||
for h in self.grid:
|
||||
interstices( self, (h[0], h[1]), (h[2], h[3]), self.paths, self.hatches, self.options.holdBackHatchFromEdges, self.options.holdBackSteps )
|
||||
|
||||
# Target stroke width will be (doc width + doc height) / 2 / 1000
|
||||
# stroke_width_target = ( self.docHeight + self.docWidth ) / 2000
|
||||
# stroke_width_target = 1
|
||||
stroke_width_target = 1
|
||||
# Each hatch line stroke will be within an SVG object which may
|
||||
# be subject to transforms. So, on an object by object basis,
|
||||
# we need to transform our target width to a width suitable
|
||||
# for that object (so that after the object and its hatches are
|
||||
# transformed, the result has the desired width).
|
||||
# Target stroke width will be (doc width + doc height) / 2 / 1000
|
||||
# stroke_width_target = ( self.docHeight + self.docWidth ) / 2000
|
||||
# stroke_width_target = 1
|
||||
stroke_width_target = 1
|
||||
# Each hatch line stroke will be within an SVG object which may
|
||||
# be subject to transforms. So, on an object by object basis,
|
||||
# we need to transform our target width to a width suitable
|
||||
# for that object (so that after the object and its hatches are
|
||||
# transformed, the result has the desired width).
|
||||
|
||||
# To aid in the process, we use a diagonal line segment of length
|
||||
# stroke_width_target. We then run this segment through an object's
|
||||
# inverse transform and see what the resulting length of the inversely
|
||||
# transformed segment is. We could, alternatively, look at the
|
||||
# x and y scaling factors in the transform and average them.
|
||||
s = stroke_width_target / math.sqrt( 2 )
|
||||
# To aid in the process, we use a diagonal line segment of length
|
||||
# stroke_width_target. We then run this segment through an object's
|
||||
# inverse transform and see what the resulting length of the inversely
|
||||
# transformed segment is. We could, alternatively, look at the
|
||||
# x and y scaling factors in the transform and average them.
|
||||
s = stroke_width_target / math.sqrt( 2 )
|
||||
|
||||
# Now, dump the hatch fills sorted by which document element
|
||||
# they correspond to. This is made easy by the fact that we
|
||||
# saved the information and used each element's lxml.etree node
|
||||
# pointer as the dictionary key under which to save the hatch
|
||||
# fills for that node.
|
||||
# Now, dump the hatch fills sorted by which document element
|
||||
# they correspond to. This is made easy by the fact that we
|
||||
# saved the information and used each element's lxml.etree node
|
||||
# pointer as the dictionary key under which to save the hatch
|
||||
# fills for that node.
|
||||
|
||||
absoluteLineSegments = {}
|
||||
nAbsoluteLineSegmentTotal = 0
|
||||
nPenLifts = 0
|
||||
# To implement
|
||||
for key in self.hatches:
|
||||
direction = True
|
||||
if self.transforms.has_key( key ):
|
||||
transform = inverseTransform( self.transforms[key] )
|
||||
# Determine the scaled stroke width for a hatch line
|
||||
# We produce a line segment of unit length, transform
|
||||
# its endpoints and then determine the length of the
|
||||
# resulting line segment.
|
||||
pt1 = [0, 0]
|
||||
pt2 = [s, s]
|
||||
simpletransform.applyTransformToPoint( transform, pt1 )
|
||||
simpletransform.applyTransformToPoint( transform, pt2 )
|
||||
dx = pt2[0] - pt1[0]
|
||||
dy = pt2[1] - pt1[1]
|
||||
stroke_width = math.sqrt( dx * dx + dy * dy )
|
||||
else:
|
||||
transform = None
|
||||
stroke_width = float( 1.0 )
|
||||
|
||||
# The transform also applies to the hatch spacing we use when searching for end connections
|
||||
transformedHatchSpacing = stroke_width * self.options.hatchSpacing
|
||||
|
||||
absoluteLineSegments = {}
|
||||
nAbsoluteLineSegmentTotal = 0
|
||||
nPenLifts = 0
|
||||
# To implement
|
||||
for key in self.hatches:
|
||||
direction = True
|
||||
if self.transforms.has_key( key ):
|
||||
transform = inverseTransform( self.transforms[key] )
|
||||
# Determine the scaled stroke width for a hatch line
|
||||
# We produce a line segment of unit length, transform
|
||||
# its endpoints and then determine the length of the
|
||||
# resulting line segment.
|
||||
pt1 = [0, 0]
|
||||
pt2 = [s, s]
|
||||
simpletransform.applyTransformToPoint( transform, pt1 )
|
||||
simpletransform.applyTransformToPoint( transform, pt2 )
|
||||
dx = pt2[0] - pt1[0]
|
||||
dy = pt2[1] - pt1[1]
|
||||
stroke_width = math.sqrt( dx * dx + dy * dy )
|
||||
else:
|
||||
transform = None
|
||||
stroke_width = float( 1.0 )
|
||||
path = '' # regardless of whether or not we're reducing pen lifts
|
||||
ptLastPositionAbsolute = [ 0,0 ]
|
||||
ptLastPositionAbsolute[0] = 0
|
||||
ptLastPositionAbsolute[1] = 0
|
||||
fDistanceMovedWithPenUp = 0
|
||||
if not self.options.reducePenLifts:
|
||||
for segment in self.hatches[key]:
|
||||
if len( segment ) < 2:
|
||||
continue
|
||||
pt1 = segment[0]
|
||||
pt2 = segment[1]
|
||||
# Okay, we're going to put these hatch lines into the same
|
||||
# group as the element they hatch. That element is down
|
||||
# some chain of SVG elements, some of which may have
|
||||
# transforms attached. But, our hatch lines have been
|
||||
# computed assuming that those transforms have already
|
||||
# been applied (since we had to apply them so as to know
|
||||
# where this element is on the page relative to other
|
||||
# elements and their transforms). So, we need to invert
|
||||
# the transforms for this element and then either apply
|
||||
# that inverse transform here and now or set it in a
|
||||
# transform attribute of the <path> element. Having it
|
||||
# set in the path element seems a bit counterintuitive
|
||||
# after the fact (i.e., what's this tranform here for?).
|
||||
# So, we compute the inverse transform and apply it here.
|
||||
if transform != None:
|
||||
simpletransform.applyTransformToPoint( transform, pt1 )
|
||||
simpletransform.applyTransformToPoint( transform, pt2 )
|
||||
# Now generate the path data for the <path>
|
||||
if direction:
|
||||
# Go this direction
|
||||
path += ( 'M %f,%f l %f,%f ' %
|
||||
( pt1[0], pt1[1], pt2[0] - pt1[0], pt2[1] - pt1[1] ) )
|
||||
else:
|
||||
# Or go this direction
|
||||
path += ( 'M %f,%f l %f,%f ' %
|
||||
( pt2[0], pt2[1], pt1[0] - pt2[0], pt1[1] - pt2[1] ) )
|
||||
|
||||
direction = not direction
|
||||
# for segment in self.hatches[key]:
|
||||
self.joinFillsWithNode( key, stroke_width, path[:-1] )
|
||||
|
||||
# The transform also applies to the hatch spacing we use when searching for end connections
|
||||
transformedHatchSpacing = stroke_width * self.options.hatchSpacing
|
||||
|
||||
path = '' # regardless of whether or not we're reducing pen lifts
|
||||
ptLastPositionAbsolute = [ 0,0 ]
|
||||
ptLastPositionAbsolute[0] = 0
|
||||
ptLastPositionAbsolute[1] = 0
|
||||
fDistanceMovedWithPenUp = 0
|
||||
if not self.options.reducePenLifts:
|
||||
for segment in self.hatches[key]:
|
||||
if len( segment ) < 2:
|
||||
continue
|
||||
else: # if not self.options.reducePenLifts:
|
||||
for segment in self.hatches[key]:
|
||||
if len( segment ) < 2: # Copied from original, no idea why this is needed [sbm]
|
||||
continue
|
||||
if ( direction ):
|
||||
pt1 = segment[0]
|
||||
pt2 = segment[1]
|
||||
# Okay, we're going to put these hatch lines into the same
|
||||
# group as the element they hatch. That element is down
|
||||
# some chain of SVG elements, some of which may have
|
||||
# transforms attached. But, our hatch lines have been
|
||||
# computed assuming that those transforms have already
|
||||
# been applied (since we had to apply them so as to know
|
||||
# where this element is on the page relative to other
|
||||
# elements and their transforms). So, we need to invert
|
||||
# the transforms for this element and then either apply
|
||||
# that inverse transform here and now or set it in a
|
||||
# transform attribute of the <path> element. Having it
|
||||
# set in the path element seems a bit counterintuitive
|
||||
# after the fact (i.e., what's this tranform here for?).
|
||||
# So, we compute the inverse transform and apply it here.
|
||||
if transform != None:
|
||||
simpletransform.applyTransformToPoint( transform, pt1 )
|
||||
simpletransform.applyTransformToPoint( transform, pt2 )
|
||||
# Now generate the path data for the <path>
|
||||
if direction:
|
||||
# Go this direction
|
||||
else:
|
||||
pt1 = segment[1]
|
||||
pt2 = segment[0]
|
||||
# Okay, we're going to put these hatch lines into the same
|
||||
# group as the element they hatch. That element is down
|
||||
# some chain of SVG elements, some of which may have
|
||||
# transforms attached. But, our hatch lines have been
|
||||
# computed assuming that those transforms have already
|
||||
# been applied (since we had to apply them so as to know
|
||||
# where this element is on the page relative to other
|
||||
# elements and their transforms). So, we need to invert
|
||||
# the transforms for this element and then either apply
|
||||
# that inverse transform here and now or set it in a
|
||||
# transform attribute of the <path> element. Having it
|
||||
# set in the path element seems a bit counterintuitive
|
||||
# after the fact (i.e., what's this tranform here for?).
|
||||
# So, we compute the inverse transform and apply it here.
|
||||
if transform != None:
|
||||
simpletransform.applyTransformToPoint( transform, pt1 )
|
||||
simpletransform.applyTransformToPoint( transform, pt2 )
|
||||
|
||||
# Now generate the path data for the <path>
|
||||
# BUT we want to combine as many paths as possible to reduce pen lifts.
|
||||
# In order to combine paths, we need to know all of the path segments.
|
||||
# The solution to this conundrum is to generate all path segments,
|
||||
# but instead of drawing them into the path right away, we put them in
|
||||
# an array where they'll be available for random access
|
||||
# by our anti-pen-lift algorithm
|
||||
absoluteLineSegments[ nAbsoluteLineSegmentTotal ] = [ pt1, pt2, False ] # False indicates that segment has not yet been drawn
|
||||
nAbsoluteLineSegmentTotal += 1
|
||||
direction = not direction
|
||||
# for segment in self.hatches[key]:
|
||||
|
||||
# Now have a nice juicy buffer full of line segments with absolute coordinates
|
||||
fProposedNeighborhoodRadiusSquared = self.ProposeNeighborhoodRadiusSquared( transformedHatchSpacing ) # Just fixed and simple for now - may make function of neighborhood later
|
||||
for referenceCount in range( nAbsoluteLineSegmentTotal ): # This is the entire range of segments,
|
||||
# Sets global referenceCount to segment which has an end closest to current pen position.
|
||||
# Doesn't need to select which end is closest, as that will happen below, with nReferenceEndIndex.
|
||||
# When we have gone thru this whole range, we will be completely done.
|
||||
# We only get here again, after all _connected_ segments have been "drawn".
|
||||
if ( not absoluteLineSegments[referenceCount][2] ): # Test whether this segment has been drawn
|
||||
# Has not been drawn yet
|
||||
|
||||
# Before we do any irrevocable changes to path, let's see if we are going to be able to append any segments.
|
||||
# The below solution is inelegant, but has the virtue of being relatively simple to implement.
|
||||
# Pre-qualify this segment on the issue of whether it has any connecting segments.
|
||||
# If it does not, then just add the path for this one segment, and go on to the next.
|
||||
# If it does have connecting segments, we need to go through the recursive logic.
|
||||
# Lazily, again, select the desired direction of line ahead of time.
|
||||
|
||||
bFoundSegmentToAdd = False # default assumption
|
||||
nReferenceEndIndexAtClosest = 0
|
||||
nInnerCountAtClosest = -1
|
||||
fClosestDistanceSquared = 123456 # just a random large number
|
||||
for nReferenceEndIndex in range( 2 ):
|
||||
ptReference = absoluteLineSegments[referenceCount][nReferenceEndIndex]
|
||||
ptReferenceOtherEnd = absoluteLineSegments[referenceCount][not nReferenceEndIndex]
|
||||
fReferenceDirectionRadians = math.atan2( ptReferenceOtherEnd[1] - ptReference[1], ptReferenceOtherEnd[0] - ptReference[0] ) # from other end to this end
|
||||
# The following is just a simple copy from the routine in recursivelyAppendNearbySegmentIfAny procedure
|
||||
# Look through all possibilities to choose the closest that fulfills all requirements e.g. direction and colinearity
|
||||
for innerCount in range( nAbsoluteLineSegmentTotal ): # investigate all segments
|
||||
if ( not absoluteLineSegments[innerCount][2] ):
|
||||
# This segment currently undrawn, so it is a candidate for a path extension
|
||||
# Need to check both ends of each and every proposed segment so we can find the most appropriate one
|
||||
# Define pt2 in the reference as the end which we want to extend
|
||||
for nNewSegmentInitialEndIndex in range( 2 ):
|
||||
# First try initial end of test segment (aka pt1) vs final end (aka pt2) of reference segment
|
||||
if ( innerCount != referenceCount ): # don't investigate self ends
|
||||
deltaX = absoluteLineSegments[innerCount][nNewSegmentInitialEndIndex][0] - ptReference[0] # proposed initial pt1 X minus existing final pt1 X
|
||||
deltaY = absoluteLineSegments[innerCount][nNewSegmentInitialEndIndex][1] - ptReference[1] # proposed initial pt1 Y minus existing final pt1 Y
|
||||
if ( ( deltaX * deltaX + deltaY * deltaY ) < fProposedNeighborhoodRadiusSquared ):
|
||||
fThisDistanceSquared = deltaX * deltaX + deltaY * deltaY
|
||||
ptNewSegmentThisEnd = absoluteLineSegments[innerCount][nNewSegmentInitialEndIndex]
|
||||
ptNewSegmentOtherEnd = absoluteLineSegments[innerCount][not nNewSegmentInitialEndIndex]
|
||||
fNewSegmentDirectionRadians = math.atan2( ptNewSegmentThisEnd[1] - ptNewSegmentOtherEnd[1], ptNewSegmentThisEnd[0] - ptNewSegmentOtherEnd[0] ) # from other end to this end
|
||||
# If this end would cause an alternating direction,
|
||||
# then exclude it
|
||||
if ( not self.WouldBeAnAlternatingDirection( fReferenceDirectionRadians, fNewSegmentDirectionRadians ) ):
|
||||
pass
|
||||
# break # out of for nNewSegmentInitialEndIndex in range( 2 ):
|
||||
# if ( not self.WouldBeAnAlternatingDirection( fReferenceDirectionRadians, fNewSegmentDirectionRadians ) ):
|
||||
elif ( fThisDistanceSquared < fClosestDistanceSquared ):
|
||||
# One other thing could rule out choosing this segment end:
|
||||
# Want to screen and remove two segments that, while close enough,
|
||||
# should be disqualified because they are colinear. The reason for this is that
|
||||
# if they are colinear, they arose from the same global grid line, which means
|
||||
# that the gap between them arises from intersections with the boundary.
|
||||
# The idea here is that, all things being more-or-less equal,
|
||||
# we would like to give preference to connecting to a segment
|
||||
# which is the reverse of our current direction. This makes for better
|
||||
# bezier curve join.
|
||||
# The criterion for being colinear is that the reference segment angle is effectively
|
||||
# the same as the line connecting the reference segment to the end of the new segment.
|
||||
fJoinerDirectionRadians = math.atan2( ptNewSegmentThisEnd[1] - ptReference[1], ptNewSegmentThisEnd[0] - ptReference[0] )
|
||||
if ( not self.AreCoLinear( fReferenceDirectionRadians, fJoinerDirectionRadians) ):
|
||||
# not colinear
|
||||
fClosestDistanceSquared = fThisDistanceSquared
|
||||
bFoundSegmentToAdd = True
|
||||
nReferenceEndIndexAtClosest = nReferenceEndIndex
|
||||
nInnerCountAtClosest = innerCount
|
||||
deltaXAtClosest = deltaX
|
||||
deltaYAtClosest = deltaY
|
||||
# if ( not self.AreCoLinear( fReferenceDirectionRadians, fJoinerDirectionRadians) ):
|
||||
# if ( fThisDistanceSquared < fClosestDistanceSquared ):
|
||||
# if ( ( deltaX * deltaX + deltaY * deltaY ) < fProposedNeighborhoodRadiusSquared ):
|
||||
# if ( innerCount != referenceCount ):
|
||||
# for nNewSegmentInitialEndIndex in range( 2 ):
|
||||
# if ( not absoluteLineSegments[2] ):
|
||||
# for innerCount in range( nAbsoluteLineSegmentTotal ):
|
||||
# for nReferenceEndIndex in range( 2 ):
|
||||
|
||||
# At last we've looked at all the candidate segment ends, as related to all the reference ends
|
||||
if ( not bFoundSegmentToAdd ):
|
||||
# This segment is solitary.
|
||||
# Must start a new line, not joined to any previous paths
|
||||
deltaX = absoluteLineSegments[referenceCount][1][0] - absoluteLineSegments[referenceCount][0][0] # end minus start, in original direction
|
||||
deltaY = absoluteLineSegments[referenceCount][1][1] - absoluteLineSegments[referenceCount][0][1] # end minus start, in original direction
|
||||
path += ( 'M %f,%f l %f,%f ' %
|
||||
( pt1[0], pt1[1], pt2[0] - pt1[0], pt2[1] - pt1[1] ) )
|
||||
else:
|
||||
# Or go this direction
|
||||
path += ( 'M %f,%f l %f,%f ' %
|
||||
( pt2[0], pt2[1], pt1[0] - pt2[0], pt1[1] - pt2[1] ) )
|
||||
|
||||
direction = not direction
|
||||
# for segment in self.hatches[key]:
|
||||
self.joinFillsWithNode( key, stroke_width, path[:-1] )
|
||||
( absoluteLineSegments[referenceCount][0][0], absoluteLineSegments[referenceCount][0][1],
|
||||
deltaX, deltaY ) ) # delta is from initial point
|
||||
fDistanceMovedWithPenUp += math.hypot(
|
||||
absoluteLineSegments[referenceCount][0][0] - ptLastPositionAbsolute[0],
|
||||
absoluteLineSegments[referenceCount][0][1] - ptLastPositionAbsolute[1] )
|
||||
ptLastPositionAbsolute[0] = absoluteLineSegments[referenceCount][0][0] + deltaX
|
||||
ptLastPositionAbsolute[1] = absoluteLineSegments[referenceCount][0][1] + deltaY
|
||||
absoluteLineSegments[ referenceCount ][2] = True # True flags that this line segment has been
|
||||
# added to the path to be drawn, so should
|
||||
# no longer be a candidate for any kind of move.
|
||||
nPenLifts += 1
|
||||
else: # if ( not bFoundSegmentToAdd ):
|
||||
# Found segment to add, and we must get to it in absolute terms
|
||||
deltaX = ( absoluteLineSegments[referenceCount][nReferenceEndIndexAtClosest][0] -
|
||||
absoluteLineSegments[referenceCount][not nReferenceEndIndexAtClosest][0] )
|
||||
# final point (which was closer to the closest continuation segment) minus initial point = deltaX
|
||||
|
||||
else: # if not self.options.reducePenLifts:
|
||||
for segment in self.hatches[key]:
|
||||
if len( segment ) < 2: # Copied from original, no idea why this is needed [sbm]
|
||||
continue
|
||||
if ( direction ):
|
||||
pt1 = segment[0]
|
||||
pt2 = segment[1]
|
||||
else:
|
||||
pt1 = segment[1]
|
||||
pt2 = segment[0]
|
||||
# Okay, we're going to put these hatch lines into the same
|
||||
# group as the element they hatch. That element is down
|
||||
# some chain of SVG elements, some of which may have
|
||||
# transforms attached. But, our hatch lines have been
|
||||
# computed assuming that those transforms have already
|
||||
# been applied (since we had to apply them so as to know
|
||||
# where this element is on the page relative to other
|
||||
# elements and their transforms). So, we need to invert
|
||||
# the transforms for this element and then either apply
|
||||
# that inverse transform here and now or set it in a
|
||||
# transform attribute of the <path> element. Having it
|
||||
# set in the path element seems a bit counterintuitive
|
||||
# after the fact (i.e., what's this tranform here for?).
|
||||
# So, we compute the inverse transform and apply it here.
|
||||
if transform != None:
|
||||
simpletransform.applyTransformToPoint( transform, pt1 )
|
||||
simpletransform.applyTransformToPoint( transform, pt2 )
|
||||
|
||||
# Now generate the path data for the <path>
|
||||
# BUT we want to combine as many paths as possible to reduce pen lifts.
|
||||
# In order to combine paths, we need to know all of the path segments.
|
||||
# The solution to this conundrum is to generate all path segments,
|
||||
# but instead of drawing them into the path right away, we put them in
|
||||
# an array where they'll be available for random access
|
||||
# by our anti-pen-lift algorithm
|
||||
absoluteLineSegments[ nAbsoluteLineSegmentTotal ] = [ pt1, pt2, False ] # False indicates that segment has not yet been drawn
|
||||
nAbsoluteLineSegmentTotal += 1
|
||||
direction = not direction
|
||||
# for segment in self.hatches[key]:
|
||||
|
||||
# Now have a nice juicy buffer full of line segments with absolute coordinates
|
||||
fProposedNeighborhoodRadiusSquared = self.ProposeNeighborhoodRadiusSquared( transformedHatchSpacing ) # Just fixed and simple for now - may make function of neighborhood later
|
||||
for referenceCount in range( nAbsoluteLineSegmentTotal ): # This is the entire range of segments,
|
||||
# Sets global referenceCount to segment which has an end closest to current pen position.
|
||||
# Doesn't need to select which end is closest, as that will happen below, with nReferenceEndIndex.
|
||||
# When we have gone thru this whole range, we will be completely done.
|
||||
# We only get here again, after all _connected_ segments have been "drawn".
|
||||
if ( not absoluteLineSegments[referenceCount][2] ): # Test whether this segment has been drawn
|
||||
# Has not been drawn yet
|
||||
deltaY = ( absoluteLineSegments[referenceCount][nReferenceEndIndexAtClosest][1] -
|
||||
absoluteLineSegments[referenceCount][not nReferenceEndIndexAtClosest][1] )
|
||||
# final point (which was closer to the closest continuation segment) minus initial point = deltaY
|
||||
|
||||
# Before we do any irrevocable changes to path, let's see if we are going to be able to append any segments.
|
||||
# The below solution is inelegant, but has the virtue of being relatively simple to implement.
|
||||
# Pre-qualify this segment on the issue of whether it has any connecting segments.
|
||||
# If it does not, then just add the path for this one segment, and go on to the next.
|
||||
# If it does have connecting segments, we need to go through the recursive logic.
|
||||
# Lazily, again, select the desired direction of line ahead of time.
|
||||
path += ( 'M %f,%f l ' % (
|
||||
absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][0],
|
||||
absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][1] ) )
|
||||
fDistanceMovedWithPenUp += math.hypot(
|
||||
absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][0] - ptLastPositionAbsolute[0],
|
||||
absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][1] - ptLastPositionAbsolute[1] )
|
||||
ptLastPositionAbsolute[0] = absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][0]
|
||||
ptLastPositionAbsolute[1] = absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][1]
|
||||
# Note that this does not complete the line, as the completion (the deltaX, deltaY part) is being held in abeyance
|
||||
|
||||
bFoundSegmentToAdd = False # default assumption
|
||||
nReferenceEndIndexAtClosest = 0
|
||||
nInnerCountAtClosest = -1
|
||||
fClosestDistanceSquared = 123456 # just a random large number
|
||||
for nReferenceEndIndex in range( 2 ):
|
||||
ptReference = absoluteLineSegments[referenceCount][nReferenceEndIndex]
|
||||
ptReferenceOtherEnd = absoluteLineSegments[referenceCount][not nReferenceEndIndex]
|
||||
fReferenceDirectionRadians = math.atan2( ptReferenceOtherEnd[1] - ptReference[1], ptReferenceOtherEnd[0] - ptReference[0] ) # from other end to this end
|
||||
# The following is just a simple copy from the routine in recursivelyAppendNearbySegmentIfAny procedure
|
||||
# Look through all possibilities to choose the closest that fulfills all requirements e.g. direction and colinearity
|
||||
for innerCount in range( nAbsoluteLineSegmentTotal ): # investigate all segments
|
||||
if ( not absoluteLineSegments[innerCount][2] ):
|
||||
# This segment currently undrawn, so it is a candidate for a path extension
|
||||
# Need to check both ends of each and every proposed segment so we can find the most appropriate one
|
||||
# Define pt2 in the reference as the end which we want to extend
|
||||
for nNewSegmentInitialEndIndex in range( 2 ):
|
||||
# First try initial end of test segment (aka pt1) vs final end (aka pt2) of reference segment
|
||||
if ( innerCount != referenceCount ): # don't investigate self ends
|
||||
deltaX = absoluteLineSegments[innerCount][nNewSegmentInitialEndIndex][0] - ptReference[0] # proposed initial pt1 X minus existing final pt1 X
|
||||
deltaY = absoluteLineSegments[innerCount][nNewSegmentInitialEndIndex][1] - ptReference[1] # proposed initial pt1 Y minus existing final pt1 Y
|
||||
if ( ( deltaX * deltaX + deltaY * deltaY ) < fProposedNeighborhoodRadiusSquared ):
|
||||
fThisDistanceSquared = deltaX * deltaX + deltaY * deltaY
|
||||
ptNewSegmentThisEnd = absoluteLineSegments[innerCount][nNewSegmentInitialEndIndex]
|
||||
ptNewSegmentOtherEnd = absoluteLineSegments[innerCount][not nNewSegmentInitialEndIndex]
|
||||
fNewSegmentDirectionRadians = math.atan2( ptNewSegmentThisEnd[1] - ptNewSegmentOtherEnd[1], ptNewSegmentThisEnd[0] - ptNewSegmentOtherEnd[0] ) # from other end to this end
|
||||
# If this end would cause an alternating direction,
|
||||
# then exclude it
|
||||
if ( not self.WouldBeAnAlternatingDirection( fReferenceDirectionRadians, fNewSegmentDirectionRadians ) ):
|
||||
pass
|
||||
# break # out of for nNewSegmentInitialEndIndex in range( 2 ):
|
||||
# if ( not self.WouldBeAnAlternatingDirection( fReferenceDirectionRadians, fNewSegmentDirectionRadians ) ):
|
||||
elif ( fThisDistanceSquared < fClosestDistanceSquared ):
|
||||
# One other thing could rule out choosing this segment end:
|
||||
# Want to screen and remove two segments that, while close enough,
|
||||
# should be disqualified because they are colinear. The reason for this is that
|
||||
# if they are colinear, they arose from the same global grid line, which means
|
||||
# that the gap between them arises from intersections with the boundary.
|
||||
# The idea here is that, all things being more-or-less equal,
|
||||
# we would like to give preference to connecting to a segment
|
||||
# which is the reverse of our current direction. This makes for better
|
||||
# bezier curve join.
|
||||
# The criterion for being colinear is that the reference segment angle is effectively
|
||||
# the same as the line connecting the reference segment to the end of the new segment.
|
||||
fJoinerDirectionRadians = math.atan2( ptNewSegmentThisEnd[1] - ptReference[1], ptNewSegmentThisEnd[0] - ptReference[0] )
|
||||
if ( not self.AreCoLinear( fReferenceDirectionRadians, fJoinerDirectionRadians) ):
|
||||
# not colinear
|
||||
fClosestDistanceSquared = fThisDistanceSquared
|
||||
bFoundSegmentToAdd = True
|
||||
nReferenceEndIndexAtClosest = nReferenceEndIndex
|
||||
nInnerCountAtClosest = innerCount
|
||||
deltaXAtClosest = deltaX
|
||||
deltaYAtClosest = deltaY
|
||||
# if ( not self.AreCoLinear( fReferenceDirectionRadians, fJoinerDirectionRadians) ):
|
||||
# if ( fThisDistanceSquared < fClosestDistanceSquared ):
|
||||
# if ( ( deltaX * deltaX + deltaY * deltaY ) < fProposedNeighborhoodRadiusSquared ):
|
||||
# if ( innerCount != referenceCount ):
|
||||
# for nNewSegmentInitialEndIndex in range( 2 ):
|
||||
# if ( not absoluteLineSegments[2] ):
|
||||
# for innerCount in range( nAbsoluteLineSegmentTotal ):
|
||||
# for nReferenceEndIndex in range( 2 ):
|
||||
|
||||
# At last we've looked at all the candidate segment ends, as related to all the reference ends
|
||||
if ( not bFoundSegmentToAdd ):
|
||||
# This segment is solitary.
|
||||
# Must start a new line, not joined to any previous paths
|
||||
deltaX = absoluteLineSegments[referenceCount][1][0] - absoluteLineSegments[referenceCount][0][0] # end minus start, in original direction
|
||||
deltaY = absoluteLineSegments[referenceCount][1][1] - absoluteLineSegments[referenceCount][0][1] # end minus start, in original direction
|
||||
path += ( 'M %f,%f l %f,%f ' %
|
||||
( absoluteLineSegments[referenceCount][0][0], absoluteLineSegments[referenceCount][0][1],
|
||||
deltaX, deltaY ) ) # delta is from initial point
|
||||
fDistanceMovedWithPenUp += math.hypot(
|
||||
absoluteLineSegments[referenceCount][0][0] - ptLastPositionAbsolute[0],
|
||||
absoluteLineSegments[referenceCount][0][1] - ptLastPositionAbsolute[1] )
|
||||
ptLastPositionAbsolute[0] = absoluteLineSegments[referenceCount][0][0] + deltaX
|
||||
ptLastPositionAbsolute[1] = absoluteLineSegments[referenceCount][0][1] + deltaY
|
||||
absoluteLineSegments[ referenceCount ][2] = True # True flags that this line segment has been
|
||||
# added to the path to be drawn, so should
|
||||
# no longer be a candidate for any kind of move.
|
||||
nPenLifts += 1
|
||||
else: # if ( not bFoundSegmentToAdd ):
|
||||
# Found segment to add, and we must get to it in absolute terms
|
||||
deltaX = ( absoluteLineSegments[referenceCount][nReferenceEndIndexAtClosest][0] -
|
||||
absoluteLineSegments[referenceCount][not nReferenceEndIndexAtClosest][0] )
|
||||
# final point (which was closer to the closest continuation segment) minus initial point = deltaX
|
||||
# We are coming up on a problem:
|
||||
# If we add a curve to the end of the line, we have made the curve extend beyond the end of the line,
|
||||
# and thus beyond the boundaries we should be respecting.
|
||||
# The solution is to hold in abeyance the actual plotting of the line,
|
||||
# holding it available for shrinking if a curve is to be added.
|
||||
# That is
|
||||
relativePositionOfLastPlottedLineWasHeldInAbeyance = {}
|
||||
relativePositionOfLastPlottedLineWasHeldInAbeyance[0] = deltaX # delta is from initial point
|
||||
relativePositionOfLastPlottedLineWasHeldInAbeyance[1] = deltaY # Will be printed after we know if it must be modified
|
||||
# to keep the ending join within bounds
|
||||
ptLastPositionAbsolute[0] += deltaX
|
||||
ptLastPositionAbsolute[1] += deltaY
|
||||
|
||||
absoluteLineSegments[ referenceCount ][2] = True # True flags that this line segment has been
|
||||
# added to the path to be drawn, so should
|
||||
# no longer be a candidate for any kind of move.
|
||||
nPenLifts += 1
|
||||
# Now comes the speedup logic:
|
||||
# We've just drawn a segment starting at an absolute, not relative, position.
|
||||
# It was drawn from pt1 to pt2.
|
||||
# Look for an as-yet-not-drawn segment which has a beginning or ending
|
||||
# point "near" the end point of this absolute draw, and leave the pen down
|
||||
# while moving to and then drawing this found line.
|
||||
# Do this recursively, marking each segment True to show that
|
||||
# it has been "drawn" already.
|
||||
# pt2 is the reference point, ie. the point from which the next segment will start
|
||||
path = self.recursivelyAppendNearbySegmentIfAny(
|
||||
transformedHatchSpacing,
|
||||
0,
|
||||
referenceCount,
|
||||
nReferenceEndIndexAtClosest,
|
||||
nAbsoluteLineSegmentTotal,
|
||||
absoluteLineSegments,
|
||||
path,
|
||||
relativePositionOfLastPlottedLineWasHeldInAbeyance )
|
||||
# if ( not bFoundSegmentToAdd ): else:
|
||||
# if ( not absoluteLineSegments[referenceCount][2] ):
|
||||
# while ( self.IndexOfNearestSegmentToLastPosition() ):
|
||||
self.joinFillsWithNode( key, stroke_width, path[:-1] )
|
||||
# if not self.options.reducePenLifts: else:
|
||||
# for key in self.hatches:
|
||||
|
||||
deltaY = ( absoluteLineSegments[referenceCount][nReferenceEndIndexAtClosest][1] -
|
||||
absoluteLineSegments[referenceCount][not nReferenceEndIndexAtClosest][1] )
|
||||
# final point (which was closer to the closest continuation segment) minus initial point = deltaY
|
||||
|
||||
path += ( 'M %f,%f l ' % (
|
||||
absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][0],
|
||||
absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][1] ) )
|
||||
fDistanceMovedWithPenUp += math.hypot(
|
||||
absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][0] - ptLastPositionAbsolute[0],
|
||||
absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][1] - ptLastPositionAbsolute[1] )
|
||||
ptLastPositionAbsolute[0] = absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][0]
|
||||
ptLastPositionAbsolute[1] = absoluteLineSegments[referenceCount][ not nReferenceEndIndexAtClosest][1]
|
||||
# Note that this does not complete the line, as the completion (the deltaX, deltaY part) is being held in abeyance
|
||||
|
||||
# We are coming up on a problem:
|
||||
# If we add a curve to the end of the line, we have made the curve extend beyond the end of the line,
|
||||
# and thus beyond the boundaries we should be respecting.
|
||||
# The solution is to hold in abeyance the actual plotting of the line,
|
||||
# holding it available for shrinking if a curve is to be added.
|
||||
# That is
|
||||
relativePositionOfLastPlottedLineWasHeldInAbeyance = {}
|
||||
relativePositionOfLastPlottedLineWasHeldInAbeyance[0] = deltaX # delta is from initial point
|
||||
relativePositionOfLastPlottedLineWasHeldInAbeyance[1] = deltaY # Will be printed after we know if it must be modified
|
||||
# to keep the ending join within bounds
|
||||
ptLastPositionAbsolute[0] += deltaX
|
||||
ptLastPositionAbsolute[1] += deltaY
|
||||
|
||||
absoluteLineSegments[ referenceCount ][2] = True # True flags that this line segment has been
|
||||
# added to the path to be drawn, so should
|
||||
# no longer be a candidate for any kind of move.
|
||||
nPenLifts += 1
|
||||
# Now comes the speedup logic:
|
||||
# We've just drawn a segment starting at an absolute, not relative, position.
|
||||
# It was drawn from pt1 to pt2.
|
||||
# Look for an as-yet-not-drawn segment which has a beginning or ending
|
||||
# point "near" the end point of this absolute draw, and leave the pen down
|
||||
# while moving to and then drawing this found line.
|
||||
# Do this recursively, marking each segment True to show that
|
||||
# it has been "drawn" already.
|
||||
# pt2 is the reference point, ie. the point from which the next segment will start
|
||||
path = self.recursivelyAppendNearbySegmentIfAny(
|
||||
transformedHatchSpacing,
|
||||
0,
|
||||
referenceCount,
|
||||
nReferenceEndIndexAtClosest,
|
||||
nAbsoluteLineSegmentTotal,
|
||||
absoluteLineSegments,
|
||||
path,
|
||||
relativePositionOfLastPlottedLineWasHeldInAbeyance )
|
||||
# if ( not bFoundSegmentToAdd ): else:
|
||||
# if ( not absoluteLineSegments[referenceCount][2] ):
|
||||
# while ( self.IndexOfNearestSegmentToLastPosition() ):
|
||||
self.joinFillsWithNode( key, stroke_width, path[:-1] )
|
||||
# if not self.options.reducePenLifts: else:
|
||||
# for key in self.hatches:
|
||||
|
||||
'''
|
||||
if self.options.reducePenLifts:
|
||||
if ( nAbsoluteLineSegmentTotal != 0 ):
|
||||
inkex.errormsg( ' Saved %i%% of %i pen lifts.' % ( 100 * ( nAbsoluteLineSegmentTotal - nPenLifts ) / nAbsoluteLineSegmentTotal, nAbsoluteLineSegmentTotal ) )
|
||||
inkex.errormsg( ' pen lifts=%i, line segments=%i' % ( nPenLifts, nAbsoluteLineSegmentTotal ) )
|
||||
else:
|
||||
inkex.errormsg( ' No lines were plotted' )
|
||||
|
||||
inkex.errormsg( ' Press OK' )
|
||||
# if self.options.reducePenLifts:
|
||||
#inkex.errormsg("Elapsed CPU time was %f" % (time.clock()-self.t0))
|
||||
'''
|
||||
else: # if bHaveGrid:
|
||||
inkex.errormsg( ' Nothing to plot' )
|
||||
# if bHaveGrid: else:
|
||||
'''
|
||||
if self.options.reducePenLifts:
|
||||
if ( nAbsoluteLineSegmentTotal != 0 ):
|
||||
inkex.errormsg( ' Saved %i%% of %i pen lifts.' % ( 100 * ( nAbsoluteLineSegmentTotal - nPenLifts ) / nAbsoluteLineSegmentTotal, nAbsoluteLineSegmentTotal ) )
|
||||
inkex.errormsg( ' pen lifts=%i, line segments=%i' % ( nPenLifts, nAbsoluteLineSegmentTotal ) )
|
||||
else:
|
||||
inkex.errormsg( ' No lines were plotted' )
|
||||
|
||||
inkex.errormsg( ' Press OK' )
|
||||
# if self.options.reducePenLifts:
|
||||
#inkex.errormsg("Elapsed CPU time was %f" % (time.clock()-self.t0))
|
||||
'''
|
||||
# def effect( self ):
|
||||
|
||||
def recursivelyAppendNearbySegmentIfAny(
|
||||
|
|
Ładowanie…
Reference in New Issue