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

Legend:
Removed from v.917  
changed lines
  Added in v.931

  ViewVC Help
Powered by ViewVC 1.1.26