Skip to content

Commit

Permalink
Production ready: eliminate print statements.
Browse files Browse the repository at this point in the history
  • Loading branch information
bootchk committed Aug 15, 2013
1 parent ac38e5e commit 7b921b0
Show file tree
Hide file tree
Showing 13 changed files with 99 additions and 59 deletions.
40 changes: 40 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

This is a hand generated changelog for versions, not very accurate.
Use >git log for every commit.


Version 0.0.2
=============

SegmentString, Segment, ControlPoint classes.
Explicitly model the abstractions of a SegmentString.
This more cleanly separates freehandTool from what it produces.
Demonstrates editing a SegmentString by manipulation of its ControlPoints.
(Although editing is not graphical, just crude demo via keystrokes.)


Version 0.0.3
=============

- Relations between ControlPoints defines actions (behavior of user manipulations.)
- Cusps known by SegmentString
- Actions defined as a Strategy/Policy
- An API that can be cleanly hooked to a GUI editor.

Version 0.1
===========

A production version?

Add exception for generated null segments, catch the exception internally, and handle it gracefully.
I don't expect the algorithm to generate null segments, but if it does they are handled.

Improve ghosting of the head of the generated curve: path instead of straight line.

Clarify use of input, view (int pixel) coords and internal, scene (float) coords.
Eliminate rounding errors by not converting in the back direction.

Reraise StopIteration. If the tool fails, it will generate this exception.
A caller might be able to rescue.

Remove all print statements.
43 changes: 17 additions & 26 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
Copyright 2012 L. Konneker
-------------------------

1. About
========
About
=====

A freehand drawing tool.
Where a tool is a user interface object, something a user uses.
Expand Down Expand Up @@ -34,34 +34,23 @@ References:
See much more technical discussion in the code.


2. Version 0.0.2
================

SegmentString, Segment, ControlPoint classes.
Explicitly model the abstractions of a SegmentString.
This more cleanly separates freehandTool from what it produces.
Demonstrates editing a SegmentString by manipulation of its ControlPoints.
(Although editing is not graphical, just crude demo via keystrokes.)
Versions
========

See CHANGELOG.

3. Version 0.0.3
================

- Relations between ControlPoints defines actions (behavior of user manipulations.)
- Cusps known by SegmentString
- Actions defined as a Strategy/Policy
- An API that can be cleanly hooked to a GUI editor.
Serialize/Deserialize
======================

The output SegmentString, a QGraphicsPathItem, does not pickle.
But QPainterPath implements << for serializing, and it's not hard to do (it's not in this package.)

4. Serialize/Deserialize
========================
TODO
Calculate cuspness geometrically.
Cuspness is not currently serializable/deserializable, only exists just after SegmentString creation.


5. Directory structure and distribution
=======================================
Directory structure and distribution
====================================
The top directory freehandTool includes a demo app, freehandApp.py.
It also include other distribution artifacts e.g. setup.py.

Expand All @@ -74,17 +63,19 @@ The directory freehandTool.freehandTool.generator is a Python package that the t
The Python distribution (a zipped archive) includes only the package freehandTool.freehandTool and subpackages,
but not the demo app.

6. The demo app
===============

The demo app
============

Draw with the mouse left button down.
Any key modifies an arbitrary control point (the second one?)
A key with control key also down modifies said control point while maintaining cuspness.

A real app would have an alternate user interface for editing (dragging?) control points.

7. Installing
==============

Installing
==========

If you clone the git repository, you can change directory to the project directory and simply execute freehandApp.py.

Expand Down
2 changes: 1 addition & 1 deletion alternatePaintingQGPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def paint(self, painter, styleOption, widget):
while True:
try:
element = path.elementAt(i)
# print type(element), element.type
#print type(element), element.type
if element.isMoveTo():
pathEnd = QPointF(element.x, element.y)
i+=1
Expand Down
Binary file modified dist/freehandTool-0.1.tar.gz
Binary file not shown.
17 changes: 12 additions & 5 deletions freehandTool/freehand.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,14 +331,21 @@ def pointerMoveEvent(self, pointerEvent):
except StopIteration:
'''
While user is moving pointer with pointer button down, we don't expect pipe to stop.
If programming error stops pipe, quit app so we can see error trace.
For debugging, call exitAbnormally().
If a component of large app, raise.
A caller might catch it and rescue by ending and restarting the tool?
'''
print "Abnormal pointerMoveEvent, exiting"
sys.exit()
raise
else:
self.pathHeadGhost.updateEnd(FreehandPoint(pointerEvent.scenePos))


def exitAbnormally(self):
" For debugging: quit app so we can see error trace. "
print "Abnormal pointerMoveEvent, exiting"
sys.exit()


