/[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 930 by gross, Thu Jan 18 08:12:58 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=set()
79            for i in self.getPrimitives():
80               if isinstance(i,Point): out.add(i)
81            return list(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=set()
88            return list(set([p for p in self.collectPrimitiveBases()]))
89    
90        def copy(self):
91           """
92           returns a deep copy of the object
93           """
94           return self.substitute({})
95    
96        def modifyBy(self,transformation):
97           """
98           modifies the coordinates by applying a transformation
99           """
100           for p in self.getConstructionPoints(): p.modifyBy(transformation)
101    
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                raise TypeError, "cannot convert argument to Transformation class object."
155            return self.apply(trafo)
156    
157    
158        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            returns a new object by applying the transformation
167            """
168            out=self.copy()
169            out.modifyBy(transformation)
170            return out
171    
172  class Primitive(object):  class Primitive(object):
173      """      """
174      template for elementary geometrical object      A general primitive
175      """      """
176      def __init__(self):      def __init__(self):
177         """         """
178           initializes PrimitiveBase instance object with id
179         """         """
180         global global_primitive_id_counter         global global_primitive_id_counter
181         self.__ID=global_primitive_id_counter         self.__ID=global_primitive_id_counter
182         global_primitive_id_counter+=1         global_primitive_id_counter+=1
183    
184      def getID(self):      def getID(self):
185           """
186           returns the primitive ID
187           """
188         return self.__ID         return self.__ID
189    
190        def getDirectedID(self):
191            """
192            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):      def __repr__(self):
197         return "%s(%s)"%(self.__class__.__name__,self.getID())         return "%s(%s)"%(self.__class__.__name__,self.getID())
198      def __cmp__(self,other):  
199         return cmp(self.getID(),other.getID())      def getUnderlyingPrimitive(self):
     def getPoints(self):  
200          """          """
201          returns the C{set} of points used to construct the primitive          returns the underlying primitive
202          """          """
203          out=set()          return self
204          for i in self.getHistory():      def hasSameOrientation(self,other):
205             if isinstance(i,Point): out.add(i)          """
206          return out          returns True if other is the same primitive and has the same orientation
207            """
208            return self == other and isinstance(other,Primitive)
209    
210      def setLocalScale(self,factor=1.):      def __neg__(self):
211          """          """
212          sets the local refinement factor          returns a view onto the curve with reversed ordering
213    
214            @note: this class is overwritten by subclass
215          """          """
216          for p in self.getPoints(): p.setLocalScale(factor)          raise NotImplementedError("__neg__ is not implemented.")
217    
218      def isPoint(self):      def getGmshCommand(self, local_scaling_factor=1.):
219          """          """
220          returns C{True} is the primitive is a L{Point}          returns the Gmsh command(s) to create the primitive
221    
222            @note: this class is overwritten by subclass
223          """          """
224          return False          raise NotImplementedError("getGmshCommand is not implemented.")
225      def isCurve(self):  
226        def substitute(self,sub_dict):
227          """          """
228          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}.
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    
232            @note: this class is overwritten by subclass
233          """          """
234          return False          raise NotImplementedError("substitute is not implemented.")
235      def isSurface(self):  
236        def collectPrimitiveBases(self):
237          """          """
238          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
239            
240            @note: this class is overwritten by subclass
241          """          """
242          return False          raise NotImplementedError("collectPrimitiveBases is not implemented.")
243      def isCurveLoop(self):  
244        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        """
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           if not isinstance(primitive, Primitive):
262               raise ValueError("argument needs to be a Primitive class object.")
263           self.__primitive=primitive
264    
265        def getID(self):
266           """
267           returns the primitive ID
268           """
269           return self.__primitive.getID()
270    
271        def getUnderlyingPrimitive(self):
272          """          """
273          returns C{True} is the primitive is a L{CurveLoop}          returns the underlying primitive
274          """          """
275          return False          return self.__primitive
276      def isSurfaceLoop(self):  
277        def hasSameOrientation(self,other):
278          """          """
279          returns C{True} is the primitive is a L{SurfaceLoop}          returns True if other is the same primitive and has the same orientation
280          """          """
281          return False          return self == other and isinstance(other,ReversePrimitive)
282      def getHistory(self):  
283        def __repr__(self):
284           return "-%s(%s)"%(self.__primitive.__class__.__name__,self.getID())
285    
286        def getDirectedID(self):
287          """          """
288          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.
289          """          """
290          return set()          return -self.__primitive.getID()
           
291    
292      #==================================================      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):      def __neg__(self):
303          return ReversedPrimitive(self)            """
304      def __pos__(self):            returns a view onto the curve with reversed ordering
305          return self.copy()            """
306      def __add__(self,other):            return self.__primitive
        out=self.copy()  
        out+=other  
        return out  
     def __iadd__(self,other):  
        self.shift()  
     def shift(self,shift):  
         for p in self.getPoints(): p+=shift  
     def copy(self):  
         return Primitive()  
     def getGmshCommand(self):  
         raise NotImplementedError("getGmshCommand is not implemented for this class %s."%self.__class__.__name__)  
     def translate(self,shift):  
         raise NotImplementedError("translate is not implemented for this class %s."%self.__class__.__name__)  
307    
308  class Point(Primitive):      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      """      """
330      a three dimensional point      a three dimensional point
331      """      """
# Line 122  class Point(Primitive): Line 333  class Point(Primitive):
333         """         """
334         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
335         """         """
336         super(Point, self).__init__()         PrimitiveBase.__init__(self)
337         self.setCoordinates(x,y,z)         Primitive.__init__(self)
338           self.setCoordinates(numarray.array([x,y,z],_TYPE))
339         self.setLocalScale(local_scale)         self.setLocalScale(local_scale)
340    
341      def setLocalScale(self,factor=1.):      def setLocalScale(self,factor=1.):
342         """         """
343         sets the local refinement factor         sets the local refinement factor
# Line 132  class Point(Primitive): Line 345  class Point(Primitive):
345         if factor<=0.:         if factor<=0.:
346            raise ValueError("scaling factor must be positive.")            raise ValueError("scaling factor must be positive.")
347         self.__local_scale=factor         self.__local_scale=factor
348    
349      def getLocalScale(self):      def getLocalScale(self):
350         """         """
351         returns the local refinement factor         returns the local refinement factor
# Line 142  class Point(Primitive): Line 356  class Point(Primitive):
356         returns the coodinates of the point as L{numarray.NumArray} object         returns the coodinates of the point as L{numarray.NumArray} object
357         """         """
358         return self._x         return self._x
359      def setCoordinates(self,x,y,z):      def setCoordinates(self,x):
360         """         """
361         returns the coodinates of the point as L{numarray.NumArray} object         returns the coodinates of the point as L{numarray.NumArray} object
362         """         """
363         self._x=numarray.array([x,y,z],_TYPE)         if not isinstance(x, numarray.NumArray):
364      def getHistory(self):            self._x=numarray.array(x,_TYPE)
365           else:
366              self._x=x
367    
368        def collectPrimitiveBases(self):
369         """         """
370         returns C{set} of primitive used to construct the primitive         returns primitives used to construct the primitive
371         """         """
372         return set([self])         return [self]
373    
374      def isColocated(self,point,tol=1.e-11):      def isColocated(self,primitive):
375         """         """
376         returns True if L{Point} point is colocation (same coordinates)         returns True if L{Point} primitive is colocation (same coordinates)
377         that means if |self-point| <= tol * max(|self|,|point|)         that means if |self-primitive| <= tol * max(|self|,|primitive|)
378         """         """
379         if isinstance(point,Point):         if isinstance(primitive,Point):
380            point=point.getCoordinates()            primitive=primitive.getCoordinates()
381         c=self.getCoordinates()            c=self.getCoordinates()
382         d=c-point            d=c-primitive
383         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))
384               else:
385              return False
386    
387      #=============================================================      def substitute(self,sub_dict):
388      def copy(self):          """
389         c=self.getCoordinates()          returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
390         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
391      def isPoint(self):          with substituted arguments is returned.
392          return True          """
393      def getGmshCommand(self):          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    
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            """
407            returns the Gmsh command(s) to create the primitive
408            """
409          c=self.getCoordinates()          c=self.getCoordinates()
410          return "Point(%s) = {%e , %e, %e , %e * scale};"%(self.getID(),c[0],c[1],c[2], self.getLocalScale())          return "Point(%s) = {%s , %s, %s , %s };"%(self.getID(),c[0],c[1],c[2], self.getLocalScale()*local_scaling_factor)
411      def shift(self,shift):  
412         """      def __neg__(self):
413         shifts the point by a given shift          """
414         """          returns a view of the object with reverse orientiention. As a point has no direction the object itself is returned.
415         self._x+=numarray.array(shift,numarray.Float64)          """
416      def translate(self,shift):          return self
417         """        
418         returns the point shifted by shift  class Manifold1D(PrimitiveBase):
419         """      """
420         out=self.copy()      general one-dimensional minifold in 3D defined by a start and end point.
421         out+=other      """
422         return out      def __init__(self):
423            """
424            create a one-dimensional manifold
425            """
426            PrimitiveBase.__init__(self)
427    
428        def getStartPoint(self):
429             """
430             returns start point
431             """
432             raise NotImplementedError()
433    
434  class Curve(Primitive):      def getEndPoint(self):
435        """           """
436        a curve           returns end point
437        """           """
438        def __init__(self,*args):           raise NotImplementedError()
439    
440    class CurveBase(Manifold1D):
441        """
442        A Curve is defined by a set of control points
443        """
444        def __init__(self):
445            """            """
446            defines a curve form a set of control points            create curve
447              """
448              Manifold1D.__init__(self)
449    
450        def __len__(self):
451            """            """
452            super(Curve, self).__init__()            returns the number of control points
453            l=len(args)            """
454            for i in range(l):            return len(self.getControlPoints())
455                if not args[i].isPoint():  
456                   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):  
457           """           """
458           returns start point           returns start point
459           """           """
460           return self.__nodes[0]           return self.getControlPoints()[0]
461    
462        def getEnd(self):      def getEndPoint(self):
463           """           """
464           returns end point           returns end point
465           """           """
466           return self.__nodes[-1]           return self.getControlPoints()[-1]
467    
468        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           """
480           defines a curve form control points
481           """
482           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    
492        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        def substitute(self,sub_dict):
505            """
506            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            """
510            if not sub_dict.has_key(self):
511                new_p=[]
512                for p in self.getControlPoints(): new_p.append(p.substitute(sub_dict))
513                sub_dict[self]=self.__class__(*tuple(new_p))
514            return sub_dict[self]
515    
516        def getNodes(self):      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        def isColocated(self,primitive):
525           """
526           returns True curves are on the same position
527           """
528           if hasattr(primitive,"getUnderlyingPrimitive"):
529             if isinstance(primitive.getUnderlyingPrimitive(),self.__class__):
530               if len(primitive) == len(self):
531                 cp0=self.getControlPoints()
532                 cp1=primitive.getControlPoints()
533                 match=True
534                 for i in range(len(cp0)):
535                    if not cp0[i].isColocated(cp1[i]):
536                       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                 return True
543           return False
544    
545    class ReverseCurve(CurveBase, ReversePrimitive):
546        """
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           if not isinstance(curve, Curve):
554               raise TypeError("ReverseCurve needs to be an instance of Curve")
555           CurveBase.__init__(self)
556           ReversePrimitive.__init__(self,curve)
557    
558        def getControlPoints(self):
559           """           """
560           returns a list of the nodes           returns a list of the points
561           """           """
562           return self.__nodes           out=[p for p in self.getUnderlyingPrimitive().getControlPoints()]
563        def getGmshCommand(self):           out.reverse()
564             return out
565    
566    class Spline(Curve):
567        """
568        a spline curve defined through a list of control points.
569        """
570        def getGmshCommand(self,scaling_factor=1.):
571            """
572            returns the Gmsh command(s) to create the Curve
573            """
574          out=""          out=""
575          for i in self.getNodes():          for i in self.getControlPoints():
576              if len(out)>0:              if len(out)>0:
577                  out+=", %s"%i.getID()                  out+=", %s"%i.getDirectedID()
578              else:              else:
579                  out="%s"%i.getID()                  out="%s"%i.getDirectedID()
580          return "Spline(%s) = {%s};"%(self.getID(),out)          return "Spline(%s) = {%s};"%(self.getID(),out)
581        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  
   
