/[escript]/trunk/pycad/py_src/primitives.py
ViewVC logotype

Annotation of /trunk/pycad/py_src/primitives.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 899 - (hide annotations)
Mon Nov 13 08:02:24 2006 UTC (16 years, 4 months ago) by gross
File MIME type: text/x-python
File size: 15414 byte(s)
a first very basic version of pycad
1 gross 898 # $Id:$
2    
3     """
4 gross 899 Geometrical Primitives
5 gross 898
6     the concept is inspired by gmsh and very much focused on the fact that
7     the classes are used to wrk with gmsh.
8    
9     @var __author__: name of author
10     @var __copyright__: copyrights
11     @var __license__: licence agreement
12     @var __url__: url entry point on documentation
13     @var __version__: version
14     @var __date__: date of the version
15     """
16    
17    
18     __author__="Lutz Gross, l.gross@uq.edu.au"
19     __copyright__=""" Copyright (c) 2006 by ACcESS MNRF
20     http://www.access.edu.au
21     Primary Business: Queensland, Australia"""
22     __license__="""Licensed under the Open Software License version 3.0
23     http://www.opensource.org/licenses/osl-3.0.php"""
24     __url__="http://www.iservo.edu.au/esys/escript"
25     __version__="$Revision:$"
26     __date__="$Date:$"
27    
28 gross 899 import numarray
29    
30     global global_primitive_id_counter
31     global_primitive_id_counter=0
32    
33     class Primitive(object):
34 gross 898 """
35     template for elementary geometrical object
36     """
37     def __init__(self):
38     """
39     """
40 gross 899 global global_primitive_id_counter
41     self.__ID=global_primitive_id_counter
42     global_primitive_id_counter+=1
43     def getID(self):
44     return self.__ID
45     def __repr__(self):
46     return "%s(%s)"%(self.__class__.__name__,self.getID())
47     def __cmp__(self,other):
48     return cmp(self.getID(),other.getID())
49     def getGmshCommand(self):
50     raise NotImplementedError("getGmshCommand is not implemented for this class %s."%self.__class__.__name__)
51     def isPoint(self):
52     return False
53     def isCurve(self):
54     return False
55     def isSurface(self):
56     return False
57     def isCurveLoop(self):
58     return False
59     def isSurfaceLoop(self):
60     return False
61     def __neg__(self):
62     return ReversedPrimitive(self)
63 gross 898
64 gross 899 class ReversedPrimitive(object):
65     def __init__(self,prim):
66     self.__prim=prim
67     def __getattr__(self,name):
68     if name == "getID":
69     return self.getReverseID
70     else:
71     return getattr(self.__prim,name)
72     def getReverseID(self):
73     return -self.__prim.getID()
74    
75     class Point(Primitive):
76 gross 898 """
77     a three dimensional point
78     """
79     def __init__(self,x=0.,y=0.,z=0.,local_scale=1.):
80     """
81     creates a point with coorinates x,y,z with a relative refinement factor
82     """
83     super(Point, self).__init__()
84     if not local_scale > 0.:
85     raise ValueError("local_scale needs to be positive.")
86     self._x=numarray.array([x,y,z],numarray.Float64)
87 gross 899 self.setLocalScale(local_scale)
88 gross 898 def setLocalScale(self,factor=1.):
89     self.__local_scale=factor
90 gross 899 def isPoint(self):
91     return True
92     def getLocalScale(self):
93     return self.__local_scale
94     def getCoordinates(self):
95     return self._x
96     def __add__(self,other):
97     c=self.getCoordinates()+numarray.array(other,numarray.Float64)
98     return Point(x=c[0],y=c[1],z=c[2],local_scale=self.getLocalScale())
99     def getGmshCommand(self):
100     c=self.getCoordinates()
101     return "Point(%s) = {%e , %e, %e , %e * scale};"%(self.getID(),c[0],c[1],c[2], self.getLocalScale())
102     def getHistory(self):
103     return set([self])
104 gross 898
105 gross 899 class Curve(Primitive):
106 gross 898 """
107     a curve
108     """
109     def __init__(self,*args):
110     """
111     defines a curve form a set of control points
112     """
113     super(Curve, self).__init__()
114     l=len(args)
115     for i in range(l):
116 gross 899 if not args[i].isPoint():
117     raise TypeError("%s-th argument is not a Point object."%i)
118     self.__nodes=args
119 gross 898 def __len__(self):
120     return len(self.__nodes)
121 gross 899 def isCurve(self):
122     return True
123     def getHistory(self):
124     out=set([self])
125     for i in self.getNodes(): out|=i.getHistory()
126     return out
127 gross 898
128     def getStart(self):
129     """
130     returns start point
131     """
132     return self.__nodes[0]
133    
134     def getEnd(self):
135     """
136     returns end point
137     """
138     return self.__nodes[-1]
139    
140     def getNodes(self):
141     """
142     returns a list of the nodes
143     """
144     return self.__nodes
145 gross 899 def __add__(self,other):
146     return Curve([p+other for p in self.getNodes()])
147     def getGmshCommand(self):
148     out=""
149     for i in self.getNodes():
150     if len(out)>0:
151     out+=", %s"%i.getID()
152     else:
153     out="%s"%i.getID()
154     return "Spline(%s) = {%s};"%(self.getID(),out)
155 gross 898
156     class BezierCurve(Curve):
157     """
158     a Bezier curve
159     """
160     def __neg__(self):
161 gross 899 """
162     returns the line segment with swapped start and end points
163     """
164     return BezierCurve(self.getNodes()[::-1])
165     def __add__(self,other):
166     return BezierCurve([p+other for p in self.getNodes()])
167     def getGmshCommand(self):
168     out=""
169     for i in self.getNodes():
170     if len(out)>0:
171     out+=", %s"%i.getID()
172     else:
173     out="%s"%i.getID()
174     return "Bezier(%s) = {%s};"%(self.getID(),out)
175 gross 898
176     class BSplineCurve(Curve):
177     """
178     a BSpline curve. Control points may be repeated.
179     """
180     def __neg__(self):
181 gross 899 """
182     returns the line segment with swapped start and end points
183     """
184     return BSplineCurve(self.getNodes()[::-1])
185     def __add__(self,other):
186     return BSplineCurve([p+other for p in self.getNodes()])
187     def getGmshCommand(self):
188     out=""
189     for i in self.getNodes():
190     if len(out)>0:
191     out+=", %s"%i.getID()
192     else:
193     out="%s"%i.getID()
194     return "BSpline(%s) = {%s};"%(self.getID(),out)
195 gross 898
196     class Line(Curve):
197     """
198     a line is defined by two L{Point}s
199     """
200 gross 899 def __init__(self,start,end):
201     """
202     defines a curve form a set of control points
203     """
204     super(Line, self).__init__(start,end)
205 gross 898 def __neg__(self):
206 gross 899 return ReversedPrimitive(self)
207     def __add__(self,other):
208     return Line(self.getEnd()+other,self.getStart()+other)
209     def getGmshCommand(self):
210     return "Line(%s) = {%s, %s};"%(self.getID(),self.getStart().getID(),self.getEnd().getID())
211 gross 898
212     class Arc(Curve):
213     """
214     defines an arc
215     """
216     def __init__(self,center,start,end):
217     """
218     creates an arc by the start point, end point and center
219     """
220 gross 899 if center.isPoint():
221 gross 898 raise TypeError("center needs to be a Point object.")
222     super(Arc, self).__init__(start,end)
223     self.__center=center
224    
225     def getCenter(self):
226     """
227     returns center
228     """
229     return self.__center
230 gross 899 def __add__(self,other):
231     return Arc(self.getCenter()+other,self.getStart()+other,self.getEnd()+other)
232 gross 898
233 gross 899 def getHistory(self):
234     out=set([self])
235     out|=self.getCenter().getHistory()
236     for i in self.getNodes(): out|=i.getHistory()
237     return out
238     def getGmshCommand(self):
239     return "Circle(%s) = {%s, %s, %s};"%(self.getID(),self.getStart().getID(),self.getCenter().getID(),self.getEnd().getID())
240    
241     class CurveLoop(Primitive):
242 gross 898 """
243     An oriented loop of curves.
244    
245     The loop must be closed and the L{Curves}s should be oriented consistently.
246     """
247     def __init__(self,*curves):
248     """
249     creates a polygon from a list of line curves. The curves must form a closed loop.
250     """
251     super(CurveLoop, self).__init__()
252 gross 899 self.__curves=[]
253     self.addCurve(*curves)
254     def addCurve(self,*curves):
255     for i in range(len(curves)):
256     if not curves[i].isCurve():
257     raise TypeError("%s-th argument is not a Curve object."%i)
258     self.__curves+=curves
259 gross 898
260 gross 899 def isCurveLoop(self):
261     return True
262 gross 898 def getCurves(self):
263     return self.__curves
264 gross 899 def __add__(self,other):
265     return CurveLoop(*tuple([c+other for c in self.getCurves()[::-1]]))
266 gross 898 def __len__(self):
267     return len(self.__curves)
268 gross 899 def getHistory(self):
269     out=set([self])
270     for i in self.getCurves(): out|=i.getHistory()
271     return out
272     def getGmshCommand(self):
273     out=""
274     for i in self.getCurves():
275     if len(out)>0:
276     out+=", %s"%i.getID()
277     else:
278     out="%s"%i.getID()
279     return "Line Loop(%s) = {%s};"%(self.getID(),out)
280 gross 898
281 gross 899 class Surface(Primitive):
282 gross 898 """
283     a surface
284     """
285     def __init__(self,loop):
286     """
287     creates a surface with boundary loop
288    
289     @param loop: L{CurveLoop} defining the boundary of the surface
290     """
291     super(Surface, self).__init__()
292 gross 899 if not loop.isCurveLoop():
293 gross 898 raise TypeError("argument loop needs to be a CurveLoop object.")
294     self.__loop=loop
295 gross 899 def isSurface(self):
296     return True
297 gross 898 def getBoundaryLoop(self):
298     return self.__loop
299 gross 899 def __add__(self,other):
300     return Surface(self.getBoundaryLoop()+other)
301     def getHistory(self):
302     out=set([self]) | self.getBoundaryLoop().getHistory()
303     return out
304     def getGmshCommand(self):
305     return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
306    
307 gross 898 class PlaneSurface(Surface):
308     """
309     a plane surface with holes
310     """
311     def __init__(self,loop,holes=[]):
312     """
313     creates a plane surface.
314    
315     @param loop: L{CurveLoop} defining the boundary of the surface
316     @param holes: list of L{CurveLoop} defining holes in the surface.
317     @note: A CurveLoop defining a hole should not have any lines in common with the exterior CurveLoop.
318     A CurveLoop defining a hole should not have any lines in common with another CurveLoop defining a hole in the same surface.
319     """
320     super(PlaneSurface, self).__init__(loop)
321     for i in range(len(holes)):
322 gross 899 if not holes[i].inCurveLoop():
323 gross 898 raise TypeError("%i th hole needs to be a CurveLoop object.")
324     self.__holes=holes
325     def getHoles(self):
326     return self.__holes
327 gross 899 def __add__(self,other):
328     return PlaneSurface(self.getBoundaryLoop()+other, holes=[h+other for h in self.getHoles()])
329     def getHistory(self):
330     out=set([self]) | self.getBoundaryLoop().getHistory()
331     for i in self.getHoles(): out|=i.getHistory()
332     return out
333     def getGmshCommand(self):
334     out=""
335     for i in self.getHoles():
336     if len(out)>0:
337     out+=", %s"%i.getID()
338     else:
339     out="%s"%i.getID()
340     if len(out)>0:
341     return "Plane Surface(%s) = {%s, %s};"%(self.getID(),self.getBoundaryLoop().getID(), out)
342     else:
343     return "Plane Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
344 gross 898
345     class RuledSurface(Surface):
346     """
347     A ruled surface, i.e., a surface that can be interpolated using transfinite interpolation
348     """
349     def __init__(self,loop):
350     """
351     creates a ruled surface from a
352    
353     @param loop: L{CurveLoop} defining the boundary of the surface. There is a restriction of composed of either three or four L{Curve} objects.
354     """
355 gross 899 if not loop.isCurveLoop():
356 gross 898 raise TypeError("argument loop needs to be a CurveLoop object.")
357     if len(loop)<3:
358     raise TypeError("the loop must contain at least three Curves.")
359     super(RuledSurface, self).__init__(loop)
360 gross 899 def __add__(self,other):
361     return RuledSurface(self.getBoundaryLoop()+other)
362     def getGmshCommand(self):
363     return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
364 gross 898
365 gross 899 class SurfaceLoop(Primitive):
366 gross 898 """
367     a surface loop. It defines the shell of a volume.
368    
369     The loop must represent a closed shell, and the L{Surface}s should be oriented consistently.
370     """
371     def __init__(self,*surfaces):
372     """
373     creates a surface loop
374     """
375     super(SurfaceLoop, self).__init__()
376 gross 899 self.__surfaces=[]
377     self.addSurface(*surfaces)
378     def addSurface(self,*surfaces):
379     for i in range(len(surfaces)):
380     if not surfaces[i].isSurface():
381     raise TypeError("%s-th argument is not a Surface object."%i)
382     self.__surfaces+=surfaces
383 gross 898
384 gross 899 def isSurfaceLoop(self):
385     return True
386 gross 898 def getSurfaces(self):
387     return self.__surfaces
388 gross 899 def __add__(self,other):
389     return SurfaceLoop([c+other for c in self.getSurfaces])
390 gross 898 def __len__(self):
391     return len(self.__surfaces)
392 gross 899 def getHistory(self):
393     out=set([self])
394     for i in self.getSurfaces(): out|=i.getHistory()
395     return out
396     def getGmshCommand(self):
397     out=""
398     for i in self.getSurfaces():
399     if len(out)>0:
400     out+=", %s"%i.getID()
401     else:
402     out="%s"%i.getID()
403     return "Surface Loop(%s) = {%s};"%(self.getID(),out)
404 gross 898
405 gross 899 class Volume(Primitive):
406 gross 898 """
407     a volume with holes.
408     """
409     def __init__(self,loop,holes=[]):
410     """
411     creates a volume
412    
413     @param loop: L{SurfaceLoop} defining the boundary of the surface
414     @param holes: list of L{SurfaceLoop} defining holes in the surface.
415     @note: A SurfaceLoop defining a hole should not have any surfaces in common with the exterior SurfaceLoop.
416     A SurfaceLoop defining a hole should not have any surfaces in common with another SurfaceLoop defining a hole in the same volume.
417     """
418     super(Volume, self).__init__()
419 gross 899 if not loop.isSurfaceLoop():
420 gross 898 raise TypeError("argument loop needs to be a SurfaceLoop object.")
421     for i in range(len(holes)):
422 gross 899 if not holes[i].isSurfaceLoop():
423 gross 898 raise TypeError("%i th hole needs to be a SurfaceLoop object.")
424     self.__loop=loop
425     self.__holes=holes
426     def getHoles(self):
427     return self.__holes
428     def getSurfaceLoop(self):
429     return self.__loop
430 gross 899 def __add__(self,other):
431     return Volume(self.getSurfaceLoop()+other, holes=[h+other for h in self.getHoles()])
432     def getHistory(self):
433     out=set([self]) | self.getSurfaceLoop().getHistory()
434     for i in self.getHoles(): out|=i.getHistory()
435     return out
436     def getGmshCommand(self):
437     out=""
438     for i in self.getHoles():
439     if len(out)>0:
440     out+=", %s"%i.getID()
441     else:
442     out="%s"%i.getID()
443     if len(out)>0:
444     return "Volume(%s) = {%s, %s};"%(self.getID(),self.getSurfaceLoop().getID(), out)
445     else:
446     return "Volume(%s) = {%s};"%(self.getID(),self.getSurfaceLoop().getID())
447 gross 898
448 gross 899 class PropertySet(Primitive):
449 gross 898 """
450 gross 899 defines a group L{Primitive} objects.
451 gross 898 """
452     def __init__(self,tag=None,*items):
453     super(PropertySet, self).__init__()
454     self.__items=items
455     self.__tag=tag
456 gross 899 def getHistory(self):
457     out=set([self, self.getBoundaryLoop().getHistory()])
458     for i in self.getHoles(): out|=i.getHistory()
459     return out
460    
461     class PrimitiveStack(object):
462     def __init__(self,*items):
463     self.__prims=set()
464     for i in items:
465     self.__prims|=i.getHistory()
466     self.__prims=list(self.__prims)
467     self.__prims.sort()
468    
469     def getGmshCommands(self):
470     out=""
471     for i in self.__prims:
472     out+=i.getGmshCommand()+"\n"
473     return out
474    
475     def getPycadCommands(self,name="TMP_"):
476     out=""
477     for i in self.__prims:
478     out+=i.getPycadCommand(name)+"\n"

  ViewVC Help
Powered by ViewVC 1.1.26