summaryrefslogtreecommitdiff
path: root/support/consdiag/consdiag.py
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/consdiag/consdiag.py
Initial commit
Diffstat (limited to 'support/consdiag/consdiag.py')
-rw-r--r--support/consdiag/consdiag.py1099
1 files changed, 1099 insertions, 0 deletions
diff --git a/support/consdiag/consdiag.py b/support/consdiag/consdiag.py
new file mode 100644
index 0000000000..b328f5ee9f
--- /dev/null
+++ b/support/consdiag/consdiag.py
@@ -0,0 +1,1099 @@
+import string
+
+"""
+1998 Manuel Gutierrez Algaba
+You are free to use , modify, distribute and copy this piece of
+python code, if you keep this free copyright notice in it.
+
+consdiag.py Version 1.1
+
+constructor of diagrams:
+
+Given a frame of classes and relationships among clases, it
+generates latex code ,that represents those classes in the
+Rumbaugh OO notation.
+"""
+
+"""
+The first idea is this :
+If we have a box representing the class we stablish *contact_points*
+in its borders, so we can connect them , the positions inside
+a box are absolute to a relative point, the self.x , self.y in the
+a_simple_class.
+
+- a_simple_class : just draw a box , with the name of the class ,
+attributes, functions, an the multiplicity of that class.
+
+- union_derivation : draws two simple classes , one of them the
+mather class, and the other, the derived class. It also
+supports several levels of derivation.
+
+- union_association : draw two simple classes, one of them has
+0:n instances of the other or viceversa.
+
+- union_aggregation: as derivation but with aggregates
+
+Although it'd be really wise to do a class with the common
+attributes of these three classes and inheritate from it, I've not
+done it. So many functions seem to be redundant and what's worse,
+some comments to common functions are done in just one class.
+Sorry for that... Read the simpler classes first.
+
+The position of the boxes are determined by the position of a base
+a_simple_class, whose contact_points will be supplied to the boxes
+conected (by unions) to it , so that the other boxes can obtain
+an absolute positioning.
+
+This model of contact points is not valid when you want to inheritate
+from several classes at the same time. :(
+
+So this piece of code is
+finished 3-1-99. Except for bugs.
+
+It's a nice piece of code for creating very simple drawings.
+
+"""
+
+"""
+Here are some nice nice constant to scale the drawings.
+Possibly, it'd be wiser to do some more.
+
+"""
+sscale="0.2"
+typeofletter = "\\small"
+
+"""
+ In this part we declare a higher level of interfaces
+for functions that generate Latex code .
+It'll be interesting that more of this kind of functions
+would be created. So that we isolate low level details...
+
+"""
+
+def generate_move(f,x,y ):
+ f.write(" \\move("+`x` +" "+ `y`+" )")
+
+def rgenerate_move(f,x,y ):
+ f.write(" \\rmove("+`x` +" "+ `y`+" )")
+
+"""
+a_placed_text and a_placed_line are objects for drawing
+small elements in the class, elements that don't play a main
+role in the structure of positioning of the draw.
+
+"""
+
+class a_placed_text:
+ def __init__(self,x,y,text):
+ self.x=x
+ self.y=y
+ self.text=text
+
+ def generate_move(self,f):
+ rgenerate_move(f,self.x, self.y)
+ f.write("\\rlvec (0 0) ")
+ f.write("\\htext { "+self.text+" }\n ")
+ rgenerate_move(f,-self.x, -self.y)
+
+
+class a_placed_line:
+ def __init__(self,x,y,x1,y1):
+ self.x=x
+ self.y=y
+ self.x1=x1
+ self.y1= y1
+
+ def generate_move(self,f):
+ rgenerate_move(f,self.x, self.y)
+ f.write("\\rlvec ("+`self.x1`+" "+`self.y1`+") ")
+ f.write("\\rlvec ("+`-self.x1`+" "+`-self.y1`+") ")
+ rgenerate_move(f,-self.x, -self.y)
+
+
+'''
+scale: it is just a factor for adjusting the length of the lines.
+This class is a simple abstraction for storing the scale.
+
+'''
+class scale:
+ def __init__(self,l):
+ self.l = l
+
+ def what_scale(self):
+ return self.l
+
+"""
+line, horizontal_line, vertical_line,... are simple objects intentended
+to keep information of a line to draw. Remember that we don't draw
+until we have settled the absolute positions, that is, when we've
+drawn another parts of the drawing, ...
+All this objects are intentended to generate relative positioning
+"""
+
+class line:
+ def __init__(self,length,dx,dy):
+ self.l = length
+ self.dx = dx
+ self.dy = dy
+ def what_length(self):
+ return self.l
+ def what_x(self):
+ return self.dx
+ def what_y(self):
+ return self.dy
+
+class horizontal_line(line):
+ def __init__(self,dx):
+ line.__init__(self,dx,dx,0)
+
+class vertical_line(line):
+ def __init__(self,dy):
+ line.__init__(self,dy,0,dy)
+
+class diagonal_line(line):
+ def __init__(self,dx,dy):
+ line.__init__(self,dy+dx,dx,dy)
+
+"""
+contact_point: It's another rather simple storage of information,
+it could named 'label', it helps to know where we can join one
+class with any other.
+
+"""
+
+class contact_point:
+ def __init__(self,name):
+ self.name = name
+
+ def what_name(self):
+ return self.name
+ def what_x(self):
+ return self.x
+ def what_y(self):
+ return self.y
+ def do_x(self,x):
+ self.x = x
+ def do_y(self,y):
+ self.y = y
+
+"""
+a_simple_class:
+This must generate code for a class, if we say :
+ clase frutas, attributes: perecedera , dulce, seca, carnosa,
+del tiempo, tropical,
+
+it must generate code that shows:
+
+
+__________
+| fruits |
+|--------|
+|cheap |
+|sweet |
+|dry |
+|.... |
+|________|
+
+or even :
+
+__________
+| fruits |
+|--------|
+|cheap |
+|sweet |
+|dry |
+| |
+| |
+----------
+|eat |
+|buy |
+|take |
+| / |
+|_____/_3|
+
+Where the first section has got the name of the class,
+the second one , the types of operations of the class 'fruits',
+and the number 3, means that this draw of the class fruit is
+the third one that can be seen in the documentation.
+
+This class is the base for building more complex drawings as
+derivations an associations.
+
+"""
+
+class a_simple_class(scale):
+ def __init__(self):
+ scale.__init__(self,2)
+ # it holds all the lines and contact points that make the
+ # drawing
+ self.list_of_lines = []
+ # in the example of the fruit, they'd be : sweet, dry, cheap
+ self.list_of_atributes = []
+ # in the example of the fruit, they'd be : eat, buy, take
+ self.list_of_functions = []
+ self.x = 0
+ self.y = 0
+ # x and y are attributes for calculating where we are ,
+ # when we draw 'virtually' the lines, so we can calculate
+ # every contact point.
+ # self.origin_x an self_origin_y are useful when actually
+ # drawing the class, they're the absolute positioning
+ # that are set by the topology all the whole drawing.
+ self.origin_x = 0
+ self.origin_y = 0
+ self.the_contact_points = {}
+ # this in the drawing of the fruit would be 3
+ self._index_of_class = 0
+
+ def do_origin_x(self, x):
+ self.origin_x = x
+
+ def do_origin_y(self, y):
+ self.origin_y = y
+
+ ''' propagate_origin are functions useful when we have several
+ levels of nesting, for example in an union-derivation, in
+ that case and when we start to say to lower drawings which
+ are their absolute positions. Then they propagate those
+ absolute positions, in a simple class they have no much
+ sense. But they are needed !!
+ '''
+ def propagate_origin_x(self,x):
+ self.do_origin_x(x)
+
+ def propagate_origin_y(self,y):
+ self.do_origin_y(y)
+
+ def do_name_clase(self,name_clase):
+ ''' in the example of the fruit, this would set self.name_clase
+ to fruit '''
+ self.name_clase = string.replace(name_clase,"_","\_")
+ self.calculate_width()
+
+ def do_attributes(self, list_of_atributes):
+ for i in list_of_atributes:
+ self.list_of_atributes.append(string.replace(i,"_","\_"))
+ self.calculate_width()
+
+ def calculate_width(self):
+ " \
+ calculate_width has the responsability of set the width \
+ of the class, so it must guess which of the words is the \
+ longest one \
+ "
+ j = len(self.name_clase)
+ for i in self.list_of_atributes+self.list_of_functions :
+ if len(i) > j:
+ j = len(i)
+ if j>30:
+ self.width_of_the_box = j /2.5
+ else:
+ self.width_of_the_box = j /2.2
+
+ def do_functions(self, list_of_functions):
+ for i in list_of_functions:
+ self.list_of_functions.append(string.replace(i,"_","\_"))
+ self.calculate_width()
+
+ def index_of_class(self, n):
+ self._index_of_class = n
+
+ ''' virtually_drawing, only calculates where we are moving to so we can decide on which position we set the contact points '''
+ def virtually_drawing(self,l):
+ for i in l:
+ if isinstance(i,vertical_line):
+ self.y = self.y + i.what_y()
+ elif isinstance(i, horizontal_line):
+ self.x = self.x + i.what_x()
+ elif isinstance(i, contact_point):
+ i.do_x(self.x)
+ i.do_y(self.y)
+ self.the_contact_points[i.what_name()] = i
+ self.list_of_lines.append(i)
+
+ def do_lines(self):
+ " this draw the lines of the drawing, but ... virtually!"
+ self.do_upwards_line()
+ self.do_lines_of_the_right()
+ self.do_downwards_line()
+ self.do_lines_of_the_left()
+
+ def do_upwards_line(self):
+ j = self.width_of_the_box
+ parte_uno = j * self.what_scale() / 2
+ self.virtually_drawing([horizontal_line(parte_uno),
+ contact_point('superior'),
+ horizontal_line(parte_uno)])
+
+
+ def do_lines_of_the_left(self):
+ " really it draws one single line!"
+ j = len(self.list_of_atributes+self.list_of_functions) + 4
+ if len(self.list_of_atributes) <2 :
+ j = j + 3
+ adding = []
+
+ self.virtually_drawing([vertical_line(j),
+ contact_point('leftsided'),
+ vertical_line(j)] + adding)
+
+
+ def do_lines_of_the_right(self):
+ " really it draws one single line!"
+ j = len(self.list_of_atributes+self.list_of_functions) + 4
+ if len(self.list_of_atributes) <2 :
+ j = j + 3
+ # at the end of this line is the place where we can
+ # insert the index of the class
+ adding = []
+ if self._index_of_class != 0:
+ adding = [a_placed_line(-3.5,0,3.5,3.5),
+ a_placed_text(-2.5,1, `self._index_of_class`)]
+ self.virtually_drawing([vertical_line(-j),
+ contact_point('rightsided'),
+ vertical_line(-j)]+ adding)
+
+
+ def do_downwards_line(self):
+ j = self.width_of_the_box
+ parte_uno = j * self.what_scale() / 2
+ self.virtually_drawing([horizontal_line(-parte_uno),
+ contact_point('inferior'),
+ horizontal_line(-parte_uno)])
+
+ def give_me_contact_point(self,i):
+ return self.the_contact_points[i]
+
+ def imprime_list_of_lines(self):
+ " This function is really useful for debugging purposes !!"
+ self.x = 0
+ self.y = 0
+ print self.list_of_lines
+ for i in self.list_of_lines:
+ if isinstance(i,vertical_line):
+ self.y = self.y + i.what_y()
+ print "vertical_line", self.y
+ elif isinstance(i, horizontal_line):
+ self.x = self.x + i.what_x()
+ print "horizontal_line", self.x
+ else: # it's a contact point
+ print "contact point ", i.what_name(), i.what_x(), i.what_y()
+
+ def generate_headings(self,f):
+ " this function is only needed when the simple class is the \
+ only one drawing, so it must generate the latex command of \
+ the preface of the drawing! "
+ global sscale, typeofletter
+ fi = open(f,'w')
+ fi.write( "\\begin{center}\n"+ "\\begin{texdraw}\n"+ typeofletter+" \\drawdim {cm}\n \setunitscale "+sscale + " \\linewd 0.02\n" )
+ return fi
+
+ def generate_latex_code(self,f):
+ " This function is only needed when the simple class is the \
+ only one drawing, then it generates latex heading , footnote,\
+ and the class itself"
+ fi =self.generate_headings(f)
+ self.core_generate_latex_code(fi)
+ self.generate_footnote(fi)
+
+ def core_generate_latex_code(self,fi):
+ " Draw the lines, and all the words of the drawing \
+ of the simple class "
+ self.genera_labels(fi)
+ for i in self.list_of_lines:
+ if isinstance(i,vertical_line):
+ fi.write("\\rlvec(0 "+`i.what_y()`+" )\n")
+ elif isinstance(i, horizontal_line):
+ fi.write( "\\rlvec( "+`i.what_x()`+" 0)\n")
+ elif isinstance(i, a_placed_text):
+ i.generate_move(fi)
+ elif isinstance(i, a_placed_line):
+ i.generate_move(fi)
+
+
+ def generate_footnote(self,fi):
+ fi.write( "\\end{texdraw}\n"+ "\\end{center}\n")
+ fi.close()
+
+ def adjusted_text(self,f, x, y ,e):
+ " It's a higher level way of placing an object in x,y"
+ f.write("\\htext("+`x`+" "+`y`+" ) { "+e+" }\n ")
+
+ def genera_labels(self,f):
+ " this function really draws the simple class"
+ self.generate_label_name_of_class(f)
+ self.generate_atributes(f)
+ self.generate_functions(f)
+ self.draw_line_of_the_box_of_the_name_of_the_class(f)
+ self.draw_line_of_the_box_of_the_functions_of_the_class(f)
+
+ def generate_label_name_of_class(self, f):
+ generate_move(f,self.origin_x, self.origin_y )
+ f.write("\\rlvec(0 0) \\textref h:L v:C ")
+ self.adjusted_text(f, 0.5 + self.origin_x, -1 + self.origin_y, self.name_clase)
+
+ def generate_atributes(self,f):
+ generate_move(f,self.origin_x, self.origin_y )
+ f.write("\\rlvec(0 0) \\textref h:L v:C ")
+ counter = -2.8
+ for i in self.list_of_atributes:
+ counter = counter - 1.7
+ self.adjusted_text(f,0.5 + self.origin_x, counter + -1 + self.origin_y, i)
+
+ def generate_functions(self,f):
+ " generate the functions of the class, in the example of fruits \
+ they'd be eat,take, buy "
+ generate_move(f,self.origin_x, self.origin_y )
+ f.write("\\rlvec(0 0) \\textref h:L v:C ")
+ counter = -self.poor_adjustment()
+ for i in self.list_of_functions:
+ counter = counter - 1.6
+ self.adjusted_text(f,0.5 + self.origin_x, counter + -1 + self.origin_y, i)
+
+ def draw_line_of_the_box_of_the_name_of_the_class(self,f):
+ " this line is the one below the name of the class"
+ j = self.width_of_the_box
+ j = j * self.what_scale()
+ generate_move(f, self.origin_x, self.origin_y - 2.4)
+ f.write("\\rlvec("+`j` +" 0 )")
+ generate_move(f, self.origin_x, self.origin_y )
+
+ def draw_line_of_the_box_of_the_functions_of_the_class(self,f):
+ " this line is the one above the functions of the class"
+ if self.list_of_functions == []:
+ return
+ j = self.width_of_the_box
+ j = j * self.what_scale()
+ yoffset = self.poor_adjustment()
+ generate_move(f, self.origin_x, self.origin_y - yoffset)
+ print self.name_clase,yoffset
+ f.write("\\rlvec("+`j` +" 0 )")
+ generate_move(f, self.origin_x, self.origin_y )
+
+ def poor_adjustment(self):
+ yoffset = len(self.list_of_atributes)* 2.9
+ if yoffset < 10 :
+ yoffset = 10
+ return yoffset
+
+'''
+union_derivation is intended to do things like :
+
+ ------
+ | |
+ | a |
+ |----|
+ |
+ |
+ d
+ ----------
+ | |
+ | |
+ --- ---
+ |b| |c|
+ --- ---
+
+where : a,b,c are simple classes or another union_derivationes.
+
+d is a triangle :)
+'''
+
+
+'''
+See the comments of simple_class first , because I won t repeat
+them here again .
+
+'''
+'''
+Terminology, the mother class is sometimes called part_a,
+the first daughter class is sometimes called part_b, and
+the rest of daughter classes are called parts_c
+'''
+
+class union_derivation(scale):
+ def __init__(self):
+ scale.__init__(self,2)
+ self.x = 0
+ self.y = 0
+ self.the_contact_points={}
+ self.parts_c = []
+ self.groups_of_lines=[]
+
+ def give_me_contact_point(self,i):
+ return self.the_contact_points[i]
+
+ def do_origin_x(self, x):
+ self.origin_x = x
+
+ def do_origin_y(self, y):
+ self.origin_y = y
+
+ '''
+ Here the propagations are more serious than in a simple_class \
+ the require absolute positioning of the class involved in the\
+ drawing '''
+ def propagate_origin_x(self,x):
+ print "propagating x at",x
+ self.part_a.do_origin_x(x)
+ cp = self.part_a.give_me_contact_point('inferior')
+ self.do_origin_x ( cp.what_x() + self.part_a.origin_x )
+
+ def propagate_origin_y(self,y):
+ self.part_a.do_origin_y(y)
+ cp = self.part_a.give_me_contact_point('inferior')
+ self.do_origin_y ( cp.what_y() + self.part_a.origin_y )
+
+ def virtually_drawing(self,l, list_of_lines):
+ for i in l:
+ if isinstance(i,vertical_line):
+ self.y = self.y + i.what_y()
+ elif isinstance(i, horizontal_line):
+ self.x = self.x + i.what_x()
+ elif isinstance(i, diagonal_line):
+ self.y = self.y + i.what_y()
+ self.x = self.x + i.what_x()
+ elif isinstance(i, a_placed_text):
+ pass
+ elif isinstance(i, a_placed_line):
+ pass
+ elif isinstance(i, contact_point) :
+ i.do_x(self.x)
+ i.do_y(self.y)
+ self.the_contact_points[i.what_name()] = i
+ list_of_lines.append(i)
+
+ def add_a_new_derivation(self,c):
+ " This function adds a derivation to a compound class-derived\
+ class"
+ self.parts_c.append(c)
+ cp = self.give_me_contact_point(`2*len(self.parts_c) - 1`+' next_derivation')
+ print "Adding new derivation at ", cp.what_x(), cp.what_y()
+ j = self.what_scale() / 2
+ k = []
+ # all this draws the arm the joins a daughter with the
+ # rest of the family
+ # besides, notice, that odd (1,3,5) contact points are
+ # places for new daughters of the family, and even (0,2,4)
+ # are places where the 'current' daughter is actually
+ # placed
+ self.virtual_move(self.give_me_contact_point(`2*len(self.parts_c) -1`+' next_derivation'))
+ self.virtually_drawing([horizontal_line( j * self.last_width),
+ contact_point(`2*len(self.parts_c) +1`+' next_derivation'),
+ vertical_line( -j * 2),
+ contact_point(`2*len(self.parts_c)`+' next_derivation')], k)
+ self.groups_of_lines.append(list(k))
+ self.last_width = c.width_of_the_box * 2 + 2
+
+ def virtual_move(self,c):
+ self.x = c.what_x()
+ self.y = c.what_y()
+
+ def add_union(self, a, b):
+ " a is the union_derivation or the class mother and\
+ b is the derived class "
+ if isinstance(a, union_derivation):
+ self.add_a_new_derivation(b)
+ else:
+ self.part_a = a
+ self.part_b = b
+ self.last_width = self.part_b.width_of_the_box *1.5 + 2
+ self.width_of_the_box = self.last_width
+ self.create_the_derivation(a,b)
+
+ def create_the_derivation(self,a,b):
+ cp = a.give_me_contact_point('inferior')
+ self.do_origin_x ( cp.what_x() )
+ self.do_origin_y ( cp.what_y() )
+ print "line 269, consdiag",self.x, self.y
+ j = self.what_scale() / 2
+ k = []
+ # here it's drawn the arm that joins the mother class
+ # and the first daughter. Besides we stablish some contact
+ # points, 0 next_derivation, is the place of the first daughter
+ # 1 next_derivation the place where the next daughter could
+ # join the family
+ self.virtually_drawing([vertical_line(- j * 7),
+ diagonal_line(j,-j),
+ contact_point('1 next_derivation'),
+ horizontal_line(-2*j),
+ diagonal_line(j,j),
+ diagonal_line(-j,-j),
+ horizontal_line(-12*j),
+ vertical_line( -j * 2),
+ contact_point('0 next_derivation')],k)
+ self.groups_of_lines.append(list(k))
+
+
+ def generate_headings(self,f):
+ global sscale
+ fi = open(f,'w')
+ fi.write( "\\begin{center}\n"+ "\\begin{texdraw}\n"+ typeofletter+ " \\drawdim {cm}\n \setunitscale "+sscale+ " \\linewd 0.02\n" )
+ return fi
+
+
+ def generate_latex_lines(self, lines,fi):
+ for i in lines:
+ if isinstance(i,vertical_line):
+ fi.write("\\rlvec(0 "+`i.what_y()`+" )\n")
+ elif isinstance(i, horizontal_line):
+ fi.write("\\rlvec( "+`i.what_x()`+" 0)\n")
+ elif isinstance(i,diagonal_line):
+ fi.write("\\rlvec( "+`i.what_x()`+" "+ `i.what_y()`+")\n")
+ elif isinstance(i, a_placed_text):
+ i.generate_move(fi)
+
+
+
+ def generate_latex_code(self,fo):
+ fi = self.generate_headings(fo)
+
+ self.core_generate_latex_code(fi)
+
+ self.generate_latex_foot(fi)
+
+ def core_generate_latex_code(self,fi):
+ self.part_a.core_generate_latex_code(fi)
+ generate_move(fi, self.origin_x, self.origin_y)
+ self.generate_latex_lines(self.groups_of_lines[0],fi)
+
+ cp = self.give_me_contact_point('0 next_derivation')
+ # once we've drawn part_a , then we can know where part_b
+ # should lie...
+ self.part_b.propagate_origin_x ( cp.what_x() + self.origin_x - 3)
+ self.part_b.propagate_origin_y ( cp.what_y() + self.origin_y )
+ self.part_b.core_generate_latex_code(fi)
+ self.generate_rest_derivations(fi)
+
+ def generate_latex_foot(self,fi):
+ fi.write( "\\end{texdraw}\n"+ "\\end{center}\n")
+ fi.close()
+
+ def generate_rest_derivations(self,f):
+ j = 1
+ for i in self.parts_c:
+ # the even next derivations (1,3,5,...) mark the
+ # place where new daughters will be placed
+ cp = self.give_me_contact_point(`2*j -1 `+' next_derivation')
+ generate_move(f,cp.what_x() + self.origin_x, cp.what_y() + self.origin_y )
+ self.generate_latex_lines(self.groups_of_lines[j],f)
+ cp = self.give_me_contact_point(`2*j `+' next_derivation')
+ i.propagate_origin_x ( cp.what_x() + self.origin_x - 3)
+ i.propagate_origin_y ( cp.what_y() + self.origin_y )
+ i.core_generate_latex_code(f)
+ j = j + 1
+
+
+'''
+this is the class that intends to do :
+
+--------| |-----
+| |1:1 1:2| |
+| a |---------- b |
+| | | |
+|-------| |_____|
+
+where a and b are simple classes !!
+
+I have done not much else in this class, and you should understand
+this one if you have understood the previous ones.
+
+'''
+
+class union_association(scale):
+ def __init__(self):
+ scale.__init__(self,2)
+ self.x = 0
+ self.y = 0
+ self.the_contact_points={}
+ self.united = []
+ self.parts_c = []
+ self.groups_of_lines=[]
+
+ def give_me_contact_point(self,i):
+ return self.the_contact_points[i]
+
+ def do_origin_x(self, x):
+ self.origin_x = x
+
+ def do_origin_y(self, y):
+ self.origin_y = y
+
+ def propagate_origin_x(self,x):
+ print "propagating x at",x
+ self.part_a.do_origin_x(x)
+ cp = self.part_a.give_me_contact_point('inferior')
+ self.do_origin_x ( cp.what_x() + self.part_a.origin_x )
+
+ def propagate_origin_y(self,y):
+ self.part_a.do_origin_y(y)
+ cp = self.part_a.give_me_contact_point('inferior')
+ self.do_origin_y ( cp.what_y() + self.part_a.origin_y )
+
+ def virtually_drawing(self,l, list_of_lines):
+ for i in l:
+ if isinstance(i,vertical_line):
+ self.y = self.y + i.what_y()
+ elif isinstance(i, horizontal_line):
+ self.x = self.x + i.what_x()
+ elif isinstance(i, diagonal_line):
+ self.y = self.y + i.what_y()
+ self.x = self.x + i.what_x()
+ elif isinstance(i, a_placed_text ):
+ # this sort doesn't affects internal positioning
+ pass
+ elif isinstance(i, contact_point):
+ # it's a contact point
+ i.do_x(self.x)
+ i.do_y(self.y)
+ self.the_contact_points[i.what_name()] = i
+ # otherwise it doesn't affect to the positioning
+ list_of_lines.append(i)
+
+ def add_a_new_association(self,c):
+ pass
+
+ def virtual_move(self,c):
+ self.x = c.what_x()
+ self.y = c.what_y()
+
+ def add_union(self, a, b, texta= None, textb = None):
+ " a is the union_derivation or the class mother and\
+ b is the derived class "
+ if isinstance(a, union_association):
+ self.add_a_new_association(b)
+ else:
+ self.part_a = a
+ self.part_b = b
+ self.create_the_association(a,b,texta, textb)
+
+ def create_the_association(self,a,b,texta,textb):
+ j = self.what_scale() / 2
+ cp = a.give_me_contact_point('rightsided')
+ self.do_origin_x ( cp.what_x() )
+ self.do_origin_y ( cp.what_y() )
+ print "line 269, consdiag",self.x, self.y
+ k = []
+ f = (len(texta) + len(textb)) * 1.6
+ self.virtually_drawing([ a_placed_text(0.1*j,j,texta),
+ horizontal_line(f*j),
+ a_placed_text(-j*1.3*len(textb),j,textb),
+ contact_point("rightsided")
+ ], k)
+ self.groups_of_lines.append(list(k))
+
+
+ def generate_headings(self,f):
+ global sscale
+ fi = open(f,'w')
+ fi.write( "\\begin{center}\n"+ "\\begin{texdraw}\n"+ typeofletter+ " \\drawdim {cm}\n \setunitscale "+sscale+ " \\linewd 0.02\n" )
+ return fi
+
+
+ def generate_latex_lines(self, lines,fi):
+ for i in lines:
+ if isinstance(i,vertical_line):
+ fi.write("\\rlvec(0 "+`i.what_y()`+" )\n")
+ elif isinstance(i, horizontal_line):
+ fi.write("\\rlvec( "+`i.what_x()`+" 0)\n")
+ elif isinstance(i,diagonal_line):
+ fi.write("\\rlvec( "+`i.what_x()`+" "+ `i.what_y()`+")\n")
+ elif isinstance(i, a_placed_text):
+ i.generate_move(fi)
+
+ def generate_latex_code(self,fo):
+ fi = self.generate_headings(fo)
+
+ self.core_generate_latex_code(fi)
+
+ self.generate_latex_foot(fi)
+
+ def core_generate_latex_code(self,fi):
+ self.part_a.core_generate_latex_code(fi)
+ generate_move(fi, self.origin_x, self.origin_y)
+ self.generate_latex_lines(self.groups_of_lines[0],fi)
+
+ cp = self.give_me_contact_point('rightsided')
+ self.part_b.propagate_origin_x ( cp.what_x() + self.origin_x )
+ self.part_b.propagate_origin_y ( cp.what_y() + self.origin_y + 4)
+ self.part_b.core_generate_latex_code(fi)
+ self.generate_rest_derivations(fi)
+
+ def generate_latex_foot(self,fi):
+ fi.write( "\\end{texdraw}\n"+ "\\end{center}\n")
+ fi.close()
+
+ def generate_rest_derivations(self,f):
+ pass
+
+
+class union_aggregation(union_derivation):
+ def __init__(self):
+ union_derivation.__init__(self)
+
+ def create_the_derivation(self,a,b):
+ " This creates another kind of derivation"
+ cp = a.give_me_contact_point('inferior')
+ self.do_origin_x ( cp.what_x() )
+ self.do_origin_y ( cp.what_y() )
+ print "line 269, consdiag",self.x, self.y
+ j = self.what_scale() / 2
+ k = []
+ # here it's drawn the arm that joins the mother class
+ # and the first daughter. Besides we stablish some contact
+ # points, 0 next_derivation, is the place of the first daughter
+ # 1 next_derivation the place where the next daughter could
+ # join the family
+ self.virtually_drawing([
+ diagonal_line(j,-j), # we draw \
+ diagonal_line(-j,-j), # /
+ diagonal_line(j,j), # now we return back
+ diagonal_line(-j,j),
+ diagonal_line(-j,-j), # we draw the another /
+ diagonal_line(j,-j), # \
+ vertical_line(- j * 8),
+ contact_point('1 next_derivation'),
+ horizontal_line(-12*j), # a bit of adjustment here
+ vertical_line( -j * 2),
+ contact_point('0 next_derivation')
+ ],k)
+ self.groups_of_lines.append(list(k))
+
+
+
+def test():
+ " this test creates several levels of inheritances"
+ c = a_simple_class()
+ c.do_name_clase('fruta')
+ c.do_attributes(['perecedera' , 'dulce', 'seca', 'carnosa',
+ 'del tiempo', 'tropical'])
+ c.do_lines()
+ #c.imprime_list_of_lines()
+ c.generate_latex_code('result')
+
+ d = a_simple_class()
+ d.do_name_clase('empleado')
+ d.do_attributes(['paga por horas' , 'sueldo'])
+ d.do_lines()
+ #d.imprime_list_of_lines()
+ d.generate_latex_code('result2')
+ e = union_derivation()
+ e.add_union(c,d)
+ f = a_simple_class()
+# f.do_name_clase('employee')
+# f.do_attributes(['weekly wage' , 'social insecurity'])
+# f.do_lines()
+# e.add_union(e,f)
+ g= a_simple_class()
+ g.do_name_clase('python')
+ g.do_attributes(['easily workable', 'non strict typing'])
+ g.do_lines()
+ e.add_union(e,g)
+ h = a_simple_class()
+ h.do_name_clase('fruta')
+ h.do_attributes(['perecedera' , 'dulce', 'seca', 'carnosa',
+ 'del tiempo', 'tropical'])
+ h.do_lines()
+ j = a_simple_class()
+ j.do_name_clase('empleado')
+ j.do_attributes(['paga por horas' , 'sueldo'])
+ j.do_lines()
+ i = union_derivation()
+ i.add_union(j,h)
+ e.add_union(e,i)
+ e.generate_latex_code('result3')
+
+
+def test1():
+ " This test make an association"
+ c = a_simple_class()
+ c.do_name_clase('enterprise')
+ c.do_attributes(['name' , 'profits', 'established', 'fiscal paradises',
+ 'frauds', 'bad tricks'])
+ c.do_lines()
+ #c.imprime_list_of_lines()
+ c.generate_latex_code('result')
+
+ d = a_simple_class()
+ d.do_name_clase('worker')
+ d.do_attributes(['wage' , 'timetable', 'seniority'])
+ d.do_lines()
+ #d.imprime_list_of_lines()
+ #d.generate_latex_code('result2')
+ e = union_association()
+ e.add_union(c,d,"0:n","0:1")
+ e.generate_latex_code('drawing7.tex')
+
+def test2():
+ " This tests uses the section of functions in every class, and the marks of repeated-class"
+ c = a_simple_class()
+ c.do_name_clase('frutas')
+ c.do_attributes(['name' , 'dulce', 'seca', 'carnosa',
+ 'del tiempo', 'tropical'])
+ c.do_functions(['comer','tirar','vender'])
+ c.index_of_class(3)
+ c.do_lines()
+ #c.imprime_list_of_lines()
+ c.generate_latex_code('result3')
+
+def _generate_single_class():
+ c = a_simple_class()
+ c.do_name_clase('enterprise')
+ c.do_attributes(['name' , 'benefits', 'money', 'health',
+ 'hobbies', 'dreams', 'under_score.'])
+ c.do_lines()
+
+ c.generate_latex_code('drawing1.tex')
+
+def _generate_single_class_long_names():
+ c = a_simple_class()
+ c.do_name_clase('person')
+ c.do_attributes(['name' , 'sex', 'money', 'health',
+ 'hobbies', 'dreams', 'opinion about latest polls',
+ 'position when playing soccer',
+ 'favourite scripting language'])
+ c.do_lines()
+ c.generate_latex_code('drawing2.tex')
+
+def _generate_single_class_function_and_mark():
+ c = a_simple_class()
+ c.do_name_clase('person')
+ c.do_attributes(['name' , 'sex', 'money', 'health',
+ 'hobbies', 'dreams'])
+ c.do_functions(['dream', 'love', 'play soccer', 'diving'])
+ c.index_of_class(3)
+
+ c.do_lines()
+ c.generate_latex_code('drawing3.tex')
+
+def _generate_simple_inheritance():
+ c = a_simple_class()
+ c.do_name_clase('person')
+ c.do_attributes(['name' , 'sex', 'money', 'health',
+ 'hobbies', 'dreams'])
+ c.do_functions(['dream', 'love', 'play soccer', 'diving'])
+
+ c.do_lines()
+ d = a_simple_class()
+ d.do_name_clase('work')
+ d.do_attributes(['salary' , 'post',
+ 'labor union', 'productivity', 'qualifications',
+ 'capabilities'])
+ d.do_functions(['work', 'strike', 'be ill', 'be fired'])
+
+ d.do_lines()
+ e = union_derivation()
+ e.add_union(c,d)
+ e.generate_latex_code('drawing4.tex')
+
+def _generate_multiple_inheritance():
+ c = a_simple_class()
+ c.do_name_clase('person')
+ c.do_attributes(['name' , 'sex', 'money', 'health',
+ 'hobbies', 'dreams'])
+
+ c.do_lines()
+ d = a_simple_class()
+ d.do_name_clase('worker')
+ d.do_attributes(['salary' , 'post',
+ 'labor union', 'productivity', 'qualifications',
+ 'capabilities'])
+
+ d.do_lines()
+ f = a_simple_class()
+ f.do_name_clase('father')
+ f.do_attributes(['busy' , 'tenderness',
+ 'stubornness', 'caress', 'kisses', 'capabilities'])
+
+ f.do_lines()
+ g = a_simple_class()
+ g.do_name_clase('chess player')
+ g.do_attributes(['elo' , 'cruelty',
+ 'stubornness', 'bad tricks', 'intelligence', 'openings knowledge'])
+
+ g.do_lines()
+ e = union_derivation()
+ e.add_union(c,d)
+ e.add_union(e,f)
+ e.add_union(e,g)
+ e.generate_latex_code('drawing5.tex')
+
+def _generate_multiple_inheritance_with_multiple_levels():
+ d = a_simple_class()
+ d.do_name_clase('worker')
+ d.do_attributes(['salary' , 'post',
+ 'labor union', 'productivity', 'qualifications',
+ 'capabilities'])
+
+
+ d.do_lines()
+ f = a_simple_class()
+ f.do_name_clase('computer scientist')
+ f.do_attributes(['languages' , 'preferred OS',
+ 'preferred editor', 'hackerism', 'ATBB'])
+
+ f.do_lines()
+
+ h = union_derivation()
+ h.add_union(d,f)
+
+ c = a_simple_class()
+ c.do_name_clase('person')
+ c.do_attributes(['name' , 'sex', 'money', 'health',
+ 'hobbies', 'dreams'])
+ c.do_lines()
+
+ e = union_derivation()
+ e.add_union(c,h)
+ e.generate_latex_code('drawing6.tex')
+
+def _generate_associations():
+ test1()
+
+
+def _generate_multiple_aggregation():
+ c = a_simple_class()
+ c.do_name_clase('person')
+ c.do_attributes(['name' , 'sex', 'money', 'health',
+ 'hobbies', 'dreams'])
+
+ c.do_lines()
+ d = a_simple_class()
+ d.do_name_clase('worker')
+ d.do_attributes(['salary' , 'post',
+ 'labor union', 'productivity', 'qualifications',
+ 'capabilities'])
+
+ d.do_lines()
+ f = a_simple_class()
+ f.do_name_clase('father')
+ f.do_attributes(['busy' , 'tenderness',
+ 'stubornness', 'caress', 'kisses', 'capabilities'])
+
+ f.do_lines()
+ g = a_simple_class()
+ g.do_name_clase('chess player')
+ g.do_attributes(['elo' , 'cruelty',
+ 'stubornness', 'bad tricks', 'intelligence', 'openings knowledge'])
+
+ g.do_lines()
+ e = union_aggregation()
+ e.add_union(c,d)
+ e.add_union(e,f)
+ e.add_union(e,g)
+ e.generate_latex_code('drawing8.tex')
+
+
+if __name__=='__main__':
+ _generate_single_class()
+ _generate_single_class_long_names()
+ _generate_single_class_function_and_mark()
+ _generate_simple_inheritance()
+ _generate_multiple_inheritance()
+ _generate_multiple_inheritance_with_multiple_levels()
+ _generate_associations()
+ _generate_multiple_aggregation()
+
+
+
+
+