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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 899 - (show annotations)
Mon Nov 13 08:02:24 2006 UTC (14 years, 10 months ago) by gross
File MIME type: text/x-python
File size: 15414 byte(s)
a first very basic version of pycad
1 # $Id:$
2
3 """
4 Geometrical Primitives
5
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 import numarray
29
30 global global_primitive_id_counter
31 global_primitive_id_counter=0
32
33 class Primitive(object):
34 """
35 template for elementary geometrical object
36 """
37 def __init__(self):
38 """
39 """
40 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
64 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 """
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 self.setLocalScale(local_scale)
88 def setLocalScale(self,factor=1.):
89 self.__local_scale=factor
90 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
105 class Curve(Primitive):
106 """
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 if not args[i].isPoint():
117 raise TypeError("%s-th argument is not a Point object."%i)
118 self.__nodes=args
119 def __len__(self):
120 return len(self.__nodes)
121 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
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 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
156 class BezierCurve(Curve):
157 """
158 a Bezier curve
159 """
160 def __neg__(self):
161 """
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
176 class BSplineCurve(Curve):
177 """
178 a BSpline curve. Control points may be repeated.
179 """
180 def __neg__(self):
181 """
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
196 class Line(Curve):
197 """
198 a line is defined by two L{Point}s
199 """
200 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 def __neg__(self):
206 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
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 if center.isPoint():
221 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 def __add__(self,other):
231 return Arc(self.getCenter()+other,self.getStart()+other,self.getEnd()+other)
232
233 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 """
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 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
260 def isCurveLoop(self):
261 return True
262 def getCurves(self):
263 return self.__curves
264 def __add__(self,other):
265 return CurveLoop(*tuple([c+other for c in self.getCurves()[::-1]]))
266 def __len__(self):
267 return len(self.__curves)
268 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
281 class Surface(Primitive):
282 """
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 if not loop.isCurveLoop():
293 raise TypeError("argument loop needs to be a CurveLoop object.")
294 self.__loop=loop
295 def isSurface(self):
296 return True
297 def getBoundaryLoop(self):
298 return self.__loop
299 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 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 if not holes[i].inCurveLoop():
323 raise TypeError("%i th hole needs to be a CurveLoop object.")
324 self.__holes=holes
325 def getHoles(self):
326 return self.__holes
327 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
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 if not loop.isCurveLoop():
356 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 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
365 class SurfaceLoop(Primitive):
366 """
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 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
384 def isSurfaceLoop(self):
385 return True
386 def getSurfaces(self):
387 return self.__surfaces
388 def __add__(self,other):
389 return SurfaceLoop([c+other for c in self.getSurfaces])
390 def __len__(self):
391 return len(self.__surfaces)
392 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
405 class Volume(Primitive):
406 """
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 if not loop.isSurfaceLoop():
420 raise TypeError("argument loop needs to be a SurfaceLoop object.")
421 for i in range(len(holes)):
422 if not holes[i].isSurfaceLoop():
423 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 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
448 class PropertySet(Primitive):
449 """
450 defines a group L{Primitive} objects.
451 """
452 def __init__(self,tag=None,*items):
453 super(PropertySet, self).__init__()
454 self.__items=items
455 self.__tag=tag
456 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