/[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 930 - (hide annotations)
Thu Jan 18 08:12:58 2007 UTC (12 years, 6 months ago) by gross
File MIME type: text/x-python
File size: 45456 byte(s)
more tests and some modifications on SurfaceLoop
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 928
56     class PrimitiveBase(object):
57 gross 898 """
58 gross 929 template for a set of primitives
59 gross 898 """
60 gross 929 def __init__(self):
61 gross 898 """
62 gross 928 initializes PrimitiveBase instance object with id
63 gross 898 """
64 gross 929 pass
65 gross 915
66 gross 899 def __cmp__(self,other):
67 gross 928 """
68     compares object with other by comparing the absolute value of the ID
69     """
70 gross 929 if isinstance(other, PrimitiveBase):
71     return cmp(self.getID(),other.getID())
72 gross 928 else:
73     return False
74 gross 916 def getConstructionPoints(self):
75 gross 912 """
76 gross 916 returns the points used to construct the primitive
77 gross 912 """
78     out=set()
79 gross 916 for i in self.getPrimitives():
80 gross 912 if isinstance(i,Point): out.add(i)
81 gross 916 return list(out)
82 gross 912
83 gross 916 def getPrimitives(self):
84 gross 912 """
85 gross 928 returns a list of primitives used to construct the primitive with no double entries
86 gross 912 """
87 gross 928 out=set()
88 gross 929 return list(set([p for p in self.collectPrimitiveBases()]))
89 gross 912
90 gross 915 def copy(self):
91     """
92 gross 916 returns a deep copy of the object
93 gross 915 """
94 gross 925 return self.substitute({})
95 gross 912
96 gross 915 def modifyBy(self,transformation):
97 gross 916 """
98     modifies the coordinates by applying a transformation
99     """
100     for p in self.getConstructionPoints(): p.modifyBy(transformation)
101 gross 915
102     def __add__(self,other):
103     """
104     returns a new object shifted by other
105     """
106     return self.apply(Translation(numarray.array(other,_TYPE)))
107    
108     def __sub__(self,other):
109     """
110     returns a new object shifted by other
111     """
112     return self.apply(Translation(-numarray.array(other,_TYPE)))
113    
114     def __iadd__(self,other):
115     """
116     shifts the point by other
117     """
118     self.modifyBy(Translation(numarray.array(other,_TYPE)))
119     return self
120    
121     def __isub__(self,other):
122     """
123     shifts the point by -other
124     """
125     self.modifyBy(Translation(-numarray.array(other,_TYPE)))
126     return self
127    
128     def __imul__(self,other):
129     """
130     modifies object by applying L{Transformation} other. If other is not a L{Transformation} it will try convert it.
131     """
132     if isinstance(other,int) or isinstance(other,float):
133     trafo=Dilation(other)
134     elif isinstance(other,numarray.NumArray):
135     trafo=Translation(other)
136     elif isinstance(other,Transformation):
137     trafo=other
138     else:
139     raise TypeError, "cannot convert argument to Trnsformation class object."
140     self.modifyBy(trafo)
141     return self
142    
143     def __rmul__(self,other):
144     """
145     applies L{Transformation} other to object. If other is not a L{Transformation} it will try convert it.
146     """
147     if isinstance(other,int) or isinstance(other,float):
148     trafo=Dilation(other)
149     elif isinstance(other,numarray.NumArray):
150     trafo=Translation(other)
151     elif isinstance(other,Transformation):
152     trafo=other
153     else:
154 gross 916 raise TypeError, "cannot convert argument to Transformation class object."
155 gross 915 return self.apply(trafo)
156    
157    
158 gross 916 def setLocalScale(self,factor=1.):
159     """
160     sets the local refinement factor
161     """
162     for p in self.getConstructionPoints(): p.setLocalScale(factor)
163    
164     def apply(self,transformation):
165     """
166 gross 928 returns a new object by applying the transformation
167 gross 916 """
168 gross 925 out=self.copy()
169     out.modifyBy(transformation)
170     return out
171 gross 916
172 gross 929 class Primitive(object):
173     """
174     A general primitive
175     """
176     def __init__(self):
177     """
178     initializes PrimitiveBase instance object with id
179     """
180     global global_primitive_id_counter
181     self.__ID=global_primitive_id_counter
182     global_primitive_id_counter+=1
183    
184     def getID(self):
185     """
186     returns the primitive ID
187     """
188     return self.__ID
189    
190     def getDirectedID(self):
191 gross 928 """
192 gross 929 returns the primitive ID where a negative signs means that the reversed ordring is used.
193     """
194     return self.getID()
195    
196     def __repr__(self):
197     return "%s(%s)"%(self.__class__.__name__,self.getID())
198    
199     def getUnderlyingPrimitive(self):
200     """
201     returns the underlying primitive
202     """
203     return self
204 gross 930 def hasSameOrientation(self,other):
205     """
206     returns True if other is the same primitive and has the same orientation
207     """
208     return self == other and isinstance(other,Primitive)
209 gross 929
210     def __neg__(self):
211     """
212     returns a view onto the curve with reversed ordering
213    
214 gross 928 @note: this class is overwritten by subclass
215     """
216 gross 929 raise NotImplementedError("__neg__ is not implemented.")
217 gross 928
218     def getGmshCommand(self, local_scaling_factor=1.):
219     """
220     returns the Gmsh command(s) to create the primitive
221    
222     @note: this class is overwritten by subclass
223     """
224 gross 929 raise NotImplementedError("getGmshCommand is not implemented.")
225 gross 928
226 gross 925 def substitute(self,sub_dict):
227     """
228     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
229     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
230     with substituted arguments is returned.
231 gross 928
232     @note: this class is overwritten by subclass
233 gross 925 """
234 gross 929 raise NotImplementedError("substitute is not implemented.")
235 gross 925
236 gross 929 def collectPrimitiveBases(self):
237 gross 928 """
238 gross 929 returns a list of primitives used to construct the primitive. It may contain primitives twice
239    
240     @note: this class is overwritten by subclass
241 gross 928 """
242 gross 929 raise NotImplementedError("collectPrimitiveBases is not implemented.")
243 gross 928
244 gross 929 def isColocated(self,primitive):
245     """
246     returns True is the two primitives are located at the smae position
247    
248     @note: this class is overwritten by subclass
249     """
250     raise NotImplementedError("isColocated is not implemented.")
251    
252    
253     class ReversePrimitive(object):
254 gross 928 """
255     A view onto a primitive creating an reverse orientation
256     """
257     def __init__(self,primitive):
258     """
259     instantiate a view onto primitve
260     """
261 gross 929 if not isinstance(primitive, Primitive):
262     raise ValueError("argument needs to be a Primitive class object.")
263 gross 928 self.__primitive=primitive
264    
265 gross 929 def getID(self):
266     """
267     returns the primitive ID
268     """
269     return self.__primitive.getID()
270    
271 gross 928 def getUnderlyingPrimitive(self):
272     """
273     returns the underlying primitive
274     """
275     return self.__primitive
276    
277 gross 930 def hasSameOrientation(self,other):
278     """
279     returns True if other is the same primitive and has the same orientation
280     """
281     return self == other and isinstance(other,ReversePrimitive)
282    
283 gross 929 def __repr__(self):
284     return "-%s(%s)"%(self.__primitive.__class__.__name__,self.getID())
285    
286     def getDirectedID(self):
287 gross 928 """
288 gross 929 returns the primitive ID where a negative signs means that the reversed ordring is used.
289 gross 928 """
290 gross 929 return -self.__primitive.getID()
291 gross 928
292 gross 929 def substitute(self,sub_dict):
293     """
294     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
295     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
296     with substituted arguments is returned.
297     """
298     if not sub_dict.has_key(self):
299     sub_dict[self]=-self.getUnderlyingPrimitive().substitute(sub_dict)
300     return sub_dict[self]
301    
302     def __neg__(self):
303     """
304     returns a view onto the curve with reversed ordering
305     """
306     return self.__primitive
307    
308     def getGmshCommand(self, local_scaling_factor=1.):
309     """
310     returns the Gmsh command(s) to create the primitive
311     """
312     return self.__primitive.getGmshCommand(local_scaling_factor)
313    
314     def collectPrimitiveBases(self):
315     """
316     returns a list of primitives used to construct the primitive. It may contain primitives twice
317     """
318     return self.__primitive.collectPrimitiveBases()
319    
320     def isColocated(self,primitive):
321     """
322     returns True is the two primitives are located at the smae position
323    
324     @note: this class is overwritten by subclass
325     """
326     return self.__primitive.isColocated(primitive)
327    
328     class Point(Primitive, PrimitiveBase):
329 gross 898 """
330     a three dimensional point
331     """
332     def __init__(self,x=0.,y=0.,z=0.,local_scale=1.):
333     """
334 gross 912 creates a point with coorinates x,y,z with the local refinement factor local_scale
335 gross 898 """
336 gross 929 PrimitiveBase.__init__(self)
337 gross 928 Primitive.__init__(self)
338 gross 915 self.setCoordinates(numarray.array([x,y,z],_TYPE))
339 gross 899 self.setLocalScale(local_scale)
340 gross 915
341 gross 898 def setLocalScale(self,factor=1.):
342 gross 902 """
343 gross 912 sets the local refinement factor
344 gross 902 """
345 gross 912 if factor<=0.:
346     raise ValueError("scaling factor must be positive.")
347 gross 898 self.__local_scale=factor
348 gross 929
349 gross 902 def getLocalScale(self):
350 gross 912 """
351     returns the local refinement factor
352     """
353 gross 902 return self.__local_scale
354 gross 912 def getCoordinates(self):
355     """
356     returns the coodinates of the point as L{numarray.NumArray} object
357     """
358     return self._x
359 gross 915 def setCoordinates(self,x):
360 gross 912 """
361     returns the coodinates of the point as L{numarray.NumArray} object
362     """
363 gross 915 if not isinstance(x, numarray.NumArray):
364     self._x=numarray.array(x,_TYPE)
365     else:
366     self._x=x
367    
368 gross 929 def collectPrimitiveBases(self):
369 gross 912 """
370 gross 916 returns primitives used to construct the primitive
371 gross 912 """
372 gross 916 return [self]
373 gross 912
374 gross 916 def isColocated(self,primitive):
375 gross 912 """
376 gross 916 returns True if L{Point} primitive is colocation (same coordinates)
377     that means if |self-primitive| <= tol * max(|self|,|primitive|)
378 gross 912 """
379 gross 916 if isinstance(primitive,Point):
380     primitive=primitive.getCoordinates()
381     c=self.getCoordinates()
382     d=c-primitive
383     return numarray.dot(d,d)<=getToleranceForColocation()**2*max(numarray.dot(c,c),numarray.dot(primitive,primitive))
384     else:
385     return False
386 gross 912
387 gross 925 def substitute(self,sub_dict):
388     """
389     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
390     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
391     with substituted arguments is returned.
392     """
393     if not sub_dict.has_key(self):
394     c=self.getCoordinates()
395     sub_dict[self]=Point(c[0],c[1],c[2],local_scale=self.getLocalScale())
396     return sub_dict[self]
397 gross 915
398     def modifyBy(self,transformation):
399     """
400     modifies the coordinates by applying a transformation
401     """
402     self.setCoordinates(transformation(self.getCoordinates()))
403    
404    
405     def getGmshCommand(self, local_scaling_factor=1.):
406 gross 916 """
407     returns the Gmsh command(s) to create the primitive
408     """
409 gross 899 c=self.getCoordinates()
410 gross 915 return "Point(%s) = {%s , %s, %s , %s };"%(self.getID(),c[0],c[1],c[2], self.getLocalScale()*local_scaling_factor)
411 gross 898
412 gross 928 def __neg__(self):
413     """
414     returns a view of the object with reverse orientiention. As a point has no direction the object itself is returned.
415     """
416     return self
417    
418     class Manifold1D(PrimitiveBase):
419 gross 916 """
420 gross 928 general one-dimensional minifold in 3D defined by a start and end point.
421 gross 916 """
422 gross 928 def __init__(self):
423     """
424     create a one-dimensional manifold
425     """
426 gross 929 PrimitiveBase.__init__(self)
427 gross 928
428     def getStartPoint(self):
429     """
430     returns start point
431     """
432     raise NotImplementedError()
433    
434     def getEndPoint(self):
435     """
436     returns end point
437     """
438     raise NotImplementedError()
439    
440     class CurveBase(Manifold1D):
441 gross 929 """
442     A Curve is defined by a set of control points
443     """
444 gross 928 def __init__(self):
445 gross 916 """
446 gross 929 create curve
447 gross 916 """
448 gross 928 Manifold1D.__init__(self)
449 gross 916
450     def __len__(self):
451     """
452     returns the number of control points
453     """
454 gross 928 return len(self.getControlPoints())
455 gross 916
456     def getStartPoint(self):
457 gross 898 """
458     returns start point
459     """
460 gross 929 return self.getControlPoints()[0]
461 gross 898
462 gross 916 def getEndPoint(self):
463 gross 898 """
464     returns end point
465     """
466 gross 929 return self.getControlPoints()[-1]
467 gross 898
468 gross 929 def getControlPoints(self):
469     """
470     returns a list of the points
471     """
472     raise NotImplementedError()
473    
474     class Curve(CurveBase, Primitive):
475     """
476     a curve defined through a list of control points.
477     """
478     def __init__(self,*points):
479 gross 916 """
480 gross 929 defines a curve form control points
481 gross 916 """
482 gross 929 if len(points)<2:
483     raise TypeError("Curve needs at least two points")
484     i=0
485     for p in points:
486     i+=1
487     if not isinstance(p,Point): raise TypeError("%s-th argument is not a Point object."%i)
488     self.__points=points
489     CurveBase.__init__(self)
490     Primitive.__init__(self)
491 gross 916
492 gross 929 def getControlPoints(self):
493     """
494     returns a list of the points
495     """
496     return self.__points
497    
498     def __neg__(self):
499     """
500     returns a view onto the curve with reversed ordering
501     """
502     return ReverseCurve(self)
503    
504 gross 925 def substitute(self,sub_dict):
505 gross 916 """
506 gross 925 returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
507     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
508     with substituted arguments is returned.
509 gross 916 """
510 gross 925 if not sub_dict.has_key(self):
511     new_p=[]
512     for p in self.getControlPoints(): new_p.append(p.substitute(sub_dict))
513 gross 929 sub_dict[self]=self.__class__(*tuple(new_p))
514 gross 925 return sub_dict[self]
515 gross 916
516 gross 929 def collectPrimitiveBases(self):
517     """
518     returns primitives used to construct the Curve
519     """
520     out=[self]
521     for p in self.getControlPoints(): out+=p.collectPrimitiveBases()
522     return out
523    
524 gross 916 def isColocated(self,primitive):
525     """
526     returns True curves are on the same position
527     """
528 gross 930 if hasattr(primitive,"getUnderlyingPrimitive"):
529     if isinstance(primitive.getUnderlyingPrimitive(),self.__class__):
530     if len(primitive) == len(self):
531 gross 916 cp0=self.getControlPoints()
532     cp1=primitive.getControlPoints()
533 gross 919 match=True
534 gross 916 for i in range(len(cp0)):
535     if not cp0[i].isColocated(cp1[i]):
536 gross 919 match=False
537     break
538     if not match:
539     for i in range(len(cp0)):
540     if not cp0[i].isColocated(cp1[len(cp0)-1-i]):
541     return False
542 gross 916 return True
543 gross 930 return False
544 gross 916
545 gross 929 class ReverseCurve(CurveBase, ReversePrimitive):
546 gross 928 """
547     a curve defined through a list of control points.
548     """
549     def __init__(self,curve):
550     """
551     defines a curve form control points
552     """
553 gross 929 if not isinstance(curve, Curve):
554     raise TypeError("ReverseCurve needs to be an instance of Curve")
555 gross 928 CurveBase.__init__(self)
556 gross 929 ReversePrimitive.__init__(self,curve)
557 gross 928
558     def getControlPoints(self):
559     """
560     returns a list of the points
561     """
562 gross 929 out=[p for p in self.getUnderlyingPrimitive().getControlPoints()]
563 gross 928 out.reverse()
564     return out
565    
566 gross 916 class Spline(Curve):
567     """
568     a spline curve defined through a list of control points.
569     """
570 gross 929 def getGmshCommand(self,scaling_factor=1.):
571 gross 916 """
572     returns the Gmsh command(s) to create the Curve
573     """
574 gross 899 out=""
575 gross 916 for i in self.getControlPoints():
576 gross 899 if len(out)>0:
577 gross 929 out+=", %s"%i.getDirectedID()
578 gross 899 else:
579 gross 929 out="%s"%i.getDirectedID()
580 gross 899 return "Spline(%s) = {%s};"%(self.getID(),out)
581 gross 916
582 gross 898
583     class BezierCurve(Curve):
584     """
585     a Bezier curve
586     """
587 gross 929 def getGmshCommand(self,scaling_factor=1.):
588 gross 916 """
589     returns the Gmsh command(s) to create the Curve
590     """
591 gross 899 out=""
592 gross 916 for i in self.getControlPoints():
593 gross 899 if len(out)>0:
594 gross 929 out+=", %s"%i.getDirectedID()
595 gross 899 else:
596 gross 929 out="%s"%i.getDirectedID()
597 gross 899 return "Bezier(%s) = {%s};"%(self.getID(),out)
598 gross 898
599 gross 916 class BSpline(Curve):
600 gross 898 """
601     a BSpline curve. Control points may be repeated.
602     """
603 gross 929 def getGmshCommand(self,scaling_factor=1.):
604 gross 916 """
605     returns the Gmsh command(s) to create the Curve
606     """
607 gross 899 out=""
608 gross 916 for i in self.getControlPoints():
609 gross 899 if len(out)>0:
610 gross 929 out+=", %s"%i.getDirectedID()
611 gross 899 else:
612 gross 929 out="%s"%i.getDirectedID()
613 gross 899 return "BSpline(%s) = {%s};"%(self.getID(),out)
614 gross 898
615     class Line(Curve):
616     """
617 gross 929 a line is defined by two pointDirecteds
618 gross 898 """
619 gross 916 def __init__(self,*points):
620 gross 899 """
621 gross 916 defines a line with start and end point
622 gross 899 """
623 gross 916 if len(points)!=2:
624     raise TypeError("Line needs two points")
625 gross 929 Curve.__init__(self,*points)
626     def getGmshCommand(self,scaling_factor=1.):
627 gross 916 """
628     returns the Gmsh command(s) to create the Curve
629     """
630 gross 929 return "Line(%s) = {%s, %s};"%(self.getID(),self.getStartPoint().getDirectedID(),self.getEndPoint().getDirectedID())
631 gross 898
632 gross 916
633 gross 928 class ArcBase(Manifold1D):
634 gross 929 def __init__(self):
635     """
636     create curve
637     """
638     Manifold1D.__init__(self)
639     def collectPrimitiveBases(self):
640 gross 928 """
641     returns the primitives used to construct the Curve
642     """
643     out=[self]
644 gross 929 out+=self.getStartPoint().collectPrimitiveBases()
645     out+=self.getEndPoint().collectPrimitiveBases()
646     out+=self.getCenterPoint().collectPrimitiveBases()
647 gross 928 return out
648    
649    
650 gross 929 def getCenterPoint(self):
651     """
652     returns center
653     """
654     raise NotImplementedError()
655 gross 928
656 gross 929 class Arc(ArcBase, Primitive):
657 gross 898 """
658 gross 917 defines an arc which is strictly, smaller than Pi
659 gross 898 """
660     def __init__(self,center,start,end):
661     """
662     creates an arc by the start point, end point and center
663     """
664 gross 917 if not isinstance(center,Point): raise TypeError("center needs to be a Point object.")
665     if not isinstance(end,Point): raise TypeError("end needs to be a Point object.")
666     if not isinstance(start,Point): raise TypeError("start needs to be a Point object.")
667     # TODO: check length of circle.
668 gross 928 ArcBase.__init__(self)
669 gross 929 Primitive.__init__(self)
670 gross 898 self.__center=center
671 gross 916 self.__start=start
672     self.__end=end
673 gross 928 def __neg__(self):
674 gross 929 """
675     returns a view onto the curve with reversed ordering
676     """
677     return ReverseArc(self)
678 gross 898
679 gross 916 def getStartPoint(self):
680 gross 898 """
681 gross 916 returns start point
682     """
683     return self.__start
684    
685     def getEndPoint(self):
686     """
687     returns end point
688     """
689     return self.__end
690    
691     def getCenterPoint(self):
692     """
693 gross 898 returns center
694     """
695     return self.__center
696    
697 gross 929 def substitute(self,sub_dict):
698     """
699     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
700     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
701     with substituted arguments is returned.
702     """
703     if not sub_dict.has_key(self):
704     sub_dict[self]=Arc(self.getCenterPoint().substitute(sub_dict),self.getStartPoint().substitute(sub_dict),self.getEndPoint().substitute(sub_dict))
705     return sub_dict[self]
706    
707     def getGmshCommand(self,scaling_factor=1.):
708     """
709     returns the Gmsh command(s) to create the primitive
710     """
711     return "Circle(%s) = {%s, %s, %s};"%(self.getID(),self.getStartPoint().getDirectedID(),self.getCenterPoint().getDirectedID(),self.getEndPoint().getDirectedID())
712    
713     def isColocated(self,primitive):
714     """
715     returns True curves are on the same position
716     """
717 gross 930 if hasattr(primitive,"getUnderlyingPrimitive"):
718     if isinstance(primitive.getUnderlyingPrimitive(),Arc):
719 gross 929 return (self.getCenterPoint().isColocated(primitive.getCenterPoint())) and ( \
720     (self.getEndPoint().isColocated(primitive.getEndPoint()) and self.getStartPoint().isColocated(primitive.getStartPoint()) ) \
721     or (self.getEndPoint().isColocated(primitive.getStartPoint()) and self.getStartPoint().isColocated(primitive.getEndPoint()) ) )
722 gross 930 return False
723 gross 929
724     class ReverseArc(ArcBase, ReversePrimitive):
725 gross 928 """
726     defines an arc which is strictly, smaller than Pi
727     """
728     def __init__(self,arc):
729 gross 916 """
730 gross 928 creates an arc by the start point, end point and center
731 gross 916 """
732 gross 929 if not isinstance(arc, Arc):
733     raise TypeError("ReverseCurve needs to be an instance of Arc")
734 gross 928 ArcBase.__init__(self)
735 gross 929 ReversePrimitive.__init__(self,arc)
736 gross 916
737 gross 928 def getStartPoint(self):
738 gross 916 """
739 gross 928 returns start point
740 gross 916 """
741 gross 929 return self.getUnderlyingPrimitive().getEndPoint()
742 gross 899
743 gross 928 def getEndPoint(self):
744     """
745     returns end point
746     """
747 gross 929 return self.getUnderlyingPrimitive().getStartPoint()
748 gross 916
749 gross 928 def getCenterPoint(self):
750 gross 916 """
751 gross 928 returns center
752 gross 916 """
753 gross 929 return self.getUnderlyingPrimitive().getCenterPoint()
754 gross 916
755 gross 929 class CurveLoop(Primitive, PrimitiveBase):
756 gross 898 """
757 gross 930 An oriented loop of one-dimensional manifolds (= curves and arcs)
758 gross 898
759 gross 928 The loop must be closed and the L{Manifold1D}s should be oriented consistently.
760 gross 898 """
761     def __init__(self,*curves):
762     """
763     creates a polygon from a list of line curves. The curves must form a closed loop.
764     """
765 gross 923 if len(curves)<2:
766     raise TypeError("at least two curves have to be given.")
767 gross 899 for i in range(len(curves)):
768 gross 928 if not isinstance(curves[i],Manifold1D):
769     raise TypeError("%s-th argument is not a Manifold1D object."%i)
770 gross 923 # for the curves a loop:
771     used=[ False for i in curves]
772     self.__curves=[curves[0]]
773     used[0]=True
774     while not min(used):
775     found=False
776     for i in xrange(len(curves)):
777     if not used[i]:
778     if self.__curves[-1].getEndPoint() == curves[i].getStartPoint():
779     self.__curves.append(curves[i])
780     used[i]=True
781     found=True
782     break
783     if not found:
784     raise ValueError("loop is not closed.")
785     if not self.__curves[0].getStartPoint() == self.__curves[-1].getEndPoint():
786     raise ValueError("loop is not closed.")
787 gross 930 Primitive.__init__(self)
788     PrimitiveBase.__init__(self)
789 gross 898
790     def getCurves(self):
791 gross 919 """
792     returns the curves defining the CurveLoop
793     """
794 gross 898 return self.__curves
795 gross 925
796 gross 929 def __neg__(self):
797     """
798     returns a view onto the curve with reversed ordering
799     """
800     return ReverseCurveLoop(self)
801    
802 gross 898 def __len__(self):
803 gross 919 """
804     return the number of curves in the CurveLoop
805     """
806 gross 928 return len(self.getCurves())
807 gross 919
808 gross 929
809     def collectPrimitiveBases(self):
810 gross 919 """
811     returns primitives used to construct the CurveLoop
812     """
813 gross 928 out=[self]
814 gross 929 for c in self.getCurves(): out+=c.collectPrimitiveBases()
815 gross 928 return out
816 gross 919
817 gross 925 def substitute(self,sub_dict):
818 gross 919 """
819 gross 925 returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
820     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
821     with substituted arguments is returned.
822 gross 919 """
823 gross 925 if not sub_dict.has_key(self):
824     new_c=[]
825     for c in self.getCurves(): new_c.append(c.substitute(sub_dict))
826     sub_dict[self]=CurveLoop(*tuple(new_c))
827     return sub_dict[self]
828 gross 919
829     def isColocated(self,primitive):
830     """
831     returns True if each curve is collocted with a curve in primitive
832     """
833 gross 930 if hasattr(primitive,"getUnderlyingPrimitive"):
834     if isinstance(primitive.getUnderlyingPrimitive(),CurveLoop):
835     if len(primitive) == len(self):
836     cp0=self.getCurves()
837     cp1=primitive.getCurves()
838     for c0 in cp0:
839     collocated = False
840     for c1 in cp1:
841     collocated = collocated or c0.isColocated(c1)
842     if not collocated: return False
843     return True
844     return False
845 gross 919
846 gross 929 def getGmshCommand(self,scaling_factor=1.):
847 gross 928 """
848     returns the Gmsh command(s) to create the primitive
849     """
850 gross 899 out=""
851     for i in self.getCurves():
852     if len(out)>0:
853 gross 929 out+=", %s"%i.getDirectedID()
854 gross 899 else:
855 gross 929 out="%s"%i.getDirectedID()
856 gross 899 return "Line Loop(%s) = {%s};"%(self.getID(),out)
857 gross 898
858 gross 929 class ReverseCurveLoop(ReversePrimitive, PrimitiveBase):
859 gross 898 """
860 gross 930 An oriented loop of one-dimensional manifolds (= curves and arcs)
861 gross 929
862 gross 930 The loop must be closed and the one-dimensional manifolds should be oriented consistently.
863 gross 929 """
864     def __init__(self,curve_loop):
865     """
866     creates a polygon from a list of line curves. The curves must form a closed loop.
867     """
868     if not isinstance(curve_loop, CurveLoop):
869     raise ValueError("arguments need to be an instance of CurveLoop.")
870     ReversePrimitive.__init__(self, curve_loop)
871     PrimitiveBase.__init__(self)
872    
873     def getCurves(self):
874     """
875     returns the curves defining the CurveLoop
876     """
877     return [ -c for c in self.getUnderlyingPrimitive().getCurves() ]
878    
879     def __len__(self):
880     return len(self.getUnderlyingPrimitive())
881    
882 gross 930 #=
883     class Manifold2D(PrimitiveBase):
884 gross 929 """
885 gross 930 general two-dimensional manifold
886 gross 898 """
887 gross 928 def __init__(self):
888     """
889 gross 930 create a two-dimensional manifold
890 gross 928 """
891 gross 930 PrimitiveBase.__init__(self)
892 gross 928
893 gross 930 def getBoundary(self):
894 gross 928 """
895 gross 930 returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
896 gross 928 """
897 gross 930 raise NotImplementedError()
898 gross 928
899 gross 930 class RuledSurface(Primitive, Manifold2D):
900 gross 927 """
901     A ruled surface, i.e., a surface that can be interpolated using transfinite interpolation
902     """
903 gross 898 def __init__(self,loop):
904     """
905 gross 927 creates a ruled surface with boundary loop
906 gross 898
907 gross 927 @param loop: L{CurveLoop} defining the boundary of the surface.
908 gross 898 """
909 gross 930 if not isinstance(loop.getUnderlyingPrimitive(),CurveLoop):
910 gross 898 raise TypeError("argument loop needs to be a CurveLoop object.")
911 gross 927 if len(loop)<2:
912     raise TypeError("the loop must contain at least two Curves.")
913     if len(loop)>4:
914     raise TypeError("the loop must contain at least three Curves.")
915 gross 930 Primitive.__init__(self)
916     Manifold2D.__init__(self)
917 gross 898 self.__loop=loop
918 gross 927
919 gross 930 def __neg__(self):
920     """
921     returns a view onto the suface with reversed ordering
922     """
923     return ReverseRuledSurface(self)
924    
925 gross 898 def getBoundaryLoop(self):
926 gross 927 """
927 gross 928 returns the loop defining the outer boundary
928 gross 927 """
929     return self.__loop
930    
931 gross 930 def getBoundary(self):
932 gross 928 """
933 gross 930 returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
934 gross 928 """
935 gross 930 return self.getBoundaryLoop().getCurves()
936 gross 927
937 gross 929 def getGmshCommand(self,scaling_factor=1.):
938 gross 928 """
939     returns the Gmsh command(s) to create the primitive
940     """
941 gross 929 return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getDirectedID())
942 gross 899
943 gross 927 def substitute(self,sub_dict):
944     """
945     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
946     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
947     with substituted arguments is returned.
948     """
949     if not sub_dict.has_key(self):
950 gross 928 sub_dict[self]=RuledSurface(self.getBoundaryLoop().substitute(sub_dict))
951 gross 927 return sub_dict[self]
952    
953     def isColocated(self,primitive):
954     """
955     returns True if each curve is collocted with a curve in primitive
956     """
957 gross 930 if hasattr(primitive,"getUnderlyingPrimitive"):
958     if isinstance(primitive.getUnderlyingPrimitive(),RuledSurface):
959     return self.getBoundaryLoop().isColocated(primitive.getBoundaryLoop())
960     return False
961 gross 927
962 gross 930 def collectPrimitiveBases(self):
963     """
964     returns primitives used to construct the Surface
965     """
966     return [self] + self.getBoundaryLoop().collectPrimitiveBases()
967    
968 gross 927 def createRuledSurface(*curves):
969     """
970     an easier way to create a L{RuledSurface} from given curves.
971     """
972     return RuledSurface(CurveLoop(*curves))
973    
974 gross 930
975     class ReverseRuledSurface(ReversePrimitive, Manifold2D):
976 gross 898 """
977 gross 930 creates a view onto a L{RuledSurface} but with the reverse orientation
978     """
979     def __init__(self,surface):
980     """
981     creates a polygon from a list of line curves. The curves must form a closed loop.
982     """
983     if not isinstance(surface, RuledSurface):
984     raise ValueError("arguments need to be an instance of CurveLoop.")
985     ReversePrimitive.__init__(self, surface)
986     Manifold2D.__init__(self)
987    
988     def getBoundaryLoop(self):
989     """
990     returns the CurveLoop defining the RuledSurface
991     """
992     return -self.getUnderlyingPrimitive().getBoundaryLoop()
993    
994     def getBoundary(self):
995     """
996     returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
997     """
998     return self.getBoundaryLoop().getCurves()
999     #==============================
1000     class PlaneSurface(Primitive, Manifold2D):
1001     """
1002 gross 898 a plane surface with holes
1003     """
1004     def __init__(self,loop,holes=[]):
1005     """
1006 gross 927 creates a plane surface with a hole
1007 gross 898
1008     @param loop: L{CurveLoop} defining the boundary of the surface
1009     @param holes: list of L{CurveLoop} defining holes in the surface.
1010     @note: A CurveLoop defining a hole should not have any lines in common with the exterior CurveLoop.
1011     A CurveLoop defining a hole should not have any lines in common with another CurveLoop defining a hole in the same surface.
1012     """
1013 gross 930 if not isinstance(loop.getUnderlyingPrimitive(),CurveLoop):
1014 gross 927 raise TypeError("argument loop needs to be a CurveLoop object.")
1015 gross 928 for l in loop.getCurves():
1016 gross 930 if not isinstance(l.getUnderlyingPrimitive(),Line):
1017 gross 928 raise TypeError("loop may be formed by Lines only.")
1018 gross 898 for i in range(len(holes)):
1019 gross 930 if not isinstance(holes[i].getUnderlyingPrimitive(), CurveLoop):
1020 gross 928 raise TypeError("%i-th hole needs to be a CurveLoop object.")
1021     for l in holes[i].getCurves():
1022 gross 930 if not isinstance(l.getUnderlyingPrimitive(),Line):
1023 gross 928 raise TypeError("holes may be formed by Lines only.")
1024     #TODO: check if lines and holes are in a plane
1025     #TODO: are holes really holes?
1026 gross 930 Primitive.__init__(self)
1027     Manifold2D.__init__(self)
1028 gross 928 self.__loop=loop
1029 gross 898 self.__holes=holes
1030     def getHoles(self):
1031 gross 927 """
1032     returns the holes
1033     """
1034 gross 898 return self.__holes
1035 gross 930
1036 gross 927 def getBoundaryLoop(self):
1037     """
1038     returns the loop defining the boundary
1039     """
1040     return self.__loop
1041    
1042 gross 929 def getGmshCommand(self,scaling_factor=1.):
1043 gross 928 """
1044     returns the Gmsh command(s) to create the primitive
1045     """
1046 gross 899 out=""
1047     for i in self.getHoles():
1048     if len(out)>0:
1049 gross 929 out+=", %s"%i.getDirectedID()
1050 gross 899 else:
1051 gross 929 out="%s"%i.getDirectedID()
1052 gross 899 if len(out)>0:
1053 gross 929 return "Plane Surface(%s) = {%s, %s};"%(self.getID(),self.getBoundaryLoop().getDirectedID(), out)
1054 gross 899 else:
1055 gross 929 return "Plane Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getDirectedID())
1056 gross 898
1057 gross 927 def substitute(self,sub_dict):
1058     """
1059     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
1060     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
1061     with substituted arguments is returned.
1062     """
1063     if not sub_dict.has_key(self):
1064 gross 928 sub_dict[self]=PlaneSurface(self.getBoundaryLoop().substitute(sub_dict),[ h.substitute(sub_dict) for h in self.getHoles()])
1065 gross 927 return sub_dict[self]
1066 gross 898
1067 gross 927 def isColocated(self,primitive):
1068 gross 898 """
1069 gross 927 returns True if each curve is collocted with a curve in primitive
1070     """
1071 gross 930 if hasattr(primitive,"getUnderlyingPrimitive"):
1072     if isinstance(primitive.getUnderlyingPrimitive(),PlaneSurface):
1073     if self.getBoundaryLoop().isColocated(primitive.getBoundaryLoop()):
1074     hs0=self.getHoles()
1075     hs1=primitive.getHoles()
1076     if len(hs0) == len(hs1):
1077     for h0 in hs0:
1078     collocated = False
1079     for h1 in hs1:
1080     collocated = collocated or h0.isColocated(h1)
1081     if not collocated: return False
1082     return True
1083     return False
1084     def collectPrimitiveBases(self):
1085     """
1086     returns primitives used to construct the Surface
1087     """
1088     out=[self] + self.getBoundaryLoop().collectPrimitiveBases()
1089     for i in self.getHoles(): out+=i.collectPrimitiveBases()
1090     return out
1091     def __neg__(self):
1092     """
1093     returns a view onto the curve with reversed ordering
1094     """
1095     return ReversePlaneSurface(self)
1096     def getBoundary(self):
1097     """
1098     returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
1099     """
1100     out = []+ self.getBoundaryLoop().getCurves()
1101     for h in self.getHoles(): out+=h.getCurves()
1102     return out
1103 gross 898
1104 gross 930 class ReversePlaneSurface(ReversePrimitive, Manifold2D):
1105 gross 898 """
1106 gross 930 creates a view onto a L{PlaneSurface} but with the reverse orientation
1107     """
1108     def __init__(self,surface):
1109     """
1110     creates a polygon from a list of line curves. The curves must form a closed loop.
1111     """
1112     if not isinstance(surface, PlaneSurface):
1113     raise ValueError("arguments need to be an instance of PlaneSurface.")
1114     ReversePrimitive.__init__(self, surface)
1115     Manifold2D.__init__(self)
1116    
1117     def getBoundaryLoop(self):
1118     """
1119     returns the CurveLoop defining the RuledSurface
1120     """
1121     return -self.getUnderlyingPrimitive().getBoundaryLoop()
1122    
1123     def getHoles(self):
1124     """
1125     returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
1126     """
1127     return [ -h for h in self.getUnderlyingPrimitive().getHoles() ]
1128    
1129     def getBoundary(self):
1130     """
1131     returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
1132     """
1133     out = [] + self.getBoundaryLoop().getCurves()
1134     for h in self.getHoles(): out+=h.getCurves()
1135     return out
1136    
1137    
1138     #=========================================================================
1139     class SurfaceLoop(Primitive, PrimitiveBase):
1140     """
1141 gross 928 a loop of 2D primitives. It defines the shell of a volume.
1142 gross 898
1143 gross 928 The loop must represent a closed shell, and the primitives should be oriented consistently.
1144 gross 898 """
1145     def __init__(self,*surfaces):
1146     """
1147     creates a surface loop
1148     """
1149 gross 928 if len(surfaces)<2:
1150     raise TypeError("at least two surfaces have to be given.")
1151 gross 899 for i in range(len(surfaces)):
1152 gross 930 if not isinstance(surfaces[i].getUnderlyingPrimitive(),Manifold2D):
1153     raise TypeError("%s-th argument is not a Manifold2D object."%i)
1154     Primitive.__init__(self)
1155     PrimitiveBase.__init__(self)
1156 gross 928 # for the curves a loop:
1157 gross 930 used=[ False for s in surfaces]
1158 gross 928 self.__surfaces=[surfaces[0]]
1159 gross 930 used[0]= True
1160     edges=[ e for e in surfaces[0].getBoundary() ]
1161     used_edges=[ False for e in surfaces[0].getBoundary() ]
1162     while not min(used):
1163 gross 928 found=False
1164     for i in xrange(len(surfaces)):
1165     if not used[i]:
1166     i_boundary=surfaces[i].getBoundary()
1167 gross 930 print i, i_boundary
1168     for ib in xrange(len(i_boundary)):
1169     print ib, i_boundary[ib], edges
1170 gross 928 if i_boundary[ib] in edges:
1171     if used_edges[edges.index(i_boundary[ib])]:
1172 gross 930 raise ValueError("boundary segment %s is shared by more than one surface."%str(i_boundary[ib]))
1173 gross 928 used_edges[edges.index(i_boundary[ib])]=True
1174     self.__surfaces.append(surfaces[i])
1175     for b in i_boundary:
1176     if not b in edges:
1177     edges.append(b)
1178     used_edges.append(False)
1179     found=True
1180     used[i]=True
1181     break
1182     if found: break
1183     if not found:
1184     raise ValueError("loop is not closed.")
1185 gross 930 print min(used_edges), used_edges
1186 gross 928 if min(used_edges):
1187     raise ValueError("loop is not closed. Surface is missing.")
1188     def __len__(self):
1189     """
1190     return the number of curves in the SurfaceLoop
1191     """
1192     return len(self.__surfaces)
1193 gross 898
1194 gross 930 def __neg__(self):
1195     """
1196     returns a view onto the curve with reversed ordering
1197     """
1198     return ReverseSurfaceLoop(self)
1199    
1200 gross 898 def getSurfaces(self):
1201 gross 928 """
1202     returns the surfaces defining the SurfaceLoop
1203     """
1204 gross 930 return self.__surfaces
1205 gross 928
1206 gross 929 def collectPrimitiveBases(self):
1207 gross 928 """
1208     returns primitives used to construct the SurfaceLoop
1209     """
1210     out=[self]
1211 gross 929 for c in self.getSurfaces(): out+=c.collectPrimitiveBases()
1212 gross 928 return out
1213 gross 930
1214 gross 929 def getGmshCommand(self,scaling_factor=1.):
1215 gross 928 """
1216     returns the Gmsh command(s) to create the primitive
1217     """
1218 gross 899 out=""
1219     for i in self.getSurfaces():
1220     if len(out)>0:
1221 gross 929 out+=", %s"%i.getDirectedID()
1222 gross 899 else:
1223 gross 929 out="%s"%i.getDirectedID()
1224 gross 899 return "Surface Loop(%s) = {%s};"%(self.getID(),out)
1225 gross 928 def substitute(self,sub_dict):
1226     """
1227     returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
1228     If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
1229     with substituted arguments is returned.
1230     """
1231     if not sub_dict.has_key(self):
1232     new_s=[]
1233     for s in self.getCurves(): new_s.append(s.substitute(sub_dict))
1234     sub_dict[self]=SurfaceLoop(*tuple(new_s))
1235     return sub_dict[self]
1236 gross 898
1237 gross 928 def isColocated(self,primitive):
1238     """
1239     returns True if each surface is collocted with a curve in primitive and vice versa.
1240     """
1241 gross 930 if hasattr(primitive,"getUnderlyingPrimitive"):
1242     if isinstance(primitive.getUnderlyingPrimitive(),SurfaceLoop):
1243     if len(primitive) == len(self):
1244     sp0=self.getSurfaces()
1245     sp1=primitive.getCurves()
1246     for s0 in sp0:
1247     collocated = False
1248     for s1 in sp1:
1249     collocated = collocated or s0.isColocated(s1)
1250     if not collocated: return False
1251     return True
1252     return False
1253 gross 928
1254 gross 930 class ReverseSurfaceLoop(ReversePrimitive, PrimitiveBase):
1255     """
1256     a view to SurfaceLoop with reverse orientaion
1257    
1258     The loop must represent a closed shell, and the primitives should be oriented consistently.
1259     An oriented loop of 2-dimensional manifolds (= RuledSurface, PlaneSurface)
1260    
1261     The loop must be closed and the one-dimensional manifolds should be oriented consistently.
1262     """
1263     def __init__(self,surface_loop):
1264     """
1265     creates a polygon from a list of line surfaces. The curves must form a closed loop.
1266     """
1267     if not isinstance(surface_loop, SurfaceLoop):
1268     raise ValueError("arguments need to be an instance of SurfaceLoop.")
1269     ReversePrimitive.__init__(self, surface_loop)
1270     PrimitiveBase.__init__(self)
1271    
1272     def getSurfaces(self):
1273     """
1274     returns the surfaces defining the SurfaceLoop
1275     """
1276     return [ -s for s in self.getUnderlyingPrimitive().getSurfaces() ]
1277    
1278     def __len__(self):
1279     return len(self.getUnderlyingPrimitive())
1280 gross 928 #==========================
1281 gross 929 class Volume(PrimitiveBase):
1282 gross 898 """
1283     a volume with holes.
1284     """
1285     def __init__(self,loop,holes=[]):
1286     """
1287     creates a volume
1288    
1289     @param loop: L{SurfaceLoop} defining the boundary of the surface
1290     @param holes: list of L{SurfaceLoop} defining holes in the surface.
1291     @note: A SurfaceLoop defining a hole should not have any surfaces in common with the exterior SurfaceLoop.
1292     A SurfaceLoop defining a hole should not have any surfaces in common with another SurfaceLoop defining a hole in the same volume.
1293     """
1294     super(Volume, self).__init__()
1295 gross 899 if not loop.isSurfaceLoop():
1296 gross 898 raise TypeError("argument loop needs to be a SurfaceLoop object.")
1297     for i in range(len(holes)):
1298 gross 899 if not holes[i].isSurfaceLoop():
1299 gross 898 raise TypeError("%i th hole needs to be a SurfaceLoop object.")
1300     self.__loop=loop
1301     self.__holes=holes
1302     def getHoles(self):
1303     return self.__holes
1304     def getSurfaceLoop(self):
1305     return self.__loop
1306 gross 899 def __add__(self,other):
1307     return Volume(self.getSurfaceLoop()+other, holes=[h+other for h in self.getHoles()])
1308 gross 929 def collectPrimitiveBases(self):
1309     out=[self] + self.getSurfaceLoop().collectPrimitiveBases()
1310     for i in self.getHoles(): out+=i.collectPrimitiveBases()
1311 gross 899 return out
1312 gross 916 def getConstructionPoints(self):
1313     out=self.getSurfaceLoop().getConstructionPoints()
1314 gross 902 for i in self.getHoles(): out|=i.Points()
1315     return out
1316 gross 929 def getGmshCommand(self,scaling_factor=1.):
1317 gross 928 """
1318     returns the Gmsh command(s) to create the primitive
1319     """
1320 gross 899 out=""
1321     for i in self.getHoles():
1322     if len(out)>0:
1323 gross 929 out+=", %s"%i.getDirectedID()
1324 gross 899 else:
1325 gross 929 out="%s"%i.getDirectedID()
1326 gross 899 if len(out)>0:
1327 gross 929 return "Volume(%s) = {%s, %s};"%(self.getID(),self.getSurfaceLoop().getDirectedID(), out)
1328 gross 899 else:
1329 gross 929 return "Volume(%s) = {%s};"%(self.getID(),self.getSurfaceLoop().getDirectedID())
1330 gross 898
1331 gross 929 class PropertySet(PrimitiveBase):
1332 gross 898 """
1333 gross 929 defines a group L{PrimitiveBase} objects.
1334 gross 898 """
1335     def __init__(self,tag=None,*items):
1336     super(PropertySet, self).__init__()
1337     self.__items=items
1338     self.__tag=tag
1339 gross 929 def collectPrimitiveBases(self):
1340     out=[self]+self.getBoundaryLoop().collectPrimitiveBases()
1341     for i in self.getHoles(): out+=i.collectPrimitiveBases()
1342 gross 899 return out
1343    
1344 gross 929 class PrimitiveBaseStack(object):
1345 gross 899 def __init__(self,*items):
1346     self.__prims=set()
1347     for i in items:
1348 gross 916 self.__prims|=i.getPrimitives()
1349 gross 899 self.__prims=list(self.__prims)
1350     self.__prims.sort()
1351    
1352 gross 929 def getGmshCommands(self,scaling_factor=1.):
1353 gross 899 out=""
1354     for i in self.__prims:
1355 gross 929 out+=i.getGmshCommand(scaling_factor)+"\n"
1356 gross 899 return out

  ViewVC Help
Powered by ViewVC 1.1.26