582    
583  class BezierCurve(Curve):  class BezierCurve(Curve):
584      """      """
585      a Bezier curve      a Bezier curve
586      """      """
587      def __neg__(self):      def getGmshCommand(self,scaling_factor=1.):
588           """          """
589           returns the line segment with swapped start and end points          returns the Gmsh command(s) to create the Curve
590           """          """
          return BezierCurve(self.getNodes()[::-1])  
     def __add__(self,other):  
          return BezierCurve([p+other for p in self.getNodes()])  
     def getGmshCommand(self):  
591          out=""          out=""
592          for i in self.getNodes():          for i in self.getControlPoints():
593              if len(out)>0:              if len(out)>0:
594                  out+=", %s"%i.getID()                  out+=", %s"%i.getDirectedID()
595              else:              else:
596                  out="%s"%i.getID()                  out="%s"%i.getDirectedID()
597          return "Bezier(%s) = {%s};"%(self.getID(),out)          return "Bezier(%s) = {%s};"%(self.getID(),out)
598    
599  class BSplineCurve(Curve):  class BSpline(Curve):
600      """      """
601      a BSpline curve. Control points may be repeated.      a BSpline curve. Control points may be repeated.
602      """      """
603      def __neg__(self):      def getGmshCommand(self,scaling_factor=1.):
604           """          """
605           returns the line segment with swapped start and end points          returns the Gmsh command(s) to create the Curve
606           """          """
          return BSplineCurve(self.getNodes()[::-1])  
     def __add__(self,other):  
          return BSplineCurve([p+other for p in self.getNodes()])  
     def getGmshCommand(self):  
