/[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 927 by gross, Fri Jan 12 06:32:08 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  
   
     def __repr__(self):  
        return "%s(%s)"%(self.__class__.__name__,self.getID())  
65    
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 84  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         """         """
# Line 94  class Primitive(object): Line 93  class Primitive(object):
93         """         """
94         return self.substitute({})         return self.substitute({})
95    
   
96      def modifyBy(self,transformation):      def modifyBy(self,transformation):
97         """         """
98         modifies the coordinates by applying a transformation         modifies the coordinates by applying a transformation
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 157  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 166  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 L{Point} 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          out=self.copy()          raise NotImplementedError("substitute is not implemented.")
235          out.modifyBy(transformation)  
236          return out      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):      def isColocated(self,primitive):
245         """         """
246         returns True is the two primitives are located at the smae position         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         raise NotImplementedError("isColocated is not implemented for this class %s."%self.__class__.__name__)         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):      def substitute(self,sub_dict):
293          """          """
# Line 193  class Primitive(object): Line 296  class Primitive(object):
296          with substituted arguments is returned.          with substituted arguments is returned.
297          """          """
298          if not sub_dict.has_key(self):          if not sub_dict.has_key(self):
299             sub_dict[self]=self.__class__()              sub_dict[self]=-self.getUnderlyingPrimitive().substitute(sub_dict)
300          return sub_dict[self]          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  class Point(Primitive):      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 204  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 215  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 234  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 278  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        a curve defined through a list of control points.
482        """
483        def __init__(self,*points):
484         """         """
485         returns primitives used to construct the Curve         defines a curve form control points
486         """         """
487         out=set()         if len(points)<2:
488         for p in self.getControlPoints(): out|=set(p.getPrimitives())             raise ValueError("Curve needs at least two points")
489         out.add(self)         i=0
490         return list(out)         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 substitute(self,sub_dict):      def substitute(self,sub_dict):
510          """          """
# Line 350  class Curve(Primitive1D): Line 518  class Curve(Primitive1D):
518              sub_dict[self]=self.__class__(*tuple(new_p))              sub_dict[self]=self.__class__(*tuple(new_p))
519          return sub_dict[self]          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               match=True
# Line 368  class Curve(Primitive1D): Line 545  class Curve(Primitive1D):
545                     if not cp0[i].isColocated(cp1[len(cp0)-1-i]):                     if not cp0[i].isColocated(cp1[len(cp0)-1-i]):
546                        return False                        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 394  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 432  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 Arc(Primitive1D):  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        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 452  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 475  class Arc(Primitive1D): Line 699  class Arc(Primitive1D):
699         """         """
700         return self.__center         return self.__center
701    
     def getPrimitives(self):  
        """  
        returns the primitives used to construct the Curve  
        """  
        out=set()  
        out|=set(self.getStartPoint().getPrimitives())  
        out|=set(self.getEndPoint().getPrimitives())  
        out|=set(self.getCenterPoint().getPrimitives())  
        out.add(self)  
        return list(out)  
   
     def getGmshCommand(self):  
        """  
        returns the Gmsh command(s) to create the primitive  
        """  
        return "Circle(%s) = {%s, %s, %s};"%(self.getID(),self.getStartPoint().getID(),self.getCenterPoint().getID(),self.getEndPoint().getID())  
   
702      def substitute(self,sub_dict):      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}.          returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
# Line 502  class Arc(Primitive1D): Line 709  class Arc(Primitive1D):
709              sub_dict[self]=Arc(self.getCenterPoint().substitute(sub_dict),self.getStartPoint().substitute(sub_dict),self.getEndPoint().substitute(sub_dict))              sub_dict[self]=Arc(self.getCenterPoint().substitute(sub_dict),self.getStartPoint().substitute(sub_dict),self.getEndPoint().substitute(sub_dict))
710          return sub_dict[self]          return sub_dict[self]
711    
712        def getGmshCommand(self,scaling_factor=1.):
713           """
714           returns the Gmsh command(s) to create the primitive
715           """
716           return "Circle(%s) = {%s, %s, %s};"%(self.getID(),self.getStartPoint().getDirectedID(),self.getCenterPoint().getDirectedID(),self.getEndPoint().getDirectedID())
717    
718      def isColocated(self,primitive):      def isColocated(self,primitive):
719         """         """
720         returns True curves are on the same position         returns True curves are on the same position
721         """         """
722         if isinstance(primitive,Arc):         if hasattr(primitive,"getUnderlyingPrimitive"):
723              if isinstance(primitive.getUnderlyingPrimitive(),Arc):
724              return (self.getCenterPoint().isColocated(primitive.getCenterPoint())) and ( \              return (self.getCenterPoint().isColocated(primitive.getCenterPoint())) and ( \
725                     (self.getEndPoint().isColocated(primitive.getEndPoint()) and self.getStartPoint().isColocated(primitive.getStartPoint()) ) \                     (self.getEndPoint().isColocated(primitive.getEndPoint()) and self.getStartPoint().isColocated(primitive.getStartPoint()) ) \
726                  or (self.getEndPoint().isColocated(primitive.getStartPoint()) and self.getStartPoint().isColocated(primitive.getEndPoint()) ) )                  or (self.getEndPoint().isColocated(primitive.getStartPoint()) and self.getStartPoint().isColocated(primitive.getEndPoint()) ) )
727         else:         return False
           return False  
728    
729  class Primitive2D(Primitive):  class ReverseArc(ArcBase, ReversePrimitive):
730        """      """
731        general two-dimensional primitive      defines an arc which is strictly, smaller than Pi
732        """      """
733        def __init__(self,*args):      def __init__(self,arc):
734            """         """
735            create a two-dimensional primitive         creates an arc by the start point, end point and center
736            """         """
737            super(Primitive2D, self).__init__()         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 getStartPoint(self):
743           """
744           returns start point
745           """
746           return self.getUnderlyingPrimitive().getEndPoint()
747    
748        def getEndPoint(self):
749           """
750           returns end point
751           """
752           return self.getUnderlyingPrimitive().getStartPoint()
753    
754  class CurveLoop(Primitive2D):      def getCenterPoint(self):
755           """
756           returns center
757           """
758           return self.getUnderlyingPrimitive().getCenterPoint()
759    
760    class CurveLoop(Primitive, PrimitiveBase):
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         """         """
        super(CurveLoop, self).__init__()  
770         if len(curves)<2:         if len(curves)<2:
771              raise TypeError("at least two curves have to be given.")              raise ValueError("at least two curves have to be given.")
772         for i in range(len(curves)):         for i in range(len(curves)):
773             if not isinstance(curves[i],Primitive1D):             if not isinstance(curves[i],Manifold1D):
774                raise TypeError("%s-th argument is not a Primitive1D object."%i)                raise TypeError("%s-th argument is not a Manifold1D object."%i)
775         # for the curves a loop:         # for the curves a loop:
776         used=[ False for i in curves]         used=[ False for i in curves]
777         self.__curves=[curves[0]]         self.__curves=[curves[0]]
# Line 556  class CurveLoop(Primitive2D): Line 789  class CurveLoop(Primitive2D):
789               raise ValueError("loop is not closed.")               raise ValueError("loop is not closed.")
790         if not self.__curves[0].getStartPoint() == self.__curves[-1].getEndPoint():         if not self.__curves[0].getStartPoint() == self.__curves[-1].getEndPoint():
791            raise ValueError("loop is not closed.")            raise ValueError("loop is not closed.")
792           Primitive.__init__(self)
793           PrimitiveBase.__init__(self)
794    
795      def getCurves(self):      def getCurves(self):
796         """         """
# Line 563  class CurveLoop(Primitive2D): Line 798  class CurveLoop(Primitive2D):
798         """         """
799         return self.__curves         return self.__curves
800    
801        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         """         """
809         return the number of curves in the CurveLoop         return the number of curves in the CurveLoop
810         """         """
811         return len(self.__curves)         return len(self.getCurves())
812    
813      def getPrimitives(self):  
814        def collectPrimitiveBases(self):
815         """         """
816         returns primitives used to construct the CurveLoop         returns primitives used to construct the CurveLoop
817         """         """
818         out=set()         out=[self]
819         for c in self.getCurves(): out|=set(c.getPrimitives())         for c in self.getCurves(): out+=c.collectPrimitiveBases()
820         out.add(self)         return out
        return list(out)  
821    
822      def substitute(self,sub_dict):      def substitute(self,sub_dict):
823          """          """
# Line 590  class CurveLoop(Primitive2D): Line 831  class CurveLoop(Primitive2D):
831              sub_dict[self]=CurveLoop(*tuple(new_c))              sub_dict[self]=CurveLoop(*tuple(new_c))
832          return sub_dict[self]          return sub_dict[self]
833    
   
834      def isColocated(self,primitive):      def isColocated(self,primitive):
835         """         """
836         returns True if each curve is collocted with a curve in primitive         returns True if each curve is collocted with a curve in primitive
837         """         """
838         if isinstance(primitive,CurveLoop):         if hasattr(primitive,"getUnderlyingPrimitive"):
839            if len(primitive) == len(self):            if isinstance(primitive.getUnderlyingPrimitive(),CurveLoop):
840               cp0=self.getCurves()               if len(primitive) == len(self):
841               cp1=primitive.getCurves()                  cp0=self.getCurves()
842               for c0 in cp0:                  cp1=primitive.getCurves()
843                   collocated = False                  for c0 in cp0:
844                   for c1 in cp1:                      collocated = False
845                        collocated = collocated or c0.isColocated(c1)                      for c1 in cp1:
846                   if not collocated: return False                           collocated = collocated or c0.isColocated(c1)
847               return True                      if not collocated: return False
848            else:                  return True
849               return False         return False
        else:  
           return False  
850    
851      def getGmshCommand(self):      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(Primitive2D):  class ReverseCurveLoop(ReversePrimitive, PrimitiveBase):
864      """      """
865      a surface      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      pass      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  class RuledSurface(Surface):      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 ruled surface, i.e., a surface that can be interpolated using transfinite interpolation      A ruled surface, i.e., a surface that can be interpolated using transfinite interpolation
907      """      """
# Line 635  class RuledSurface(Surface): Line 911  class RuledSurface(Surface):
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(RuledSurface, self).__init__()         if not isinstance(loop.getUnderlyingPrimitive(),CurveLoop):
        if not isinstance(CurveLoop):  
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:         if len(loop)<2:
917             raise TypeError("the loop must contain at least two Curves.")             raise ValueError("the loop must contain at least two Curves.")
918         if len(loop)>4:         if len(loop)>4:
919             raise TypeError("the loop must contain at least three Curves.")             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    
924        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          """          """
932          returns the loop defining the boundary          returns the loop defining the outer boundary
933          """          """
934          return self.__loop          return self.__loop
935    
936      def getPrimitives(self):      def getBoundary(self):
937          out=set([self]) | self.getBoundaryLoop().getPrimitives()          """
938            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 getPrimitives(self):      def getGmshCommand(self,scaling_factor=1.):
943         """          """
944         returns primitives used to construct the CurveLoop          returns the Gmsh command(s) to create the primitive
945         """          """
946         out=list(set([self]) | self.getBoundaryLoop().getPrimitives())          return "Ruled Surface(%s) = {%s};"%(self.getID(),self.getBoundaryLoop().getDirectedID())
947    
948      def substitute(self,sub_dict):      def substitute(self,sub_dict):
949          """          """
# Line 670  class RuledSurface(Surface): Line 952  class RuledSurface(Surface):
952          with substituted arguments is returned.          with substituted arguments is returned.
953          """          """
954          if not sub_dict.has_key(self):          if not sub_dict.has_key(self):
955              sub_dict[self]=CurveLoop(self.getBoundaryLoop().substitute(sub_dict))              sub_dict[self]=RuledSurface(self.getBoundaryLoop().substitute(sub_dict))
956          return sub_dict[self]          return sub_dict[self]
957    
958      def isColocated(self,primitive):      def isColocated(self,primitive):
959         """         """
960         returns True if each curve is collocted with a curve in primitive         returns True if each curve is collocted with a curve in primitive
961         """         """
962         if isinstance(primitive,RuledSurface):         if hasattr(primitive,"getUnderlyingPrimitive"):
963            return self.getBoundaryLoop().colocated(primitive.getBoundaryLoop())            if isinstance(primitive.getUnderlyingPrimitive(),RuledSurface):
964         else:               return self.getBoundaryLoop().isColocated(primitive.getBoundaryLoop())
965            return False         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):  def createRuledSurface(*curves):
974        """        """
# Line 688  def createRuledSurface(*curves): Line 976  def createRuledSurface(*curves):
976        """        """
977        return RuledSurface(CurveLoop(*curves))        return RuledSurface(CurveLoop(*curves))
978    
979  class PlaneSurface(Surface):  
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        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      """      """
# Line 701  class PlaneSurface(Surface): Line 1015  class PlaneSurface(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__()         if not isinstance(loop.getUnderlyingPrimitive(),CurveLoop):
        if not isinstance(loop,CurveLoop):  
