NOTE: the original response was done via email from a location where I
do not have posting privileges; this is a copy of that message for
continuity...
Dennis Lee Bieber a écrit :
Oops, sorry I missed it in fact.
But I still have a problem with my the primitives (some pathes I had to
build ):
i.e a mathematical ray is infinite, so I must draw a segment on screen
and need the paper sizes to calculate the segments starts and ends (
I've got a lot of objects like this ). I don't know how to build them
without passing a paper instance.
The actual implementation of some primitives uses :
def __init__(self, paper_instance, etc. ):
do something
But I as mentioned before, I'm not satisfied with it since I shall
write this do draw a Line :*
paper.draw( Line( paper, x1, y1, x2, y2) This is what I don't find
aesthetic : the repetition of "paper" calls.
This is, in my mind, both a usage and a design flaw.
You are creating (and throwing away) instances of drawable
objects to the draw method of a paper instance. But what does
paper.draw() actually do with the drawable object? Call a draw method
within it? If so, that is when you should pass the paper instance (or
just the part needed -- clipping rectangle perhaps?).
Without any actual drawing operations, see if you can follow
along with this code.
-=-=-=-=-=-=-
class Drawable(object):
def __init__(self):
raise NotImplementedError
def draw(self, parent=None):
if not parent: #note: I've not defined the exceptions
raise DrawableError("Must specify parent canvas")
class Point(Drawable):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
class Line(Drawable):
def __init__(self, start, end):
self._start = start
self._end = end
def draw(self, parent=None):
super(Line, self).draw(parent)
# perform whatever is needed to draw /this/ object
# onto the parent (canvas) object.
class Rectangle(Drawable):
def __init__(self, topLeft, bottomRight):
self._topLeft = topLeft
self._bottomRight = bottomRight
self._topRight = Point(bottomRight.x, topLeft.y)
self._bottomLeft = Point(topLeft.x, bottomRight.y)
def draw(self, parent=None):
super(Rectangle, self).draw(parent)
# perform whatever is needed to draw /this/ object
# onto the parent (canvas) object
# etc. for other primitive drawing objects
class Canvas(object):
def __init__(self):
self.clear()
def draw(self):
for p in self._displayList:
p.draw(self)
def getDisplayList(self):
return self._displayList[:] #copy of list
def clear(self):
self._displayList = []
def add(self, primitive=None):
if primitive:
self._displayList.append(primitive)
class Paper(Canvas):
def __init__(self, width, height):
super(Paper, self).__init__()
self._width = width
self._height = height
# don't need to define draw(), getDisplayList(), clear() or add()
# as those of Canvas will be used as is. Only if Paper-specific
# options are needed do they need overrides similar to the
# __init__() difference.
# other canvas types could go here
# with some work, even the canvas could be a "drawable"
##
## usage!
##
p = Paper(8.5, 11) #create paper (US Letter if using inches)
p.add(Line(Point(3, 3), Point(10, 10))) # add a line (note clipping!)
p.add(Rectangle(Point(3.14159, 2.787), Point(2.787, 3.14159)))
p.draw() #draw ALL primitives at once.
p.add(Rectangle(Point(-5, 5), Point(5, -5)))
p.draw() #redraw with newly added primitive
p2 = Paper(6, 4) #create a postcard size page
for primitive in p.getDisplayList():
p2.add(primitive) #copy original drawables to new paper
p2.draw() #draw them clipped to the new page size
Line(Point(x1, y1), Point(x2, y2)).draw(p2)
#draws an anonymous, throw-away, line on p2 (it is not
#added to the display list, so a subsequent p2.draw()
#will not show /this/ line
-=-=-=-=-=-=-
The actual implementation of draw() for each primitive will have
to handle clipping to the boundaries of the Canvas object that is passed
to it.
You'll notice that the only place the primitive needs to know
about the canvas is in its specific draw method. And only at that time
is the canvas (paper) passed to it.
Instead of the concept;
Paper, draw a line from x to y
(and having to pass the "paper" to the initializer of the line
primitive), you have to think in terms of:
Line, draw yourself on this paper
Or, if you consider the last example above… Compare that to your
example:
-=-=-=-=-
paper.draw( Line( paper, x1, y1, x2, y2) )
-=-=-=-=-=-
Here, you are telling the paper to do the drawing, and passing
it a Line instance (and passing it the paper it is supposed to be drawn
on). Why? The paper isn't drawing the line on itself… While
-=-=-=-=-
Line(Point(x1, y1), Point(x2, y2)).draw(paper)
-=-=-=-=-
initializes a Line instance, then asks it to draw itself using paper as
the surface to be drawn upon.
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/