607          out=""          out=""
608          for i in self.getNodes():          for i in self.getControlPoints():
609              if len(out)>0:              if len(out)>0:
610                  out+=", %s"%i.getID()                  out+=", %s"%i.getDirectedID()
611              else:              else:
612                  out="%s"%i.getID()                  out="%s"%i.getDirectedID()
613          return "BSpline(%s) = {%s};"%(self.getID(),out)          return "BSpline(%s) = {%s};"%(self.getID(),out)
614    
615  class Line(Curve):  class Line(Curve):
616      """      """
617      a line is defined by two L{Point}s      a line is defined by two pointDirecteds
618      """      """
619      def __init__(self,start,end):      def __init__(self,*points):
620          """          """
621          defines a curve form a set of control points          defines a line with start and end point
622          """          """
623          super(Line, self).__init__(start,end)          if len(points)!=2:
624      def __neg__(self):             raise TypeError("Line needs two points")
625         return ReversedPrimitive(self)          Curve.__init__(self,*points)
626      def __add__(self,other):      def getGmshCommand(self,scaling_factor=1.):
627         return Line(self.getEnd()+other,self.getStart()+other)          """
628      def getGmshCommand(self):          returns the Gmsh command(s) to create the Curve
629          return "Line(%s) = {%s, %s};"%(self.getID(),self.getStart().getID(),self.getEnd().getID())          """
630            return "Line(%s) = {%s, %s};"%(self.getID(),self.getStartPoint().getDirectedID(),self.getEndPoint().getDirectedID())
631    
632    
633    class ArcBase(Manifold1D):
634        def __init__(self):
635              """
636              create curve
637              """
638              Manifold1D.__init__(self)
639        def collectPrimitiveBases(self):
640           """
641           returns the primitives used to construct the Curve
642           """
643           out=[self]
644           out+=self.getStartPoint().collectPrimitiveBases()
645           out+=self.getEndPoint().collectPrimitiveBases()
646           out+=self.getCenterPoint().collectPrimitiveBases()
647           return out
648    
649    
650  class Arc(Curve):      def getCenterPoint(self):
651             """
652             returns center
653             """
654             raise NotImplementedError()
655    
656    class Arc(ArcBase, Primitive):
657      """      """
658      defines an arc      defines an arc which is strictly, smaller than Pi
659      """      """
660      def __init__(self,center,start,end):      def __init__(self,center,start,end):
661         """         """
662         creates an arc by the start point, end point and center         creates an arc by the start point, end point and center
663         """         """
664         if center.isPoint():         if not isinstance(center,Point): raise TypeError("center needs to be a Point object.")
665             raise TypeError("center needs to be a Point object.")         if not isinstance(end,Point): raise TypeError("end needs to be a Point object.")
666         super(Arc, self).__init__(start,end)         if not isinstance(start,Point): raise TypeError("start needs to be a Point object.")
667           # TODO: check length of circle.
668           ArcBase.__init__(self)
669           Primitive.__init__(self)
670         self.__center=center         self.__center=center
671           self.__start=start
672           self.__end=end
673        def __neg__(self):
674              """
675              returns a view onto the curve with reversed ordering
676              """
677              return ReverseArc(self)
678    
679      def getCenter(self):      def getStartPoint(self):
680           """
681           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         returns center         returns center
694         """         """
695         return self.__center         return self.__center
     def __add__(self,other):  
        return Arc(self.getCenter()+other,self.getStart()+other,self.getEnd()+other)  
696    
697      def getHistory(self):      def substitute(self,sub_dict):
698            out=set([self])          """
699            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}.
700            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
701            return out          with substituted arguments is returned.
702      def getPoints(self):          """
703            out=self.getCenter().getPoints()          if not sub_dict.has_key(self):
704            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))
705            return out          return sub_dict[self]
706      def getGmshCommand(self):  
707          return "Circle(%s) = {%s, %s, %s};"%(self.getID(),self.getStart().getID(),self.getCenter().getID(),self.getEnd().getID())      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           if hasattr(primitive,"getUnderlyingPrimitive"):
718              if isinstance(primitive.getUnderlyingPrimitive(),Arc):
719                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           return False
723    
724    class ReverseArc(ArcBase, ReversePrimitive):
725        """
726        defines an arc which is strictly, smaller than Pi
727        """
728        def __init__(self,arc):
729           """
730           creates an arc by the start point, end point and center
731           """
732           if not isinstance(arc, Arc):
733               raise TypeError("ReverseCurve needs to be an instance of Arc")
734           ArcBase.__init__(self)
735           ReversePrimitive.__init__(self,arc)
736    
737        def getStartPoint(self):
738           """
739           returns start point
740           """
741           return self.getUnderlyingPrimitive().getEndPoint()
742    
743        def getEndPoint(self):
744           """
745           returns end point
746           """
747           return self.getUnderlyingPrimitive().getStartPoint()
748    
749  class CurveLoop(Primitive):      def getCenterPoint(self):
750           """
751           returns center
752           """
753           return self.getUnderlyingPrimitive().getCenterPoint()
754    
755    class CurveLoop(Primitive, PrimitiveBase):
756      """      """
757      An oriented loop of curves.      An oriented loop of one-dimensional manifolds (= curves and arcs)
758    
759      The loop must be closed and the L{Curves}s should be oriented consistently.      The loop must be closed and the L{Manifold1D}s should be oriented consistently.
760      """      """
761      def __init__(self,*curves):      def __init__(self,*curves):
762         """         """
763         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.
764         """         """
765         super(CurveLoop, self).__init__()         if len(curves)<2:
766         self.__curves=[]              raise TypeError("at least two curves have to be given.")
        self.addCurve(*curves)  
     def addCurve(self,*curves):  
767         for i in range(len(curves)):         for i in range(len(curves)):
768             if not curves[i].isCurve():             if not isinstance(curves[i],Manifold1D):
769                raise TypeError("%s-th argument is not a Curve object."%i)                raise TypeError("%s-th argument is not a Manifold1D object."%i)
770         self.__curves+=curves         # 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           Primitive.__init__(self)
788           PrimitiveBase.__init__(self)
789    
     def isCurveLoop(self):  
         return True  
790      def getCurves(self):      def getCurves(self):
791           """
792           returns the curves defining the CurveLoop
793           """
794         return self.__curves         return self.__curves
795      def __add__(self,other):  
796         return CurveLoop(*tuple([c+other for c in self.getCurves()[::-1]]))      def __neg__(self):
797           """
798           returns a view onto the curve with reversed ordering
799           """
800           return ReverseCurveLoop(self)
801    
802      def __len__(self):      def __len__(self):
803         return len(self.__curves)         """
804      def getHistory(self):         return the number of curves in the CurveLoop
805            out=set([self])         """
806            for i in self.getCurves(): out|=i.getHistory()         return len(self.getCurves())
807            return out  
808      def getPoints(self):  
809            out=set()      def collectPrimitiveBases(self):
810            for i in self.getCurves(): out|=i.getPoints()         """
811            return out         returns primitives used to construct the CurveLoop
812      def getGmshCommand(self):         """
813           out=[self]
814           for c in self.getCurves(): out+=c.collectPrimitiveBases()
815           return out
816    
817        def substitute(self,sub_dict):
818            """
819            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            """
823            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    
829        def isColocated(self,primitive):
830           """
831           returns True if each curve is collocted with a curve in primitive
832           """
833           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    
846        def getGmshCommand(self,scaling_factor=1.):
847            """
848            returns the Gmsh command(s) to create the primitive
849            """
850          out=""          out=""
851          for i in self.getCurves():          for i in self.getCurves():
852              if len(out)>0:              if len(out)>0:
853                  out+=", %s"%i.getID()                  out+=", %s"%i.getDirectedID()
854              else:              else:
855                  out="%s"%i.getID()                  out="%s"%i.getDirectedID()
856          return "Line Loop(%s) = {%s};"%(self.getID(),out)          return "Line Loop(%s) = {%s};"%(self.getID(),out)
857    
858  class Surface(Primitive):  class ReverseCurveLoop(ReversePrimitive, PrimitiveBase):
859        """
860        An oriented loop of one-dimensional manifolds (= curves and arcs)
861    
862        The loop must be closed and the one-dimensional manifolds should be oriented consistently.
863        """
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    #=
883    class Manifold2D(PrimitiveBase):
884        """
885        general two-dimensional manifold
886        """
887        def __init__(self):
888           """
889           create a two-dimensional manifold
890           """
891           PrimitiveBase.__init__(self)
892    
893        def getBoundary(self):
894            """
895            returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
896            """
897            raise NotImplementedError()
898    
899    class RuledSurface(Primitive, Manifold2D):
900      """      """
901      a surface      A ruled surface, i.e., a surface that can be interpolated using transfinite interpolation
902      """      """
903      def __init__(self,loop):      def __init__(self,loop):
904         """         """
905         creates a  surface with boundary loop         creates a ruled surface with boundary loop
906    
907         @param loop: L{CurveLoop} defining the boundary of the surface         @param loop: L{CurveLoop} defining the boundary of the surface.
908         """         """
909         super(Surface, self).__init__()         if not isinstance(loop.getUnderlyingPrimitive(),CurveLoop):
        if not loop.isCurveLoop():  
910             raise TypeError("argument loop needs to be a CurveLoop object.")             raise TypeError("argument loop needs to be a CurveLoop object.")
911           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           Primitive.__init__(self)
916           Manifold2D.__init__(self)
917         self.__loop=loop         self.__loop=loop
918      def isSurface(self):  
919          return True      def __neg__(self):
920              """
921              returns a view onto the suface with reversed ordering
922              """
923              return ReverseRuledSurface(self)
924    
925      def getBoundaryLoop(self):      def getBoundaryLoop(self):
926         return self.__loop          """
927      def __add__(self,other):          returns the loop defining the outer boundary
928         return Surface(self.getBoundaryLoop()+other)          """
929      def getHistory(self):          return self.__loop
         out=set([self]) | self.getBoundaryLoop().getHistory()  
         return out  
     def getPoints(self):  
         return self.getBoundaryLoop().getPoints()  
     def getGmshCommand(self):  
         return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())  
930    
931  class PlaneSurface(Surface):      def getBoundary(self):
932            """
933            returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
934            """
935            return self.getBoundaryLoop().getCurves()
936    
937        def getGmshCommand(self,scaling_factor=1.):
938            """
939            returns the Gmsh command(s) to create the primitive
940            """
941            return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getDirectedID())
942    
943        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                sub_dict[self]=RuledSurface(self.getBoundaryLoop().substitute(sub_dict))
951            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           if hasattr(primitive,"getUnderlyingPrimitive"):
958              if isinstance(primitive.getUnderlyingPrimitive(),RuledSurface):
959                 return self.getBoundaryLoop().isColocated(primitive.getBoundaryLoop())
960           return False
961    
962        def collectPrimitiveBases(self):
963            """
964            returns primitives used to construct the Surface
965            """
966            return [self] + self.getBoundaryLoop().collectPrimitiveBases()
967    
968    def createRuledSurface(*curves):
969          """
970          an easier way to create a L{RuledSurface} from given curves.
971          """
972          return RuledSurface(CurveLoop(*curves))
973    
974    
975    class ReverseRuledSurface(ReversePrimitive, Manifold2D):
976        """
977        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      a plane surface with holes      a plane surface with holes
1003      """      """
1004      def __init__(self,loop,holes=[]):      def __init__(self,loop,holes=[]):
1005         """         """
1006         creates a  plane surface.         creates a  plane surface with a hole
1007    
1008         @param loop: L{CurveLoop} defining the boundary of the surface         @param loop: L{CurveLoop} defining the boundary of the surface
1009         @param holes: list of L{CurveLoop} defining holes in the surface.         @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.           @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.                A CurveLoop defining a hole should not have any lines in common with another CurveLoop defining a hole in the same surface.
1012         """         """
1013         super(PlaneSurface, self).__init__(loop)         if not isinstance(loop.getUnderlyingPrimitive(),CurveLoop):
1014               raise TypeError("argument loop needs to be a CurveLoop object.")
1015           for l in loop.getCurves():
1016               if not isinstance(l.getUnderlyingPrimitive(),Line):
1017                 raise TypeError("loop may be formed by Lines only.")
1018         for i in range(len(holes)):         for i in range(len(holes)):
1019              if not holes[i].inCurveLoop():              if not isinstance(holes[i].getUnderlyingPrimitive(), CurveLoop):
1020                   raise TypeError("%i th hole needs to be a CurveLoop object.")                   raise TypeError("%i-th hole needs to be a CurveLoop object.")
1021                for l in holes[i].getCurves():
1022                   if not isinstance(l.getUnderlyingPrimitive(),Line):
1023                      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           Primitive.__init__(self)
1027           Manifold2D.__init__(self)
1028           self.__loop=loop
1029         self.__holes=holes         self.__holes=holes
1030      def getHoles(self):      def getHoles(self):
1031           """
1032           returns the holes
1033           """
1034         return self.__holes         return self.__holes
1035      def __add__(self,other):  
1036         return PlaneSurface(self.getBoundaryLoop()+other, holes=[h+other for h in self.getHoles()])      def getBoundaryLoop(self):
1037      def getHistory(self):          """
1038          out=set([self]) | self.getBoundaryLoop().getHistory()          returns the loop defining the boundary
1039          for i in self.getHoles(): out|=i.getHistory()          """
1040          return out          return self.__loop
1041      def getPoints(self):  
1042          out=self.getBoundaryLoop().getPoints()      def getGmshCommand(self,scaling_factor=1.):
1043          for i in self.getHoles(): out|=i.getPoints()          """
1044          return out          returns the Gmsh command(s) to create the primitive
1045      def getGmshCommand(self):          """
1046          out=""          out=""
1047          for i in self.getHoles():          for i in self.getHoles():
1048              if len(out)>0:              if len(out)>0:
1049                  out+=", %s"%i.getID()                  out+=", %s"%i.getDirectedID()
1050              else:              else:
1051                  out="%s"%i.getID()                  out="%s"%i.getDirectedID()
1052          if len(out)>0:          if len(out)>0:
1053            return "Plane Surface(%s) = {%s, %s};"%(self.getID(),self.getBoundaryLoop().getID(), out)            return "Plane Surface(%s) = {%s, %s};"%(self.getID(),self.getBoundaryLoop().getDirectedID(), out)
1054          else:          else:
1055            return "Plane Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())            return "Plane Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getDirectedID())
1056    
1057  class RuledSurface(Surface):      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                sub_dict[self]=PlaneSurface(self.getBoundaryLoop().substitute(sub_dict),[ h.substitute(sub_dict) for h in self.getHoles()])
1065            return sub_dict[self]
1066    
1067        def isColocated(self,primitive):
1068           """
1069           returns True if each curve is collocted with a curve in primitive
1070           """
1071           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    
1104    class ReversePlaneSurface(ReversePrimitive, Manifold2D):
1105      """      """
1106     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
1107      """      """
1108      def __init__(self,loop):      def __init__(self,surface):
1109           """
1110           creates a polygon from a list of line curves. The curves must form a closed loop.
1111         """         """
1112         creates a ruled surface from a         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         @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):
1118         """         """
1119         if not loop.isCurveLoop():         returns the CurveLoop defining the RuledSurface
1120             raise TypeError("argument loop needs to be a CurveLoop object.")         """
1121         if len(loop)<3:         return -self.getUnderlyingPrimitive().getBoundaryLoop()
1122             raise TypeError("the loop must contain at least three Curves.")  
1123         super(RuledSurface, self).__init__(loop)      def getHoles(self):
1124      def __add__(self,other):          """
1125         return RuledSurface(self.getBoundaryLoop()+other)          returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
1126      def getGmshCommand(self):          """
1127          return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getID())          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  class SurfaceLoop(Primitive):  
1138    #=========================================================================
1139    class SurfaceLoop(Primitive, PrimitiveBase):
1140      """      """
1141      a surface loop. It defines the shell of a volume.      a loop of 2D primitives. It defines the shell of a volume.
1142    
1143      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.
1144      """      """
1145      def __init__(self,*surfaces):      def __init__(self,*surfaces):
1146         """         """
1147         creates a surface loop         creates a surface loop
1148         """         """
1149         super(SurfaceLoop, self).__init__()         if len(surfaces)<2:
1150         self.__surfaces=[]              raise TypeError("at least two surfaces have to be given.")
        self.addSurface(*surfaces)  
     def addSurface(self,*surfaces):  