1019             raise TypeError("argument loop needs to be a CurveLoop object.")             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         #TODO: check if lines are in a plane              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         returns the holes
1038         """         """
1039         return self.__holes         return self.__holes
1040    
1041      def getBoundaryLoop(self):      def getBoundaryLoop(self):
1042          """          """
1043          returns the loop defining the boundary          returns the loop defining the boundary
1044          """          """
1045          return self.__loop          return self.__loop
     def getPrimitives(self):  
         out=set([self]) | self.getBoundaryLoop().getPrimitives()  
         for i in self.getHoles(): out|=i.getPrimitives()  
         return out  
1046    
1047      def getGmshCommand(self):      def getGmshCommand(self,scaling_factor=1.):
1048            """
1049            returns the Gmsh command(s) to create the primitive
1050            """
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):      def substitute(self,sub_dict):
1063          """          """
# Line 743  class PlaneSurface(Surface): Line 1066  class PlaneSurface(Surface):
1066          with substituted arguments is returned.          with substituted arguments is returned.
1067          """          """
1068          if not sub_dict.has_key(self):          if not sub_dict.has_key(self):
1069              sub_dict[self]=CurveLoop(self.getBoundaryLoop().substitute(sub_dict),[ h.substitute(sub_dict) for h in self.getHoles()])              sub_dict[self]=PlaneSurface(self.getBoundaryLoop().substitute(sub_dict),[ h.substitute(sub_dict) for h in self.getHoles()])
1070          return sub_dict[self]          return sub_dict[self]
1071    
1072      def isColocated(self,primitive):      def isColocated(self,primitive):
1073         """         """
1074         returns True if each curve is collocted with a curve in primitive         returns True if each curve is collocted with a curve in primitive
1075         """         """
1076         if isinstance(primitive,PlaneSurface):         if hasattr(primitive,"getUnderlyingPrimitive"):
1077            if self.getBoundaryLoop().colocated(primitive.getBoundaryLoop()):            if isinstance(primitive.getUnderlyingPrimitive(),PlaneSurface):
1078               my_h=self.getHoles()               if self.getBoundaryLoop().isColocated(primitive.getBoundaryLoop()):
1079               h=primitive.getHoles()                  hs0=self.getHoles()
1080            else:                  hs1=primitive.getHoles()
1081               return False                  if len(hs0) == len(hs1):
1082         else:                      for h0 in hs0:
1083            return False                         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 ReversePlaneSurface(ReversePrimitive, Manifold2D):
1110        """
1111        creates a view onto a L{PlaneSurface} but with the reverse orientation
1112        """
1113        def __init__(self,surface):
1114           """
1115           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        def getBoundaryLoop(self):
1123           """
1124           returns the CurveLoop defining the RuledSurface
1125           """
1126           return -self.getUnderlyingPrimitive().getBoundaryLoop()
1127    
1128        def getHoles(self):
1129            """
1130            returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
1131            """
1132            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 818  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.927  
changed lines
  Added in v.931

  ViewVC Help
Powered by ViewVC 1.1.26