def pointerPressEvent(self, pointerEvent):
'''
Start freehand drawing.
Expand All @@ -351,7 +358,7 @@ def pointerReleaseEvent(self, pointerEvent):
self.closeFilterPipe()
self.pathHeadGhost.hide()
self._createFinalSegment(pointerEvent)
print "Final segment count", self.path.countSegments()
#print "Final segment count", self.path.countSegments()


def _createFinalSegment(self, pointerEvent):
Expand All @@ -374,7 +381,7 @@ def _createFinalSegment(self, pointerEvent):
# Only create final segment if pointer was NOT released at exact end of current path
# For example when ending on a timed cusp??
if currenPathEnd != currentPointerPos:
print "Created final line segment"
#print "Created final line segment"
finalLineSegment = LineSegment(startPoint=currenPathEnd, endPoint=currentPointerPos)
self.path.appendSegments( [finalLineSegment], segmentCuspness=[False])

Expand Down
8 changes: 4 additions & 4 deletions freehandTool/freehandHead.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __init__(self, **kwargs):


def showAt(self, initialPosition):
# print "showAt"
#print "showAt"
self.start = initialPosition
self.end = initialPosition
self.path.moveTo(initialPosition)
Expand All @@ -71,7 +71,7 @@ def updateEnd(self, point):
'''
Update current path by appending lineTo new end point.
'''
# print "updateEnd"
#print "updateEnd"
assert isinstance(point, FreehandPoint)
self.end = point
self.path.lineTo(point)
Expand All @@ -95,7 +95,7 @@ def floatSceneFromIntViewPoint(self, pointVCS):
def updateStart(self, pointVCS):
'''
'''
print "updateStart"
#print "updateStart"
# !!! start point from FreehandTool is in View CS.
pointViewInt = QPoint(pointVCS.x(), pointVCS.y())
pointSceneFloat = self.scene().views()[0].mapToScene(pointViewInt)
Expand All @@ -120,7 +120,7 @@ def _findFirstElementAt(self, point):
assert self.path.elementCount() > 1 # moveTo, lineTo
for elementIndex in range(1, self.path.elementCount()):
element = self.path.elementAt(elementIndex)
print element.x, element.y, point
#print element.x, element.y, point
if element.x == point.x() and element.y == point.y() :
return elementIndex
assert False, 'New start point must be on existing path.'
Expand Down
4 changes: 2 additions & 2 deletions freehandTool/generator/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ def update(self, v):
If you take out turnGenerator, this might make sense.
if abs(v.x())<=1 and abs(v.y())<=1 :
print "No constraints."
#print "No constraints."
pass
else:
'''
# print "Updating constraints"
#print "Updating constraints"
offset = PointerPoint( v.x() + (1 if v.y() >= 0 and (v.y()>0 or v.x()<0) else -1 ),
v.y() + (1 if v.x() <= 0 and (v.x()<0 or v.y()<0) else -1 ) )
if self.constraintLeft.crossProduct(offset) >= 0 :
Expand Down
7 changes: 4 additions & 3 deletions freehandTool/generator/curveGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ def CurveGenerator(self, startLine):
GeneratorExit exception is still in effect after finally, but caller does not see it,
and Python does NOT allow it to return a value.
'''
print "closed curve generator"
#print "closed curve generator"
pass



Expand Down Expand Up @@ -142,7 +143,7 @@ def segmentsFromLineMidToEnd(self, line1, line2):
'''
midToMidsegments, endOfMidToMid, cuspness = self.segmentsFromLineMidToMid(line1, line2)
finalEndPoint = FreehandPoint(self.mapFromDeviceToScene(line2.p2())) # line2.p2()
print "Mid to end"
#print "Mid to end"
midToEnd = LineSegment(endOfMidToMid, finalEndPoint)
return midToMidsegments + [midToEnd], finalEndPoint, cuspness + [True]