1151         for i in range(len(surfaces)):         for i in range(len(surfaces)):
1152             if not surfaces[i].isSurface():             if not isinstance(surfaces[i].getUnderlyingPrimitive(),Manifold2D):
1153                raise TypeError("%s-th argument is not a Surface object."%i)                raise TypeError("%s-th argument is not a Manifold2D object."%i)
1154         self.__surfaces+=surfaces         Primitive.__init__(self)
1155           PrimitiveBase.__init__(self)
1156           # for the curves a loop:
1157           used=[ False for s in surfaces]
1158           self.__surfaces=[surfaces[0]]
1159           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              found=False
1164              for i in xrange(len(surfaces)):
1165                 if not used[i]:
1166                    i_boundary=surfaces[i].getBoundary()
1167                    print i, i_boundary
1168                    for ib in xrange(len(i_boundary)):  
1169                        print ib, i_boundary[ib], edges
1170                        if i_boundary[ib] in edges:
1171                             if used_edges[edges.index(i_boundary[ib])]:
1172                                raise ValueError("boundary segment %s is shared by more than one surface."%str(i_boundary[ib]))
1173                             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           print min(used_edges), used_edges
1186           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    
1194        def __neg__(self):
1195           """
1196           returns a view onto the curve with reversed ordering
1197           """
1198           return ReverseSurfaceLoop(self)
1199    
     def isSurfaceLoop(self):  
         return True  
