/[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 902 - (show 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 # $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 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 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
84 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 """
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 self.setLocalScale(local_scale)
108 def setLocalScale(self,factor=1.):
109 """
110 sets the local relative length scale
111 """
112 self.__local_scale=factor
113 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 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 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
142
143 class Curve(Primitive):
144 """
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 if not args[i].isPoint():
155 raise TypeError("%s-th argument is not a Point object."%i)
156 self.__nodes=args
157 def __len__(self):
158 return len(self.__nodes)
159 def isCurve(self):
160 return True
161 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 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 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
195
196 class BezierCurve(Curve):
197 """
198 a Bezier curve
199 """
200 def __neg__(self):
201 """
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
216 class BSplineCurve(Curve):
217 """
218 a BSpline curve. Control points may be repeated.
219 """
220 def __neg__(self):
221 """
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
236 class Line(Curve):
237 """
238 a line is defined by two L{Point}s
239 """
240 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 def __neg__(self):
246 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
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 if center.isPoint():
261 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 def __add__(self,other):
271 return Arc(self.getCenter()+other,self.getStart()+other,self.getEnd()+other)
272
273 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 def getPoints(self):
279 out=self.getCenter().getPoints()
280 for i in self.getNodes(): out|=i.getPoints()
281 return out
282 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 """
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 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
304 def isCurveLoop(self):
305 return True
306 def getCurves(self):
307 return self.__curves
308 def __add__(self,other):
309 return CurveLoop(*tuple([c+other for c in self.getCurves()[::-1]]))
310 def __len__(self):
311 return len(self.__curves)
312 def getHistory(self):
313 out=set([self])
314 for i in self.getCurves(): out|=i.getHistory()
315 return out
316 def getPoints(self):
317 out=set()
318 for i in self.getCurves(): out|=i.getPoints()
319 return out
320 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
329 class Surface(Primitive):
330 """
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 if not loop.isCurveLoop():
341 raise TypeError("argument loop needs to be a CurveLoop object.")
342 self.__loop=loop
343 def isSurface(self):
344 return True
345 def getBoundaryLoop(self):
346 return self.__loop
347 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 def getPoints(self):
353 return self.getBoundaryLoop().getPoints()
354 def getGmshCommand(self):
355 return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
356
357 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 if not holes[i].inCurveLoop():
373 raise TypeError("%i th hole needs to be a CurveLoop object.")
374 self.__holes=holes
375 def getHoles(self):
376 return self.__holes
377 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 def getPoints(self):
384 out=self.getBoundaryLoop().getPoints()
385 for i in self.getHoles(): out|=i.getPoints()
386 return out
387 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
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 if not loop.isCurveLoop():
410 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 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
419 class SurfaceLoop(Primitive):
420 """
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 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
438 def isSurfaceLoop(self):
439 return True
440 def getSurfaces(self):
441 return self.__surfaces
442 def __add__(self,other):
443 return SurfaceLoop([c+other for c in self.getSurfaces])
444 def __len__(self):
445 return len(self.__surfaces)
446 def getHistory(self):
447 out=set([self])
448 for i in self.getSurfaces(): out|=i.getHistory()
449 return out
450 def getPoints(self):
451 out=set()
452 for i in self.getSurfaces(): out|=i.getPoints()
453 return out
454 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
463 class Volume(Primitive):
464 """
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 if not loop.isSurfaceLoop():
478 raise TypeError("argument loop needs to be a SurfaceLoop object.")
479 for i in range(len(holes)):
480 if not holes[i].isSurfaceLoop():
481 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 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 def getPoints(self):
495 out=self.getSurfaceLoop().getPoints()
496 for i in self.getHoles(): out|=i.Points()
497 return out
498 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
510 class PropertySet(Primitive):
511 """
512 defines a group L{Primitive} objects.
513 """
514 def __init__(self,tag=None,*items):
515 super(PropertySet, self).__init__()
516 self.__items=items
517 self.__tag=tag
518 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