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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.912  
changed lines
  Added in v.1123

  ViewVC Help
Powered by ViewVC 1.1.26