1200      def getSurfaces(self):      def getSurfaces(self):
1201           """
1202           returns the surfaces defining the SurfaceLoop
1203           """
1204         return self.__surfaces         return self.__surfaces
1205      def __add__(self,other):  
1206         return SurfaceLoop([c+other for c in self.getSurfaces])      def collectPrimitiveBases(self):
1207      def __len__(self):         """
1208         return len(self.__surfaces)         returns primitives used to construct the SurfaceLoop
1209      def getHistory(self):         """
1210            out=set([self])         out=[self]
1211            for i in self.getSurfaces(): out|=i.getHistory()         for c in self.getSurfaces(): out+=c.collectPrimitiveBases()
1212            return out         return out
1213      def getPoints(self):  
1214            out=set()      def getGmshCommand(self,scaling_factor=1.):
1215            for i in self.getSurfaces(): out|=i.getPoints()          """
1216            return out          returns the Gmsh command(s) to create the primitive
1217      def getGmshCommand(self):          """
1218          out=""          out=""
1219          for i in self.getSurfaces():          for i in self.getSurfaces():
1220              if len(out)>0:              if len(out)>0:
1221                  out+=", %s"%i.getID()                  out+=", %s"%i.getDirectedID()
1222              else:              else:
1223                  out="%s"%i.getID()                  out="%s"%i.getDirectedID()
1224          return "Surface Loop(%s) = {%s};"%(self.getID(),out)          return "Surface Loop(%s) = {%s};"%(self.getID(),out)
1225        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    
1237        def isColocated(self,primitive):
1238           """
1239           returns True if each surface is collocted with a curve in primitive and vice versa.
1240           """
1241           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    
1254    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  class Volume(Primitive):      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    #==========================
1281    class Volume(PrimitiveBase):
1282      """      """
1283      a volume with holes.      a volume with holes.
1284      """      """
# Line 535  class Volume(Primitive): Line 1305  class Volume(Primitive):
1305         return self.__loop         return self.__loop
1306      def __add__(self,other):      def __add__(self,other):
1307         return Volume(self.getSurfaceLoop()+other, holes=[h+other for h in self.getHoles()])         return Volume(self.getSurfaceLoop()+other, holes=[h+other for h in self.getHoles()])
1308      def getHistory(self):      def collectPrimitiveBases(self):
1309          out=set([self]) | self.getSurfaceLoop().getHistory()          out=[self] + self.getSurfaceLoop().collectPrimitiveBases()
1310          for i in self.getHoles(): out|=i.getHistory()          for i in self.getHoles(): out+=i.collectPrimitiveBases()
1311          return out          return out
1312      def getPoints(self):      def getConstructionPoints(self):
1313          out=self.getSurfaceLoop().getPoints()          out=self.getSurfaceLoop().getConstructionPoints()
1314          for i in self.getHoles(): out|=i.Points()          for i in self.getHoles(): out|=i.Points()
1315          return out          return out
1316      def getGmshCommand(self):      def getGmshCommand(self,scaling_factor=1.):
1317            """
1318            returns the Gmsh command(s) to create the primitive
1319            """
1320          out=""          out=""
1321          for i in self.getHoles():          for i in self.getHoles():
1322              if len(out)>0:              if len(out)>0:
1323                  out+=", %s"%i.getID()                  out+=", %s"%i.getDirectedID()
1324              else:              else:
1325                  out="%s"%i.getID()                  out="%s"%i.getDirectedID()
1326          if len(out)>0:          if len(out)>0:
1327            return "Volume(%s) = {%s, %s};"%(self.getID(),self.getSurfaceLoop().getID(), out)            return "Volume(%s) = {%s, %s};"%(self.getID(),self.getSurfaceLoop().getDirectedID(), out)
1328          else:          else:
1329            return "Volume(%s) = {%s};"%(self.getID(),self.getSurfaceLoop().getID())            return "Volume(%s) = {%s};"%(self.getID(),self.getSurfaceLoop().getDirectedID())
   
 class ReversedPrimitive(object):  
     def __init__(self,prim):  
        self.__prim=prim  
     def __getattr__(self,name):  
        if name == "getID":  
           return self.getReverseID  
        else:  
           return getattr(self.__prim,name)  
     def getReverseID(self):  
         return -self.__prim.getID()  
