[Doc-SIG] Tex OO Rumbaugh classes drawer.

Manuel Gutierrez Algaba Manuel Gutierrez Algaba <irmina@ctv.es>
Mon, 9 Nov 1998 21:03:29 +0000 (GMT)


Hello, 

This is my 'saying hello to this list' email.

I have the problem that I have to do lots and lots of drawing
of classes for the documentation of my thesis. Although I could 
use any drawing utility, I think it could be easier to produce 
Texdraw code... So this is what I've done: 

'''
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.

By the way , I dont mind change this copyright notice to GPL,
pythonish or whatever, if you like

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 
the next steps are to do:
- union_derivation
- union_atribution

and create complex drawings.

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.

Currently it generates only tex code, but it will be interesting
,perhaps, to generate tcl/tk code, and do a small drawing utility 
in canvas. 
But now, my only target is to generate tex code, my inmediate target.

'''

'''
scale: it is just a factor for adjusting the length of the lines.

'''
class scale:
    def __init__(self,l):
	self.l = l

    def what_scale(self):
	return self.l


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 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 one should generate code for a class, that is ,
if we say :
 class frutas, attributes: perecedera , dulce, seca, carnosa, 
del tiempo, tropical,

then it generates code that represents:

__________
| frutas |
|--------|
|pereced |
|dulce   |
|seca    |
|....    |
|________|

Besides contact_points should be stablished to insert another
classes

'''

class a_simple_class(scale):
    def __init__(self):
	scale.__init__(self,2)
	self.list_of_lines = []
	self.x = 0
	self.y = 0

    def do_origin_x(self, x):
	self.originx = x

    def do_origin_y(self, y):
	self.originy = y

    def do_name_clase(self,name_clase):
	self.name_clase = name_clase
    
    def do_attributes(self, list_of_atributes):
	self.list_of_atributes = list_of_atributes

    def do_lines(self):
	self.do_line_upwards()
	self.do_lines_of_the_right()
	self.do_downwards_line()
	self.do_lines_of_the_left()

    def do_line_upwards(self):
	j = len(self.name_clase) 
	parte_uno = j * self.what_scale() / 2	
	self.virtually_drawing([horizontal_line(parte_uno),
				 contact_point('superior'),
				 horizontal_line(parte_uno)])

    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()
	    else: # es un punto de contacto
		i.do_x(self.x)
		i.do_y(self.y)
	    self.list_of_lines.append(i)

    def do_lines_of_the_left(self):
	j = len(self.list_of_atributes) + 2
	self.virtually_drawing([vertical_line(j),
                                contact_point('leftsided'),
				 vertical_line(j)])


    def do_lines_of_the_right(self):
	j = len(self.list_of_atributes) + 2
	self.virtually_drawing([vertical_line(-j),
                                contact_point('rightsided'),
				 vertical_line(-j)])


    def do_downwards_line(self):
	j = len(self.name_clase)
	parte_uno = j * self.what_scale() / 2	
	self.virtually_drawing([horizontal_line(-parte_uno),
				 contact_point('inferior'),
				 horizontal_line(-parte_uno)])


    def imprime_list_of_lines(self):
	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 is a  contact point
		print "contact point", i.what_name(), i.what_x(), i.what_y()		

    def generate_latex_code(self,f):
	fi = open(f,'w')
	print "\\begin{center}"
	print "\\begin{texdraw}"
	print "  \\drawdim {cm}"
	print " \\linewd 0.02"
	fi.write(  "\\begin{center}\n"+ "\\begin{texdraw}\n"+ "  \\drawdim {cm}\n \setunitscale 0.3"+ " \\linewd 0.02\n" )

	self.genera_labels(fi)
	for i in self.list_of_lines:
	    if isinstance(i,vertical_line):
		print "\\rlvec(0 ",i.what_y()," )"
		fi.write("\\rlvec(0 "+`i.what_y()`+" )\n")
	    elif isinstance(i, horizontal_line):
		self.x = self.x + i.what_x()
		fi.write( "\\rlvec( "+`i.what_x()`+" 0)\n")
	fi.write( "\\end{texdraw}\n"+  "\\end{center}\n")
	fi.close()

    def genera_labels(self,f):
	f.write(" \\move(0 0)\\lvec(0 0) \\textref h:L v:C \\htext(1.5 -1){"+self.name_clase+"}\n ")
	counter = -1.8
	for i in self.list_of_atributes:
	    counter = counter - 1.5
	    f.write("  \\htext(1.5 "+`counter`+"){"+i+"}\n ")
	j = len(self.name_clase)
	j = j * self.what_scale() 
	f.write("\\move(0 -2.4)\\rlvec("+`j` +" 0 )\\move(0 0)\n")


def test():
    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')



if __name__=='__main__':
    test()
	    
And that's what you can find in the 'result' file: 
\begin{center}
\begin{texdraw}
  \drawdim {cm}
 \setunitscale 0.3 \linewd 0.02
 \move(0 0)\lvec(0 0) \textref h:L v:C \htext(1.5 -1){fruta}
   \htext(1.5 -3.3){perecedera}
   \htext(1.5 -4.8){dulce}
   \htext(1.5 -6.3){seca}
   \htext(1.5 -7.8){carnosa}
   \htext(1.5 -9.3){del tiempo}
   \htext(1.5 -10.8){tropical}
 \move(0 -2.4)\rlvec(10 0 )\move(0 0)
\rlvec( 5 0)
\rlvec( 5 0)
\rlvec(0 -8 )
\rlvec(0 -8 )
\rlvec( -5 0)
\rlvec( -5 0)
\rlvec(0 8 )
\rlvec(0 8 )
\end{texdraw}
\end{center}

It's not too much. 
I'll improve the code until it does all what I need. 

Do you want to join ? If so, email irmina@ctv.es

I've created a web page for such a project in : 
www.ctv.es/USERS/irmina/texpython.htm

I think it's a very easy and
interesting project,... provide with Tex documentation python sources!!!

At last for those who use python and tex in their theses.

ideas? 

Regards
Manolo