Expand All @@ -160,7 +161,7 @@ def segmentsForCusp(self, cuspPoint, endPoint):
Note we already generated segment to first midpoint,
and will subsequently generate segment from second midpoint.
'''
print "cusp <<<"
#print "cusp <<<"
try:
# !!! Here is where we use cache
firstSegment = LineSegment(self.lastEndPointGenerated, cuspPoint)
Expand Down
21 changes: 11 additions & 10 deletions freehandTool/generator/lineGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def LineGenerator(self, startPosition):
while True:
turn, positionElapsedTime = (yield)
#turnElapsedTime = turnClock.restart()
# print "Turn elapsed", turnElapsedTime
#print "Turn elapsed", turnElapsedTime
#line = self.smallestLineFromPath(previousTurn, turn) # TEST
line = self._lineFromPath(startTurn, previousTurn, turn, constraints) # ,directions)
if line is not None: # if turn not satisfied by vector
Expand All @@ -54,24 +54,25 @@ def LineGenerator(self, startPosition):
startTurn = previousTurn # !!! current turn is part of next PathLine
didLastEmitCusp = True
else:
print "Skipping consecutive cusps"
#print "Skipping consecutive cusps"
pass
# else current path (all turns) still satisfied by a PathLine: wait

previousTurn = turn # Roll forward !!! Every turn, not just on send()
except Exception:
# !!! GeneratorExit is a BaseException, not an Exception
# Unexpected programming errors, which are obscured unless caught
print "Exception in LineGenerator"
#print "Exception in LineGenerator"
traceback.print_exc()
raise
except GeneratorExit:
print "closing line generator"
#print "closing line generator"
if previousTurn != startTurn:
print "closing line generator"
#print "closing line generator"
#print "startTurn, previousTurn", startTurn, previousTurn
''' Have turn not sent. Fabricate a PathLine and send() it now. '''
self.curveGenerator.send((PathLine(startTurn, previousTurn), False))
print "closed line generator"
#print "closed line generator"



Expand Down Expand Up @@ -112,7 +113,7 @@ def _lineFromPath(self, startTurn, previousTurn, currentTurn, constraints, direc
if len(directions) > 3:
# a path with four directions can't be approximated with one vector
# end point is starting pixel of segment ???
print "Four directions"
#print "Four directions"
self.resetLineFittingFilter()
# Note end is previousTurn, not current Turn
return PathLine(startTurn, previousTurn)
Expand All @@ -122,7 +123,7 @@ def _lineFromPath(self, startTurn, previousTurn, currentTurn, constraints, direc
vectorViaAllTurns = currentTurn - startTurn

if constraints.isViolatedBy(vector=vectorViaAllTurns):
# print "Constraint violation", constraints, "vector", vectorViaAllTurns
#print "Constraint violation", constraints, "vector", vectorViaAllTurns
result = self._interpolateConstraintViolating(startTurn=startTurn,
lastSatisfyingTurn=previousTurn,
firstNonsatisfingTurn=currentTurn)
Expand All @@ -144,11 +145,11 @@ def _forceLineFromPath(self, startTurn, previousTurn, currentTurn, constraints,

if startTurn == currentTurn:
''' A reversal. A line from start to current would be Null. '''
print "Reversal"
#print "Reversal"
assert previousTurn != startTurn
return PathLine(startTurn, previousTurn)
else:
## print "Force PathLine", startTurn, currentTurn
##print "Force PathLine", startTurn, currentTurn
return PathLine(startTurn, currentTurn)


Expand Down
6 changes: 3 additions & 3 deletions freehandTool/generator/turnGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def TurnGenerator(self, startPosition):
positionClock = QTime.currentTime() # note restart returns elapsed
positionClock.restart()
# I also tried countPositionsSinceTurn to solve lag for cusp-like
# print "init turn"
#print "init turn"

try:
while True:
Expand All @@ -49,12 +49,12 @@ def TurnGenerator(self, startPosition):
pass
# Not catching general exceptions, have not found a need for it.
except GeneratorExit:
print "Closing turn generator"
#print "Closing turn generator"
# assert position is defined
if previousPosition != position:
''' Have position not sent. Fabricate a turn (equal to position) and send() '''
self.lineGenerator.send((position, 0))
print "Closed turn generator"
#print "Closed turn generator"



Expand Down
2 changes: 1 addition & 1 deletion freehandTool/segmentString/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def isNull(self):
Float equality a problem?
'''
result = self.controlPoints[0] == self.controlPoints[3]
# print "isNull", result
#print "isNull", result
return result


Expand Down
2 changes: 1 addition & 1 deletion freehandTool/segmentString/segmentActions.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def _dispatchMoveRelated(self, relations, controlPoint, deltaCoordinate, alterna
if self.isRoleAnchorAtCusp(controlPoint):
if not alternateMode:
# default is : make cusps more cuspy or possibly take out cusp
print "Moving cusp anchor"
#print "Moving cusp anchor"
self.moveAnchorSetNotMaintainingCuspness(relations, controlPoint, deltaCoordinate, alternateMode, visitor)
else:
# alternate is weaker: don't remove the cusp, only move it as a three ControlPoint unit
Expand Down
6 changes: 3 additions & 3 deletions freehandTool/segmentString/segmentString.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ def appendInternalRepr(self, path, pointsLCS):
!!! and cubicTo has 3 points of Segment's 4 points.
'''
assert len(pointsLCS) == SegmentString.ELEMENTS_PER_SEGMENT
# print "appendInternalRep", pointsLCS
#print "appendInternalRep", pointsLCS
path.cubicTo(*pointsLCS[1:])


Expand All @@ -383,7 +383,7 @@ def segmentChanged(self, segment, indexOfSegmentInString):
User changed control points of segment (i.e. model.)
Propagate change to path (i.e. view.)
'''
## print "Segment changed"
##print "Segment changed"
self.updateSegment(segment, indexOfSegmentInString)


Expand Down Expand Up @@ -526,7 +526,7 @@ def _getSegmentAt(self, segmentIndex):
(last point of previous segment shared with first point of next segment.)
E.G. CurveSegment requires four points from three in the path.
'''
# print "SegmentIndex", segmentIndex
#print "SegmentIndex", segmentIndex
assert segmentIndex >= 0 and segmentIndex <= self._indexOfLastSegment()
assert self.countSegments() > 0

Expand Down

0 comments on commit 7b921b0

Please sign in to comment.