1330    
1331  class PropertySet(Primitive):  class PropertySet(PrimitiveBase):
1332      """      """
1333      defines a group L{Primitive} objects.      defines a group L{PrimitiveBase} objects.
1334      """      """
1335      def __init__(self,tag=None,*items):      def __init__(self,tag=None,*items):
1336         super(PropertySet, self).__init__()         super(PropertySet, self).__init__()
1337         self.__items=items         self.__items=items
1338         self.__tag=tag         self.__tag=tag
1339      def getHistory(self):      def collectPrimitiveBases(self):
1340          out=set([self, self.getBoundaryLoop().getHistory()])          out=[self]+self.getBoundaryLoop().collectPrimitiveBases()
1341          for i in self.getHoles(): out|=i.getHistory()          for i in self.getHoles(): out+=i.collectPrimitiveBases()
1342          return out          return out
1343    
1344  class PrimitiveStack(object):  class PrimitiveBaseStack(object):
1345        def __init__(self,*items):        def __init__(self,*items):
1346          self.__prims=set()          self.__prims=set()
1347          for i in items:          for i in items:
1348              self.__prims|=i.getHistory()              self.__prims|=i.getPrimitives()
1349          self.__prims=list(self.__prims)          self.__prims=list(self.__prims)
1350          self.__prims.sort()          self.__prims.sort()
1351    
1352        def getGmshCommands(self):        def getGmshCommands(self,scaling_factor=1.):
1353          out=""          out=""
1354          for i in self.__prims:          for i in self.__prims:
1355             out+=i.getGmshCommand()+"\n"             out+=i.getGmshCommand(scaling_factor)+"\n"
1356          return out          return out

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

  ViewVC Help
Powered by ViewVC 1.1.26