/[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 902 - (hide annotations)
Thu Nov 16 07:22:08 2006 UTC (16 years, 4 months ago) by gross
File MIME type: text/x-python
File size: 17057 byte(s)
extended functionality
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 isPoint(self):
50     return False
51     def isCurve(self):
52     return False
53     def isSurface(self):
54     return False
55     def isCurveLoop(self):
56     return False
57     def isSurfaceLoop(self):
58     return False
59     def __neg__(self):
60     return ReversedPrimitive(self)
61 gross 902 def __pos__(self):
62     return self.copy()
63     def __add__(self,other):
64     out=self.copy()
65     out+=other
66     return out
67     def __iadd__(self,other):
68     self.shift()
69     def setLocalLength(self,factor=1.):
70     for p in self.getPoints(): p.setLocalLength(factor)
71     def shift(self,shift):
72     for p in self.getPoints(): p+=shift
73     def copy(self):
74     return Primitive()
75     def getGmshCommand(self):
76     raise NotImplementedError("getGmshCommand is not implemented for this class %s."%self.__class__.__name__)
77     def getHistory(self):
78     return set()
79     def getPoints(self):
80     return set()
81     def translate(self,shift):
82     raise NotImplementedError("translate is not implemented for this class %s."%self.__class__.__name__)
83 gross 898
84 gross 899 class ReversedPrimitive(object):
85     def __init__(self,prim):
86     self.__prim=prim
87     def __getattr__(self,name):
88     if name == "getID":
89     return self.getReverseID
90     else:
91     return getattr(self.__prim,name)
92     def getReverseID(self):
93     return -self.__prim.getID()
94    
95     class Point(Primitive):
96 gross 898 """
97     a three dimensional point
98     """
99     def __init__(self,x=0.,y=0.,z=0.,local_scale=1.):
100     """
101     creates a point with coorinates x,y,z with a relative refinement factor
102     """
103     super(Point, self).__init__()
104     if not local_scale > 0.:
105     raise ValueError("local_scale needs to be positive.")
106     self._x=numarray.array([x,y,z],numarray.Float64)
107 gross 899 self.setLocalScale(local_scale)
108 gross 898 def setLocalScale(self,factor=1.):
109 gross 902 """
110     sets the local relative length scale
111     """
112 gross 898 self.__local_scale=factor
113 gross 902 def getLocalScale(self):
114     return self.__local_scale
115     def copy(self):
116     c=self.getCoordinates()
117     return Point(c[0],c[1],c[2],local_scale=self.getLocalScale())
118 gross 899 def isPoint(self):
119     return True
120     def getCoordinates(self):
121     return self._x
122     def getGmshCommand(self):
123     c=self.getCoordinates()
124     return "Point(%s) = {%e , %e, %e , %e * scale};"%(self.getID(),c[0],c[1],c[2], self.getLocalScale())
125     def getHistory(self):
126     return set([self])
127 gross 902 def getPoints(self):
128     return set([self])
129     def shift(self,shift):
130     """
131     shifts the point by a given shift
132     """
133     self._x+=numarray.array(shift,numarray.Float64)
134     def translate(self,shift):
135     """
136     returns the point shifted by shift
137     """
138     out=self.copy()
139     out+=other
140     return out
141 gross 898
142 gross 902
143 gross 899 class Curve(Primitive):
144 gross 898 """
145     a curve
146     """
147     def __init__(self,*args):
148     """
149     defines a curve form a set of control points
150     """
151     super(Curve, self).__init__()
152     l=len(args)
153     for i in range(l):
154 gross 899 if not args[i].isPoint():
155     raise TypeError("%s-th argument is not a Point object."%i)
156     self.__nodes=args
157 gross 898 def __len__(self):
158     return len(self.__nodes)
159 gross 899 def isCurve(self):
160     return True
161 gross 898 def getStart(self):
162     """
163     returns start point
164     """
165     return self.__nodes[0]
166    
167     def getEnd(self):
168     """
169     returns end point
170     """
171     return self.__nodes[-1]
172    
173     def getNodes(self):
174     """
175     returns a list of the nodes
176     """
177     return self.__nodes
178 gross 899 def getGmshCommand(self):
179     out=""
180     for i in self.getNodes():
181     if len(out)>0:
182     out+=", %s"%i.getID()
183     else:
184     out="%s"%i.getID()
185     return "Spline(%s) = {%s};"%(self.getID(),out)
186 gross 902 def getHistory(self):
187     out=set([self])
188     for i in self.getNodes(): out|=i.getHistory()
189     return out
190     def getPoints(self):
191     out=set()
192     for i in self.getNodes(): out|=i.getPoints()
193     return out
194 gross 898
195 gross 902
196 gross 898 class BezierCurve(Curve):
197     """
198     a Bezier curve
199     """
200     def __neg__(self):
201 gross 899 """
202     returns the line segment with swapped start and end points
203     """
204     return BezierCurve(self.getNodes()[::-1])
205     def __add__(self,other):
206     return BezierCurve([p+other for p in self.getNodes()])
207     def getGmshCommand(self):
208     out=""
209     for i in self.getNodes():
210     if len(out)>0:
211     out+=", %s"%i.getID()
212     else:
213     out="%s"%i.getID()
214     return "Bezier(%s) = {%s};"%(self.getID(),out)
215 gross 898
216     class BSplineCurve(Curve):
217     """
218     a BSpline curve. Control points may be repeated.
219     """
220     def __neg__(self):
221 gross 899 """
222     returns the line segment with swapped start and end points
223     """
224     return BSplineCurve(self.getNodes()[::-1])
225     def __add__(self,other):
226     return BSplineCurve([p+other for p in self.getNodes()])
227     def getGmshCommand(self):
228     out=""
229     for i in self.getNodes():
230     if len(out)>0:
231     out+=", %s"%i.getID()
232     else:
233     out="%s"%i.getID()
234     return "BSpline(%s) = {%s};"%(self.getID(),out)
235 gross 898
236     class Line(Curve):
237     """
238     a line is defined by two L{Point}s
239     """
240 gross 899 def __init__(self,start,end):
241     """
242     defines a curve form a set of control points
243     """
244     super(Line, self).__init__(start,end)
245 gross 898 def __neg__(self):
246 gross 899 return ReversedPrimitive(self)
247     def __add__(self,other):
248     return Line(self.getEnd()+other,self.getStart()+other)
249     def getGmshCommand(self):
250     return "Line(%s) = {%s, %s};"%(self.getID(),self.getStart().getID(),self.getEnd().getID())
251 gross 898
252     class Arc(Curve):
253     """
254     defines an arc
255     """
256     def __init__(self,center,start,end):
257     """
258     creates an arc by the start point, end point and center
259     """
260 gross 899 if center.isPoint():
261 gross 898 raise TypeError("center needs to be a Point object.")
262     super(Arc, self).__init__(start,end)
263     self.__center=center
264    
265     def getCenter(self):
266     """
267     returns center
268     """
269     return self.__center
270 gross 899 def __add__(self,other):
271     return Arc(self.getCenter()+other,self.getStart()+other,self.getEnd()+other)
272 gross 898
273 gross 899 def getHistory(self):
274     out=set([self])
275     out|=self.getCenter().getHistory()
276     for i in self.getNodes(): out|=i.getHistory()
277     return out
278 gross 902 def getPoints(self):
279     out=self.getCenter().getPoints()
280     for i in self.getNodes(): out|=i.getPoints()
281     return out
282 gross 899 def getGmshCommand(self):
283     return "Circle(%s) = {%s, %s, %s};"%(self.getID(),self.getStart().getID(),self.getCenter().getID(),self.getEnd().getID())
284    
285     class CurveLoop(Primitive):
286 gross 898 """
287     An oriented loop of curves.
288    
289     The loop must be closed and the L{Curves}s should be oriented consistently.
290     """
291     def __init__(self,*curves):
292     """
293     creates a polygon from a list of line curves. The curves must form a closed loop.
294     """
295     super(CurveLoop, self).__init__()
296 gross 899 self.__curves=[]
297     self.addCurve(*curves)
298     def addCurve(self,*curves):
299     for i in range(len(curves)):
300     if not curves[i].isCurve():
301     raise TypeError("%s-th argument is not a Curve object."%i)
302     self.__curves+=curves
303 gross 898
304 gross 899 def isCurveLoop(self):
305     return True
306 gross 898 def getCurves(self):
307     return self.__curves
308 gross 899 def __add__(self,other):
309     return CurveLoop(*tuple([c+other for c in self.getCurves()[::-1]]))
310 gross 898 def __len__(self):
311     return len(self.__curves)
312 gross 899 def getHistory(self):
313     out=set([self])
314     for i in self.getCurves(): out|=i.getHistory()
315     return out
316 gross 902 def getPoints(self):
317     out=set()
318     for i in self.getCurves(): out|=i.getPoints()
319     return out
320 gross 899 def getGmshCommand(self):
321     out=""
322     for i in self.getCurves():
323     if len(out)>0:
324     out+=", %s"%i.getID()
325     else:
326     out="%s"%i.getID()
327     return "Line Loop(%s) = {%s};"%(self.getID(),out)
328 gross 898
329 gross 899 class Surface(Primitive):
330 gross 898 """
331     a surface
332     """
333     def __init__(self,loop):
334     """
335     creates a surface with boundary loop
336    
337     @param loop: L{CurveLoop} defining the boundary of the surface
338     """
339     super(Surface, self).__init__()
340 gross 899 if not loop.isCurveLoop():
341 gross 898 raise TypeError("argument loop needs to be a CurveLoop object.")
342     self.__loop=loop
343 gross 899 def isSurface(self):
344     return True
345 gross 898 def getBoundaryLoop(self):
346     return self.__loop
347 gross 899 def __add__(self,other):
348     return Surface(self.getBoundaryLoop()+other)
349     def getHistory(self):
350     out=set([self]) | self.getBoundaryLoop().getHistory()
351     return out
352 gross 902 def getPoints(self):
353     return self.getBoundaryLoop().getPoints()
354 gross 899 def getGmshCommand(self):
355     return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
356    
357 gross 898 class PlaneSurface(Surface):
358     """
359     a plane surface with holes
360     """
361     def __init__(self,loop,holes=[]):
362     """
363     creates a plane surface.
364    
365     @param loop: L{CurveLoop} defining the boundary of the surface
366     @param holes: list of L{CurveLoop} defining holes in the surface.
367     @note: A CurveLoop defining a hole should not have any lines in common with the exterior CurveLoop.
368     A CurveLoop defining a hole should not have any lines in common with another CurveLoop defining a hole in the same surface.
369     """
370     super(PlaneSurface, self).__init__(loop)
371     for i in range(len(holes)):
372 gross 899 if not holes[i].inCurveLoop():
373 gross 898 raise TypeError("%i th hole needs to be a CurveLoop object.")
374     self.__holes=holes
375     def getHoles(self):
376     return self.__holes
377 gross 899 def __add__(self,other):
378     return PlaneSurface(self.getBoundaryLoop()+other, holes=[h+other for h in self.getHoles()])
379     def getHistory(self):
380     out=set([self]) | self.getBoundaryLoop().getHistory()
381     for i in self.getHoles(): out|=i.getHistory()
382     return out
383 gross 902 def getPoints(self):
384     out=self.getBoundaryLoop().getPoints()
385     for i in self.getHoles(): out|=i.getPoints()
386     return out
387 gross 899 def getGmshCommand(self):
388     out=""
389     for i in self.getHoles():
390     if len(out)>0:
391     out+=", %s"%i.getID()
392     else:
393     out="%s"%i.getID()
394     if len(out)>0:
395     return "Plane Surface(%s) = {%s, %s};"%(self.getID(),self.getBoundaryLoop().getID(), out)
396     else:
397     return "Plane Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
398 gross 898
399     class RuledSurface(Surface):
400     """
401     A ruled surface, i.e., a surface that can be interpolated using transfinite interpolation
402     """
403     def __init__(self,loop):
404     """
405     creates a ruled surface from a
406    
407     @param loop: L{CurveLoop} defining the boundary of the surface. There is a restriction of composed of either three or four L{Curve} objects.
408     """
409 gross 899 if not loop.isCurveLoop():
410 gross 898 raise TypeError("argument loop needs to be a CurveLoop object.")
411     if len(loop)<3:
412     raise TypeError("the loop must contain at least three Curves.")
413     super(RuledSurface, self).__init__(loop)
414 gross 899 def __add__(self,other):
415     return RuledSurface(self.getBoundaryLoop()+other)
416     def getGmshCommand(self):
417     return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
418 gross 898
419 gross 899 class SurfaceLoop(Primitive):
420 gross 898 """
421     a surface loop. It defines the shell of a volume.
422    
423     The loop must represent a closed shell, and the L{Surface}s should be oriented consistently.
424     """
425     def __init__(self,*surfaces):
426     """
427     creates a surface loop
428     """
429     super(SurfaceLoop, self).__init__()
430 gross 899 self.__surfaces=[]
431     self.addSurface(*surfaces)
432     def addSurface(self,*surfaces):
433     for i in range(len(surfaces)):
434     if not surfaces[i].isSurface():
435     raise TypeError("%s-th argument is not a Surface object."%i)
436     self.__surfaces+=surfaces
437 gross 898
438 gross 899 def isSurfaceLoop(self):
439     return True
440 gross 898 def getSurfaces(self):
441     return self.__surfaces
442 gross 899 def __add__(self,other):
443     return SurfaceLoop([c+other for c in self.getSurfaces])
444 gross 898 def __len__(self):
445     return len(self.__surfaces)
446 gross 899 def getHistory(self):
447     out=set([self])
448     for i in self.getSurfaces(): out|=i.getHistory()
449     return out
450 gross 902 def getPoints(self):
451     out=set()
452     for i in self.getSurfaces(): out|=i.getPoints()
453     return out
454 gross 899 def getGmshCommand(self):
455     out=""
456     for i in self.getSurfaces():
457     if len(out)>0:
458     out+=", %s"%i.getID()
459     else:
460     out="%s"%i.getID()
461     return "Surface Loop(%s) = {%s};"%(self.getID(),out)
462 gross 898
463 gross 899 class Volume(Primitive):
464 gross 898 """
465     a volume with holes.
466     """
467     def __init__(self,loop,holes=[]):
468     """
469     creates a volume
470    
471     @param loop: L{SurfaceLoop} defining the boundary of the surface
472     @param holes: list of L{SurfaceLoop} defining holes in the surface.
473     @note: A SurfaceLoop defining a hole should not have any surfaces in common with the exterior SurfaceLoop.
474     A SurfaceLoop defining a hole should not have any surfaces in common with another SurfaceLoop defining a hole in the same volume.
475     """
476     super(Volume, self).__init__()
477 gross 899 if not loop.isSurfaceLoop():
478 gross 898 raise TypeError("argument loop needs to be a SurfaceLoop object.")
479     for i in range(len(holes)):
480 gross 899 if not holes[i].isSurfaceLoop():
481 gross 898 raise TypeError("%i th hole needs to be a SurfaceLoop object.")
482     self.__loop=loop
483     self.__holes=holes
484     def getHoles(self):
485     return self.__holes
486     def getSurfaceLoop(self):
487     return self.__loop
488 gross 899 def __add__(self,other):
489     return Volume(self.getSurfaceLoop()+other, holes=[h+other for h in self.getHoles()])
490     def getHistory(self):
491     out=set([self]) | self.getSurfaceLoop().getHistory()
492     for i in self.getHoles(): out|=i.getHistory()
493     return out
494 gross 902 def getPoints(self):
495     out=self.getSurfaceLoop().getPoints()
496     for i in self.getHoles(): out|=i.Points()
497     return out
498 gross 899 def getGmshCommand(self):
499     out=""
500     for i in self.getHoles():
501     if len(out)>0:
502     out+=", %s"%i.getID()
503     else:
504     out="%s"%i.getID()
505     if len(out)>0:
506     return "Volume(%s) = {%s, %s};"%(self.getID(),self.getSurfaceLoop().getID(), out)
507     else:
508     return "Volume(%s) = {%s};"%(self.getID(),self.getSurfaceLoop().getID())
509 gross 898
510 gross 899 class PropertySet(Primitive):
511 gross 898 """
512 gross 899 defines a group L{Primitive} objects.
513 gross 898 """
514     def __init__(self,tag=None,*items):
515     super(PropertySet, self).__init__()
516     self.__items=items
517     self.__tag=tag
518 gross 899 def getHistory(self):
519     out=set([self, self.getBoundaryLoop().getHistory()])
520     for i in self.getHoles(): out|=i.getHistory()
521     return out
522    
523     class PrimitiveStack(object):
524     def __init__(self,*items):
525     self.__prims=set()
526     for i in items:
527     self.__prims|=i.getHistory()
528     self.__prims=list(self.__prims)
529     self.__prims.sort()
530    
531     def getGmshCommands(self):
532     out=""
533     for i in self.__prims:
534     out+=i.getGmshCommand()+"\n"
535     return out

  ViewVC Help
Powered by ViewVC 1.1.26