/[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 927 - (hide annotations)
Fri Jan 12 06:32:08 2007 UTC (12 years, 8 months ago) by gross
File MIME type: text/x-python
File size: 28832 byte(s)
surfaces implemented by no testing yet
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 927 class Surface(Primitive2D):
623 gross 898 """
624     a surface
625     """
626 gross 927 pass
627    
628     class RuledSurface(Surface):
629     """
630     A ruled surface, i.e., a surface that can be interpolated using transfinite interpolation
631     """
632 gross 898 def __init__(self,loop):
633     """
634 gross 927 creates a ruled surface with boundary loop
635 gross 898
636 gross 927 @param loop: L{CurveLoop} defining the boundary of the surface.
637 gross 898 """
638 gross 927 super(RuledSurface, self).__init__()
639     if not isinstance(CurveLoop):
640 gross 898 raise TypeError("argument loop needs to be a CurveLoop object.")
641 gross 927 if len(loop)<2:
642     raise TypeError("the loop must contain at least two Curves.")
643     if len(loop)>4:
644     raise TypeError("the loop must contain at least three Curves.")
645    
646 gross 898 self.__loop=loop
647 gross 927
648 gross 898 def getBoundaryLoop(self):
649 gross 927 """
650     returns the loop defining the boundary
651     """
652     return self.__loop
653    
654 gross 916 def getPrimitives(self):
655     out=set([self]) | self.getBoundaryLoop().getPrimitives()
656 gross 927
657 gross 899 def getGmshCommand(self):
658     return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
659    
660 gross 927 def getPrimitives(self):
661     """
662     returns primitives used to construct the CurveLoop
663     """
664     out=list(set([self]) | self.getBoundaryLoop().getPrimitives())
665    
666     def substitute(self,sub_dict):
667     """
668     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
669     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
670     with substituted arguments is returned.
671     """
672     if not sub_dict.has_key(self):
673     sub_dict[self]=CurveLoop(self.getBoundaryLoop().substitute(sub_dict))
674     return sub_dict[self]
675    
676     def isColocated(self,primitive):
677     """
678     returns True if each curve is collocted with a curve in primitive
679     """
680     if isinstance(primitive,RuledSurface):
681     return self.getBoundaryLoop().colocated(primitive.getBoundaryLoop())
682     else:
683     return False
684    
685     def createRuledSurface(*curves):
686     """
687     an easier way to create a L{RuledSurface} from given curves.
688     """
689     return RuledSurface(CurveLoop(*curves))
690    
691 gross 898 class PlaneSurface(Surface):
692     """
693     a plane surface with holes
694     """
695     def __init__(self,loop,holes=[]):
696     """
697 gross 927 creates a plane surface with a hole
698 gross 898
699     @param loop: L{CurveLoop} defining the boundary of the surface
700     @param holes: list of L{CurveLoop} defining holes in the surface.
701     @note: A CurveLoop defining a hole should not have any lines in common with the exterior CurveLoop.
702     A CurveLoop defining a hole should not have any lines in common with another CurveLoop defining a hole in the same surface.
703     """
704 gross 927 super(PlaneSurface, self).__init__()
705     if not isinstance(loop,CurveLoop):
706     raise TypeError("argument loop needs to be a CurveLoop object.")
707 gross 898 for i in range(len(holes)):
708 gross 899 if not holes[i].inCurveLoop():
709 gross 898 raise TypeError("%i th hole needs to be a CurveLoop object.")
710 gross 927 #TODO: check if lines are in a plane
711 gross 898 self.__holes=holes
712     def getHoles(self):
713 gross 927 """
714     returns the holes
715     """
716 gross 898 return self.__holes
717 gross 927 def getBoundaryLoop(self):
718     """
719     returns the loop defining the boundary
720     """
721     return self.__loop
722 gross 916 def getPrimitives(self):
723     out=set([self]) | self.getBoundaryLoop().getPrimitives()
724     for i in self.getHoles(): out|=i.getPrimitives()
725 gross 899 return out
726 gross 927
727 gross 899 def getGmshCommand(self):
728     out=""
729     for i in self.getHoles():
730     if len(out)>0:
731     out+=", %s"%i.getID()
732     else:
733     out="%s"%i.getID()
734     if len(out)>0:
735     return "Plane Surface(%s) = {%s, %s};"%(self.getID(),self.getBoundaryLoop().getID(), out)
736     else:
737     return "Plane Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())
738 gross 898
739 gross 927 def substitute(self,sub_dict):
740     """
741     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
742     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
743     with substituted arguments is returned.
744     """
745     if not sub_dict.has_key(self):
746     sub_dict[self]=CurveLoop(self.getBoundaryLoop().substitute(sub_dict),[ h.substitute(sub_dict) for h in self.getHoles()])
747     return sub_dict[self]
748 gross 898
749 gross 927 def isColocated(self,primitive):
750 gross 898 """
751 gross 927 returns True if each curve is collocted with a curve in primitive
752     """
753     if isinstance(primitive,PlaneSurface):
754     if self.getBoundaryLoop().colocated(primitive.getBoundaryLoop()):
755     my_h=self.getHoles()
756     h=primitive.getHoles()
757     else:
758     return False
759     else:
760     return False
761 gross 898
762 gross 927
763     #=================================================================================================================================
764 gross 899 class SurfaceLoop(Primitive):
765 gross 898 """
766     a surface loop. It defines the shell of a volume.
767    
768     The loop must represent a closed shell, and the L{Surface}s should be oriented consistently.
769     """
770     def __init__(self,*surfaces):
771     """
772     creates a surface loop
773     """
774     super(SurfaceLoop, self).__init__()
775 gross 899 self.__surfaces=[]
776     self.addSurface(*surfaces)
777     def addSurface(self,*surfaces):
778     for i in range(len(surfaces)):
779     if not surfaces[i].isSurface():
780     raise TypeError("%s-th argument is not a Surface object."%i)
781     self.__surfaces+=surfaces
782 gross 898
783 gross 899 def isSurfaceLoop(self):
784     return True
785 gross 898 def getSurfaces(self):
786     return self.__surfaces
787 gross 899 def __add__(self,other):
788     return SurfaceLoop([c+other for c in self.getSurfaces])
789 gross 898 def __len__(self):
790     return len(self.__surfaces)
791 gross 916 def getPrimitives(self):
792 gross 899 out=set([self])
793 gross 916 for i in self.getSurfaces(): out|=i.getPrimitives()
794 gross 899 return out
795 gross 916 def getConstructionPoints(self):
796 gross 902 out=set()
797 gross 916 for i in self.getSurfaces(): out|=i.getConstructionPoints()
798 gross 902 return out
799 gross 899 def getGmshCommand(self):
800     out=""
801     for i in self.getSurfaces():
802     if len(out)>0:
803     out+=", %s"%i.getID()
804     else:
805     out="%s"%i.getID()
806     return "Surface Loop(%s) = {%s};"%(self.getID(),out)
807 gross 898
808 gross 899 class Volume(Primitive):
809 gross 898 """
810     a volume with holes.
811     """
812     def __init__(self,loop,holes=[]):
813     """
814     creates a volume
815    
816     @param loop: L{SurfaceLoop} defining the boundary of the surface
817     @param holes: list of L{SurfaceLoop} defining holes in the surface.
818     @note: A SurfaceLoop defining a hole should not have any surfaces in common with the exterior SurfaceLoop.
819     A SurfaceLoop defining a hole should not have any surfaces in common with another SurfaceLoop defining a hole in the same volume.
820     """
821     super(Volume, self).__init__()
822 gross 899 if not loop.isSurfaceLoop():
823 gross 898 raise TypeError("argument loop needs to be a SurfaceLoop object.")
824     for i in range(len(holes)):
825 gross 899 if not holes[i].isSurfaceLoop():
826 gross 898 raise TypeError("%i th hole needs to be a SurfaceLoop object.")
827     self.__loop=loop
828     self.__holes=holes
829     def getHoles(self):
830     return self.__holes
831     def getSurfaceLoop(self):
832     return self.__loop
833 gross 899 def __add__(self,other):
834     return Volume(self.getSurfaceLoop()+other, holes=[h+other for h in self.getHoles()])
835 gross 916 def getPrimitives(self):
836     out=set([self]) | self.getSurfaceLoop().getPrimitives()
837     for i in self.getHoles(): out|=i.getPrimitives()
838 gross 899 return out
839 gross 916 def getConstructionPoints(self):
840     out=self.getSurfaceLoop().getConstructionPoints()
841 gross 902 for i in self.getHoles(): out|=i.Points()
842     return out
843 gross 899 def getGmshCommand(self):
844     out=""
845     for i in self.getHoles():
846     if len(out)>0:
847     out+=", %s"%i.getID()
848     else:
849     out="%s"%i.getID()
850     if len(out)>0:
851     return "Volume(%s) = {%s, %s};"%(self.getID(),self.getSurfaceLoop().getID(), out)
852     else:
853     return "Volume(%s) = {%s};"%(self.getID(),self.getSurfaceLoop().getID())
854 gross 898
855 gross 912 class ReversedPrimitive(object):
856     def __init__(self,prim):
857     self.__prim=prim
858     def __getattr__(self,name):
859     if name == "getID":
860     return self.getReverseID
861     else:
862     return getattr(self.__prim,name)
863     def getReverseID(self):
864     return -self.__prim.getID()
865    
866 gross 899 class PropertySet(Primitive):
867 gross 898 """
868 gross 899 defines a group L{Primitive} objects.
869 gross 898 """
870     def __init__(self,tag=None,*items):
871     super(PropertySet, self).__init__()
872     self.__items=items
873     self.__tag=tag
874 gross 916 def getPrimitives(self):
875     out=set([self, self.getBoundaryLoop().getPrimitives()])
876     for i in self.getHoles(): out|=i.getPrimitives()
877 gross 899 return out
878    
879     class PrimitiveStack(object):
880     def __init__(self,*items):
881     self.__prims=set()
882     for i in items:
883 gross 916 self.__prims|=i.getPrimitives()
884 gross 899 self.__prims=list(self.__prims)
885     self.__prims.sort()
886    
887     def getGmshCommands(self):
888     out=""
889     for i in self.__prims:
890     out+=i.getGmshCommand()+"\n"
891     return out

  ViewVC Help
Powered by ViewVC 1.1.26