/[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 925 - (hide annotations)
Wed Jan 10 22:40:00 2007 UTC (12 years, 8 months ago) by gross
File MIME type: text/x-python
File size: 27354 byte(s)
testing for CurvedLoop added.
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 gross 915 from transformations import _TYPE, Translation, Dilation, Transformation
30 gross 899
31    
32 gross 915 def resetGlobalPrimitiveIdCounter():
33 gross 917 """
34     initializes the global primitive ID counter
35     """
36 gross 915 global global_primitive_id_counter
37     global_primitive_id_counter=1
38    
39 gross 916 def setToleranceForColocation(tol=1.e-11):
40 gross 917 """
41     set the global tolerance for colocation checks to tol
42     """
43 gross 916 global global_tolerance_for_colocation
44     global_tolerance_for_colocation=tol
45    
46     def getToleranceForColocation():
47 gross 917 """
48     returns the global tolerance for colocation checks
49     """
50 gross 916 return global_tolerance_for_colocation
51    
52 gross 915 resetGlobalPrimitiveIdCounter()
53 gross 916 setToleranceForColocation()
54 gross 915
55 gross 899 class Primitive(object):
56 gross 898 """
57     template for elementary geometrical object
58     """
59     def __init__(self):
60     """
61 gross 915
62 gross 898 """
63 gross 899 global global_primitive_id_counter
64     self.__ID=global_primitive_id_counter
65     global_primitive_id_counter+=1
66 gross 915
67 gross 899 def getID(self):
68     return self.__ID
69 gross 915
70 gross 899 def __repr__(self):
71     return "%s(%s)"%(self.__class__.__name__,self.getID())
72 gross 923
73 gross 899 def __cmp__(self,other):
74     return cmp(self.getID(),other.getID())
75 gross 916
76     def getConstructionPoints(self):
77 gross 912 """
78 gross 916 returns the points used to construct the primitive
79 gross 912 """
80     out=set()
81 gross 916 for i in self.getPrimitives():
82 gross 912 if isinstance(i,Point): out.add(i)
83 gross 916 return list(out)
84 gross 912
85 gross 916 def getPrimitives(self):
86 gross 912 """
87 gross 916 returns primitives used to construct the primitive
88 gross 912 """
89 gross 916 return []
90 gross 912
91 gross 915 def copy(self):
92     """
93 gross 916 returns a deep copy of the object
94 gross 915 """
95 gross 925 return self.substitute({})
96 gross 912
97 gross 915
98     def modifyBy(self,transformation):
99 gross 916 """
100     modifies the coordinates by applying a transformation
101     """
102     for p in self.getConstructionPoints(): p.modifyBy(transformation)
103 gross 915
104 gross 916
105 gross 915 def __add__(self,other):
106     """
107     returns a new object shifted by other
108     """
109     return self.apply(Translation(numarray.array(other,_TYPE)))
110    
111     def __sub__(self,other):
112     """
113     returns a new object shifted by other
114     """
115     return self.apply(Translation(-numarray.array(other,_TYPE)))
116    
117     def __iadd__(self,other):
118     """
119     shifts the point by other
120     """
121     self.modifyBy(Translation(numarray.array(other,_TYPE)))
122     return self
123    
124     def __isub__(self,other):
125     """
126     shifts the point by -other
127     """
128     self.modifyBy(Translation(-numarray.array(other,_TYPE)))
129     return self
130    
131     def __imul__(self,other):
132     """
133     modifies object by applying L{Transformation} other. If other is not a L{Transformation} it will try convert it.
134     """
135     if isinstance(other,int) or isinstance(other,float):
136     trafo=Dilation(other)
137     elif isinstance(other,numarray.NumArray):
138     trafo=Translation(other)
139     elif isinstance(other,Transformation):
140     trafo=other
141     else:
142     raise TypeError, "cannot convert argument to Trnsformation class object."
143     self.modifyBy(trafo)
144     return self
145    
146     def __rmul__(self,other):
147     """
148     applies L{Transformation} other to object. If other is not a L{Transformation} it will try convert it.
149     """
150     if isinstance(other,int) or isinstance(other,float):
151     trafo=Dilation(other)
152     elif isinstance(other,numarray.NumArray):
153     trafo=Translation(other)
154     elif isinstance(other,Transformation):
155     trafo=other
156     else:
157 gross 916 raise TypeError, "cannot convert argument to Transformation class object."
158 gross 915 return self.apply(trafo)
159    
160 gross 899 def __neg__(self):
161     return ReversedPrimitive(self)
162 gross 915
163 gross 916 def setLocalScale(self,factor=1.):
164     """
165     sets the local refinement factor
166     """
167     for p in self.getConstructionPoints(): p.setLocalScale(factor)
168    
169     def getGmshCommand(self, local_scaling_factor=1.):
170     """
171     returns the Gmsh command(s) to create the primitive
172     """
173 gross 902 raise NotImplementedError("getGmshCommand is not implemented for this class %s."%self.__class__.__name__)
174 gross 898
175 gross 916 def apply(self,transformation):
176     """
177 gross 925 returns a new L{Point} by applying the transformation
178 gross 916 """
179 gross 925 out=self.copy()
180     out.modifyBy(transformation)
181     return out
182 gross 916
183     def isColocated(self,primitive):
184     """
185     returns True is the two primitives are located at the smae position
186     """
187     raise NotImplementedError("isColocated is not implemented for this class %s."%self.__class__.__name__)
188    
189 gross 925 def substitute(self,sub_dict):
190     """
191     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
192     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
193     with substituted arguments is returned.
194     """
195     if not sub_dict.has_key(self):
196     sub_dict[self]=self.__class__()
197     return sub_dict[self]
198    
199 gross 899 class Point(Primitive):
200 gross 898 """
201     a three dimensional point
202     """
203     def __init__(self,x=0.,y=0.,z=0.,local_scale=1.):
204     """
205 gross 912 creates a point with coorinates x,y,z with the local refinement factor local_scale
206 gross 898 """
207     super(Point, self).__init__()
208 gross 915 self.setCoordinates(numarray.array([x,y,z],_TYPE))
209 gross 899 self.setLocalScale(local_scale)
210 gross 915
211 gross 898 def setLocalScale(self,factor=1.):
212 gross 902 """
213 gross 912 sets the local refinement factor
214 gross 902 """
215 gross 912 if factor<=0.:
216     raise ValueError("scaling factor must be positive.")
217 gross 898 self.__local_scale=factor
218 gross 902 def getLocalScale(self):
219 gross 912 """
220     returns the local refinement factor
221     """
222 gross 902 return self.__local_scale
223 gross 912 def getCoordinates(self):
224     """
225     returns the coodinates of the point as L{numarray.NumArray} object
226     """
227     return self._x
228 gross 915 def setCoordinates(self,x):
229 gross 912 """
230     returns the coodinates of the point as L{numarray.NumArray} object
231     """
232 gross 915 if not isinstance(x, numarray.NumArray):
233     self._x=numarray.array(x,_TYPE)
234     else:
235     self._x=x
236    
237 gross 916 def getPrimitives(self):
238 gross 912 """
239 gross 916 returns primitives used to construct the primitive
240 gross 912 """
241 gross 916 return [self]
242 gross 912
243 gross 916 def isColocated(self,primitive):
244 gross 912 """
245 gross 916 returns True if L{Point} primitive is colocation (same coordinates)
246     that means if |self-primitive| <= tol * max(|self|,|primitive|)
247 gross 912 """
248 gross 916 if isinstance(primitive,Point):
249     primitive=primitive.getCoordinates()
250     c=self.getCoordinates()
251     d=c-primitive
252     return numarray.dot(d,d)<=getToleranceForColocation()**2*max(numarray.dot(c,c),numarray.dot(primitive,primitive))
253     else:
254     return False
255 gross 912
256 gross 925 def substitute(self,sub_dict):
257     """
258     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
259     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
260     with substituted arguments is returned.
261     """
262     if not sub_dict.has_key(self):
263     c=self.getCoordinates()
264     sub_dict[self]=Point(c[0],c[1],c[2],local_scale=self.getLocalScale())
265     return sub_dict[self]
266 gross 915
267     def modifyBy(self,transformation):
268     """
269     modifies the coordinates by applying a transformation
270     """
271     self.setCoordinates(transformation(self.getCoordinates()))
272    
273    
274     def getGmshCommand(self, local_scaling_factor=1.):
275 gross 916 """
276     returns the Gmsh command(s) to create the primitive
277     """
278 gross 899 c=self.getCoordinates()
279 gross 915 return "Point(%s) = {%s , %s, %s , %s };"%(self.getID(),c[0],c[1],c[2], self.getLocalScale()*local_scaling_factor)
280 gross 898
281 gross 916 class Primitive1D(Primitive):
282 gross 898 """
283 gross 916 general one-dimensional primitive
284 gross 898 """
285     def __init__(self,*args):
286     """
287 gross 916 create a one-dimensional primitive
288 gross 898 """
289 gross 916 super(Primitive1D, self).__init__()
290    
291     class Curve(Primitive1D):
292     """
293     a curve defined through a list of control points.
294     """
295     def __init__(self,*points):
296     """
297     defines a curve form control points
298     """
299     if len(points)<2:
300     raise TypeError("Curve needs at least two points")
301 gross 898 super(Curve, self).__init__()
302 gross 916 i=0
303     for p in points:
304     i+=1
305     if not isinstance(p,Point): raise TypeError("%s-th argument is not a Point object."%i)
306     self.__points=points
307    
308     def __len__(self):
309     """
310     returns the number of control points
311     """
312     return len(self.__points)
313    
314     def getStartPoint(self):
315 gross 898 """
316     returns start point
317     """
318 gross 916 return self.__points[0]
319 gross 898
320 gross 916 def getEndPoint(self):
321 gross 898 """
322     returns end point
323     """
324 gross 916 return self.__points[-1]
325 gross 898
326 gross 916 def getControlPoints(self):
327 gross 898 """
328 gross 916 returns a list of the points
329 gross 898 """
330 gross 916 return self.__points
331    
332     def getPrimitives(self):
333     """
334     returns primitives used to construct the Curve
335     """
336     out=set()
337     for p in self.getControlPoints(): out|=set(p.getPrimitives())
338     out.add(self)
339     return list(out)
340    
341 gross 925 def substitute(self,sub_dict):
342 gross 916 """
343 gross 925 returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
344     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
345     with substituted arguments is returned.
346 gross 916 """
347 gross 925 if not sub_dict.has_key(self):
348     new_p=[]
349     for p in self.getControlPoints(): new_p.append(p.substitute(sub_dict))
350     sub_dict[self]=self.__class__(*tuple(new_p))
351     return sub_dict[self]
352 gross 916
353     def isColocated(self,primitive):
354     """
355     returns True curves are on the same position
356     """
357     if isinstance(primitive,self.__class__):
358     if len(primitive) == len(self):
359     cp0=self.getControlPoints()
360     cp1=primitive.getControlPoints()
361 gross 919 match=True
362 gross 916 for i in range(len(cp0)):
363     if not cp0[i].isColocated(cp1[i]):
364 gross 919 match=False
365     break
366     if not match:
367     for i in range(len(cp0)):
368     if not cp0[i].isColocated(cp1[len(cp0)-1-i]):
369     return False
370 gross 916 return True
371     else:
372     return False
373     else:
374     return False
375    
376     class Spline(Curve):
377     """
378     a spline curve defined through a list of control points.
379     """
380     def getGmshCommand(self):
381     """
382     returns the Gmsh command(s) to create the Curve
383     """
384 gross 899 out=""
385 gross 916 for i in self.getControlPoints():
386 gross 899 if len(out)>0:
387     out+=", %s"%i.getID()
388     else:
389     out="%s"%i.getID()
390     return "Spline(%s) = {%s};"%(self.getID(),out)
391 gross 916
392 gross 898
393     class BezierCurve(Curve):
394     """
395     a Bezier curve
396     """
397 gross 899 def getGmshCommand(self):
398 gross 916 """
399     returns the Gmsh command(s) to create the Curve
400     """
401 gross 899 out=""
402 gross 916 for i in self.getControlPoints():
403 gross 899 if len(out)>0:
404     out+=", %s"%i.getID()
405     else:
406     out="%s"%i.getID()
407     return "Bezier(%s) = {%s};"%(self.getID(),out)
408 gross 898
409 gross 916 class BSpline(Curve):
410 gross 898 """
411     a BSpline curve. Control points may be repeated.
412     """
413 gross 899 def getGmshCommand(self):
414 gross 916 """
415     returns the Gmsh command(s) to create the Curve
416     """
417 gross 899 out=""
418 gross 916 for i in self.getControlPoints():
419 gross 899 if len(out)>0:
420     out+=", %s"%i.getID()
421     else:
422     out="%s"%i.getID()
423     return "BSpline(%s) = {%s};"%(self.getID(),out)
424 gross 898
425     class Line(Curve):
426     """
427     a line is defined by two L{Point}s
428     """
429 gross 916 def __init__(self,*points):
430 gross 899 """
431 gross 916 defines a line with start and end point
432 gross 899 """
433 gross 916 if len(points)!=2:
434     raise TypeError("Line needs two points")
435     super(Line, self).__init__(*points)
436 gross 899 def getGmshCommand(self):
437 gross 916 """
438     returns the Gmsh command(s) to create the Curve
439     """
440     return "Line(%s) = {%s, %s};"%(self.getID(),self.getStartPoint().getID(),self.getEndPoint().getID())
441 gross 898
442 gross 916
443     class Arc(Primitive1D):
444 gross 898 """
445 gross 917 defines an arc which is strictly, smaller than Pi
446 gross 898 """
447     def __init__(self,center,start,end):
448     """
449     creates an arc by the start point, end point and center
450     """
451 gross 917 if not isinstance(center,Point): raise TypeError("center needs to be a Point object.")
452     if not isinstance(end,Point): raise TypeError("end needs to be a Point object.")
453     if not isinstance(start,Point): raise TypeError("start needs to be a Point object.")
454     # TODO: check length of circle.
455 gross 916 super(Arc, self).__init__()
456 gross 898 self.__center=center
457 gross 916 self.__start=start
458     self.__end=end
459 gross 898
460 gross 916 def getStartPoint(self):
461 gross 898 """
462 gross 916 returns start point
463     """
464     return self.__start
465    
466     def getEndPoint(self):
467     """
468     returns end point
469     """
470     return self.__end
471    
472     def getCenterPoint(self):
473     """
474 gross 898 returns center
475     """
476     return self.__center
477    
478 gross 916 def getPrimitives(self):
479     """
480 gross 917 returns the primitives used to construct the Curve
481 gross 916 """
482     out=set()
483     out|=set(self.getStartPoint().getPrimitives())
484     out|=set(self.getEndPoint().getPrimitives())
485     out|=set(self.getCenterPoint().getPrimitives())
486     out.add(self)
487     return list(out)
488    
489 gross 899 def getGmshCommand(self):
490 gross 916 """
491     returns the Gmsh command(s) to create the primitive
492     """
493     return "Circle(%s) = {%s, %s, %s};"%(self.getID(),self.getStartPoint().getID(),self.getCenterPoint().getID(),self.getEndPoint().getID())
494 gross 899
495 gross 925 def substitute(self,sub_dict):
496 gross 916 """
497 gross 925 returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
498     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
499     with substituted arguments is returned.
500 gross 916 """
501 gross 925 if not sub_dict.has_key(self):
502     sub_dict[self]=Arc(self.getCenterPoint().substitute(sub_dict),self.getStartPoint().substitute(sub_dict),self.getEndPoint().substitute(sub_dict))
503     return sub_dict[self]
504 gross 916
505     def isColocated(self,primitive):
506     """
507     returns True curves are on the same position
508     """
509     if isinstance(primitive,Arc):
510 gross 919 return (self.getCenterPoint().isColocated(primitive.getCenterPoint())) and ( \
511     (self.getEndPoint().isColocated(primitive.getEndPoint()) and self.getStartPoint().isColocated(primitive.getStartPoint()) ) \
512     or (self.getEndPoint().isColocated(primitive.getStartPoint()) and self.getStartPoint().isColocated(primitive.getEndPoint()) ) )
513 gross 916 else:
514     return False
515    
516 gross 919 class Primitive2D(Primitive):
517     """
518     general two-dimensional primitive
519     """
520     def __init__(self,*args):
521     """
522     create a two-dimensional primitive
523     """
524     super(Primitive2D, self).__init__()
525 gross 923
526 gross 919 class CurveLoop(Primitive2D):
527 gross 898 """
528     An oriented loop of curves.
529    
530     The loop must be closed and the L{Curves}s should be oriented consistently.
531     """
532     def __init__(self,*curves):
533     """
534     creates a polygon from a list of line curves. The curves must form a closed loop.
535     """
536     super(CurveLoop, self).__init__()
537 gross 923 if len(curves)<2:
538     raise TypeError("at least two curves have to be given.")
539 gross 899 for i in range(len(curves)):
540 gross 919 if not isinstance(curves[i],Primitive1D):
541     raise TypeError("%s-th argument is not a Primitive1D object."%i)
542 gross 923 # for the curves a loop:
543     used=[ False for i in curves]
544     self.__curves=[curves[0]]
545     used[0]=True
546     while not min(used):
547     found=False
548     for i in xrange(len(curves)):
549     if not used[i]:
550     if self.__curves[-1].getEndPoint() == curves[i].getStartPoint():
551     self.__curves.append(curves[i])
552     used[i]=True
553     found=True
554     break
555     if not found:
556     raise ValueError("loop is not closed.")
557     if not self.__curves[0].getStartPoint() == self.__curves[-1].getEndPoint():
558     raise ValueError("loop is not closed.")
559 gross 898
560     def getCurves(self):
561 gross 919 """
562     returns the curves defining the CurveLoop
563     """
564 gross 898 return self.__curves
565 gross 925
566 gross 898 def __len__(self):
567 gross 919 """
568     return the number of curves in the CurveLoop
569     """
570 gross 898 return len(self.__curves)
571 gross 919
572 gross 916 def getPrimitives(self):
573 gross 919 """
574     returns primitives used to construct the CurveLoop
575     """
576     out=set()
577     for c in self.getCurves(): out|=set(c.getPrimitives())
578     out.add(self)
579     return list(out)
580    
581 gross 925 def substitute(self,sub_dict):
582 gross 919 """
583 gross 925 returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
584     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
585     with substituted arguments is returned.
586 gross 919 """
587 gross 925 if not sub_dict.has_key(self):
588     new_c=[]
589     for c in self.getCurves(): new_c.append(c.substitute(sub_dict))
590     sub_dict[self]=CurveLoop(*tuple(new_c))
591     return sub_dict[self]
592 gross 919
593 gross 925
594 gross 919 def isColocated(self,primitive):
595     """
596     returns True if each curve is collocted with a curve in primitive
597     """
598     if isinstance(primitive,CurveLoop):
599     if len(primitive) == len(self):
600     cp0=self.getCurves()
601     cp1=primitive.getCurves()
602     for c0 in cp0:
603     collocated = False
604 gross 925 for c1 in cp1:
605     collocated = collocated or c0.isColocated(c1)
606 gross 919 if not collocated: return False
607     return True
608     else:
609     return False
610     else:
611     return False
612    
613 gross 899 def getGmshCommand(self):
614     out=""
615     for i in self.getCurves():
616     if len(out)>0:
617     out+=", %s"%i.getID()
618     else:
619     out="%s"%i.getID()
620     return "Line Loop(%s) = {%s};"%(self.getID(),out)
621 gross 898
622 gross 919 #=================================================================================================================================
623 gross 899 class Surface(Primitive):
624 gross 898 """
625     a surface
626     """
627     def __init__(self,loop):
628     """
629     creates a surface with boundary loop
630    
631     @param loop: L{CurveLoop} defining the boundary of the surface
632     """
633     super(Surface, self).__init__()
634 gross 899 if not loop.isCurveLoop():
635 gross 898 raise TypeError("argument loop needs to be a CurveLoop object.")
636     self.__loop=loop
637 gross 899 def isSurface(self):
638     return True
639 gross 898 def getBoundaryLoop(self):
640     return self.__loop
641 gross 899 def __add__(self,other):
642     return Surface(self.getBoundaryLoop()+other)
643 gross 916 def getPrimitives(self):
644     out=set([self]) | self.getBoundaryLoop().getPrimitives()
645 gross 899 return out
646 gross 916 def getConstructionPoints(self):
647     return self.getBoundaryLoop().getConstructionPoints()
648 gross 899 def getGmshCommand(self):
649     return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
650    
651 gross 898 class PlaneSurface(Surface):
652     """
653     a plane surface with holes
654     """
655     def __init__(self,loop,holes=[]):
656     """
657     creates a plane surface.
658    
659     @param loop: L{CurveLoop} defining the boundary of the surface
660     @param holes: list of L{CurveLoop} defining holes in the surface.
661     @note: A CurveLoop defining a hole should not have any lines in common with the exterior CurveLoop.
662     A CurveLoop defining a hole should not have any lines in common with another CurveLoop defining a hole in the same surface.
663     """
664     super(PlaneSurface, self).__init__(loop)
665     for i in range(len(holes)):
666 gross 899 if not holes[i].inCurveLoop():
667 gross 898 raise TypeError("%i th hole needs to be a CurveLoop object.")
668     self.__holes=holes
669     def getHoles(self):
670     return self.__holes
671 gross 899 def __add__(self,other):
672     return PlaneSurface(self.getBoundaryLoop()+other, holes=[h+other for h in self.getHoles()])
673 gross 916 def getPrimitives(self):
674     out=set([self]) | self.getBoundaryLoop().getPrimitives()
675     for i in self.getHoles(): out|=i.getPrimitives()
676 gross 899 return out
677 gross 916 def getConstructionPoints(self):
678     out=self.getBoundaryLoop().getConstructionPoints()
679     for i in self.getHoles(): out|=i.getConstructionPoints()
680 gross 902 return out
681 gross 899 def getGmshCommand(self):
682     out=""
683     for i in self.getHoles():
684     if len(out)>0:
685     out+=", %s"%i.getID()
686     else:
687     out="%s"%i.getID()
688     if len(out)>0:
689     return "Plane Surface(%s) = {%s, %s};"%(self.getID(),self.getBoundaryLoop().getID(), out)
690     else:
691     return "Plane Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
692 gross 898
693     class RuledSurface(Surface):
694     """
695     A ruled surface, i.e., a surface that can be interpolated using transfinite interpolation
696     """
697     def __init__(self,loop):
698     """
699     creates a ruled surface from a
700    
701     @param loop: L{CurveLoop} defining the boundary of the surface. There is a restriction of composed of either three or four L{Curve} objects.
702     """
703 gross 899 if not loop.isCurveLoop():
704 gross 898 raise TypeError("argument loop needs to be a CurveLoop object.")
705     if len(loop)<3:
706     raise TypeError("the loop must contain at least three Curves.")
707     super(RuledSurface, self).__init__(loop)
708 gross 899 def __add__(self,other):
709     return RuledSurface(self.getBoundaryLoop()+other)
710     def getGmshCommand(self):
711     return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
712 gross 898
713 gross 899 class SurfaceLoop(Primitive):
714 gross 898 """
715     a surface loop. It defines the shell of a volume.
716    
717     The loop must represent a closed shell, and the L{Surface}s should be oriented consistently.
718     """
719     def __init__(self,*surfaces):
720     """
721     creates a surface loop
722     """
723     super(SurfaceLoop, self).__init__()
724 gross 899 self.__surfaces=[]
725     self.addSurface(*surfaces)
726     def addSurface(self,*surfaces):
727     for i in range(len(surfaces)):
728     if not surfaces[i].isSurface():
729     raise TypeError("%s-th argument is not a Surface object."%i)
730     self.__surfaces+=surfaces
731 gross 898
732 gross 899 def isSurfaceLoop(self):
733     return True
734 gross 898 def getSurfaces(self):
735     return self.__surfaces
736 gross 899 def __add__(self,other):
737     return SurfaceLoop([c+other for c in self.getSurfaces])
738 gross 898 def __len__(self):
739     return len(self.__surfaces)
740 gross 916 def getPrimitives(self):
741 gross 899 out=set([self])
742 gross 916 for i in self.getSurfaces(): out|=i.getPrimitives()
743 gross 899 return out
744 gross 916 def getConstructionPoints(self):
745 gross 902 out=set()
746 gross 916 for i in self.getSurfaces(): out|=i.getConstructionPoints()
747 gross 902 return out
748 gross 899 def getGmshCommand(self):
749     out=""
750     for i in self.getSurfaces():
751     if len(out)>0:
752     out+=", %s"%i.getID()
753     else:
754     out="%s"%i.getID()
755     return "Surface Loop(%s) = {%s};"%(self.getID(),out)
756 gross 898
757 gross 899 class Volume(Primitive):
758 gross 898 """
759     a volume with holes.
760     """
761     def __init__(self,loop,holes=[]):
762     """
763     creates a volume
764    
765     @param loop: L{SurfaceLoop} defining the boundary of the surface
766     @param holes: list of L{SurfaceLoop} defining holes in the surface.
767     @note: A SurfaceLoop defining a hole should not have any surfaces in common with the exterior SurfaceLoop.
768     A SurfaceLoop defining a hole should not have any surfaces in common with another SurfaceLoop defining a hole in the same volume.
769     """
770     super(Volume, self).__init__()
771 gross 899 if not loop.isSurfaceLoop():
772 gross 898 raise TypeError("argument loop needs to be a SurfaceLoop object.")
773     for i in range(len(holes)):
774 gross 899 if not holes[i].isSurfaceLoop():
775 gross 898 raise TypeError("%i th hole needs to be a SurfaceLoop object.")
776     self.__loop=loop
777     self.__holes=holes
778     def getHoles(self):
779     return self.__holes
780     def getSurfaceLoop(self):
781     return self.__loop
782 gross 899 def __add__(self,other):
783     return Volume(self.getSurfaceLoop()+other, holes=[h+other for h in self.getHoles()])
784 gross 916 def getPrimitives(self):
785     out=set([self]) | self.getSurfaceLoop().getPrimitives()
786     for i in self.getHoles(): out|=i.getPrimitives()
787 gross 899 return out
788 gross 916 def getConstructionPoints(self):
789     out=self.getSurfaceLoop().getConstructionPoints()
790 gross 902 for i in self.getHoles(): out|=i.Points()
791     return out
792 gross 899 def getGmshCommand(self):
793     out=""
794     for i in self.getHoles():
795     if len(out)>0:
796     out+=", %s"%i.getID()
797     else:
798     out="%s"%i.getID()
799     if len(out)>0:
800     return "Volume(%s) = {%s, %s};"%(self.getID(),self.getSurfaceLoop().getID(), out)
801     else:
802     return "Volume(%s) = {%s};"%(self.getID(),self.getSurfaceLoop().getID())
803 gross 898
804 gross 912 class ReversedPrimitive(object):
805     def __init__(self,prim):
806     self.__prim=prim
807     def __getattr__(self,name):
808     if name == "getID":
809     return self.getReverseID
810     else:
811     return getattr(self.__prim,name)
812     def getReverseID(self):
813     return -self.__prim.getID()
814    
815 gross 899 class PropertySet(Primitive):
816 gross 898 """
817 gross 899 defines a group L{Primitive} objects.
818 gross 898 """
819     def __init__(self,tag=None,*items):
820     super(PropertySet, self).__init__()
821     self.__items=items
822     self.__tag=tag
823 gross 916 def getPrimitives(self):
824     out=set([self, self.getBoundaryLoop().getPrimitives()])
825     for i in self.getHoles(): out|=i.getPrimitives()
826 gross 899 return out
827    
828     class PrimitiveStack(object):
829     def __init__(self,*items):
830     self.__prims=set()
831     for i in items:
832 gross 916 self.__prims|=i.getPrimitives()
833 gross 899 self.__prims=list(self.__prims)
834     self.__prims.sort()
835    
836     def getGmshCommands(self):
837     out=""
838     for i in self.__prims:
839     out+=i.getGmshCommand()+"\n"
840     return out

  ViewVC Help
Powered by ViewVC 1.1.26