/[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

trunk/pycad/py_src/elementries.py revision 898 by gross, Sun Nov 12 23:56:26 2006 UTC trunk/pycad/py_src/primitives.py revision 931 by gross, Fri Jan 19 03:06:33 2007 UTC
# Line 1  Line 1 
1  # $Id:$  # $Id:$
2    
3  """  """
4  Geometrical Elementries  Geometrical Primitives
5    
6  the concept is inspired by gmsh and very much focused on the fact that  the concept is inspired by gmsh and very much focused on the fact that
7  the classes are used to wrk with gmsh.  the classes are used to wrk with gmsh.
# Line 25  __url__="http://www.iservo.edu.au/esys/e Line 25  __url__="http://www.iservo.edu.au/esys/e
25  __version__="$Revision:$"  __version__="$Revision:$"
26  __date__="$Date:$"  __date__="$Date:$"
27    
28  class Elementary(object):  import numarray
29    from transformations import _TYPE, Translation, Dilation, Transformation
30    
31    
32    def resetGlobalPrimitiveIdCounter():
33       """
34       initializes the global primitive ID counter
35       """
36       global global_primitive_id_counter
37       global_primitive_id_counter=1
38    
39    def setToleranceForColocation(tol=1.e-11):
40       """
41       set the global tolerance for colocation checks to tol
42       """
43       global global_tolerance_for_colocation
44       global_tolerance_for_colocation=tol
45    
46    def getToleranceForColocation():
47       """
48       returns the global tolerance for colocation checks
49       """
50       return global_tolerance_for_colocation
51    
52    resetGlobalPrimitiveIdCounter()
53    setToleranceForColocation()
54    
55    
56    class PrimitiveBase(object):
57      """      """
58      template for 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         pass         pass
65    
66  class Point(Elementary):      def __cmp__(self,other):
67           """
68           compares object with other by comparing the absolute value of the ID
69           """
70           if isinstance(other, PrimitiveBase):
71               return cmp(self.getID(),other.getID())
72           else:
73               return False
74        def getConstructionPoints(self):
75            """
76            returns the points used to construct the primitive
77            """
78            out=set()
79            for i in self.getPrimitives():
80               if isinstance(i,Point): out.add(i)
81            return list(out)
82    
83        def getPrimitives(self):
84            """
85            returns a list of primitives used to construct the primitive with no double entries
86            """
87            out=set()
88            return list(set([p for p in self.collectPrimitiveBases()]))
89    
90        def copy(self):
91           """
92           returns a deep copy of the object
93           """
94           return self.substitute({})
95    
96        def modifyBy(self,transformation):
97           """
98           modifies the coordinates by applying a transformation
99           """
100           for p in self.getConstructionPoints(): p.modifyBy(transformation)
101    
102        def __add__(self,other):
103            """
104            returns a new object shifted by other
105            """
106            return self.apply(Translation(numarray.array(other,_TYPE)))
107    
108        def __sub__(self,other):
109            """
110            returns a new object shifted by other
111            """
112            return self.apply(Translation(-numarray.array(other,_TYPE)))
113    
114        def __iadd__(self,other):
115            """
116            shifts the point by other
117            """
118            self.modifyBy(Translation(numarray.array(other,_TYPE)))
119            return self
120    
121        def __isub__(self,other):
122            """
123            shifts the point by -other
124            """
125            self.modifyBy(Translation(-numarray.array(other,_TYPE)))
126            return self
127    
128        def __imul__(self,other):
129            """
130            modifies object by applying L{Transformation} other. If other is not a L{Transformation} it will try convert it.
131            """
132            if isinstance(other,int) or isinstance(other,float):
133                trafo=Dilation(other)
134            elif isinstance(other,numarray.NumArray):
135                trafo=Translation(other)
136            elif isinstance(other,Transformation):
137                trafo=other
138            else:
139                raise TypeError, "cannot convert argument to Trnsformation class object."
140            self.modifyBy(trafo)
141            return self
142    
143        def __rmul__(self,other):
144            """
145            applies L{Transformation} other to object. If other is not a L{Transformation} it will try convert it.
146            """
147            if isinstance(other,int) or isinstance(other,float):
148                trafo=Dilation(other)
149            elif isinstance(other,numarray.NumArray):
150                trafo=Translation(other)
151            elif isinstance(other,Transformation):
152                trafo=other
153            else:
154                raise TypeError, "cannot convert argument to Transformation class object."
155            return self.apply(trafo)
156    
157    
158        def setLocalScale(self,factor=1.):
159           """
160           sets the local refinement factor
161           """
162           for p in self.getConstructionPoints(): p.setLocalScale(factor)
163    
164        def apply(self,transformation):
165            """
166            returns a new object by applying the transformation
167            """
168            out=self.copy()
169            out.modifyBy(transformation)
170            return out
171    
172    class Primitive(object):
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.):
219            """
220            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.")
225    
226        def substitute(self,sub_dict):
227            """
228            returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
229            If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
230            with substituted arguments is returned.
231    
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            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      """      """
332      def __init__(self,x=0.,y=0.,z=0.,local_scale=1.):      def __init__(self,x=0.,y=0.,z=0.,local_scale=1.):
333         """         """
334         creates a point with coorinates x,y,z with a relative refinement factor         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         if not local_scale > 0.:         Primitive.__init__(self)
338             raise ValueError("local_scale needs to be positive.")         self.setCoordinates(numarray.array([x,y,z],_TYPE))
339         self._x=numarray.array([x,y,z],numarray.Float64)         self.setLocalScale(local_scale)
340         self.setLocalScale(0.,local_scale)  
     def __str__(self):  
        return str(self._x)  
341      def setLocalScale(self,factor=1.):      def setLocalScale(self,factor=1.):
342           """
343           sets the local refinement factor
344           """
345           if factor<=0.:
346              raise ValueError("scaling factor must be positive.")
347         self.__local_scale=factor         self.__local_scale=factor
348    
349        def getLocalScale(self):
350           """
351           returns the local refinement factor
352           """
353           return self.__local_scale
354        def getCoordinates(self):
355           """
356           returns the coodinates of the point as L{numarray.NumArray} object
357           """
358           return self._x
359        def setCoordinates(self,x):
360           """
361           returns the coodinates of the point as L{numarray.NumArray} object
362           """
363           if not isinstance(x, numarray.NumArray):
364              self._x=numarray.array(x,_TYPE)
365           else:
366              self._x=x
367    
368        def collectPrimitiveBases(self):
369           """
370           returns primitives used to construct the primitive
371           """
372           return [self]
373    
374        def isColocated(self,primitive):
375           """
376           returns True if L{Point} primitive is colocation (same coordinates)
377           that means if |self-primitive| <= tol * max(|self|,|primitive|)
378           """
379           if isinstance(primitive,Point):
380              primitive=primitive.getCoordinates()
381              c=self.getCoordinates()
382              d=c-primitive
383              return numarray.dot(d,d)<=getToleranceForColocation()**2*max(numarray.dot(c,c),numarray.dot(primitive,primitive))
384           else:
385              return False
386    
387        def substitute(self,sub_dict):
388            """
389            returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
390            If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
391            with substituted arguments is returned.
392            """
393            if not sub_dict.has_key(self):
394               c=self.getCoordinates()
395               sub_dict[self]=Point(c[0],c[1],c[2],local_scale=self.getLocalScale())
396            return sub_dict[self]
397    
398        def modifyBy(self,transformation):
399            """
400            modifies the coordinates by applying a transformation
401            """
402            self.setCoordinates(transformation(self.getCoordinates()))
403    
404    
405        def getGmshCommand(self, local_scaling_factor=1.):
406            """
407            returns the Gmsh command(s) to create the primitive
408            """
409            c=self.getCoordinates()
410            return "Point(%s) = {%s , %s, %s , %s };"%(self.getID(),c[0],c[1],c[2], self.getLocalScale()*local_scaling_factor)
411    
412  class Curve(Elementary):      def __neg__(self):
413        """          """
414        a curve          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    class Manifold1D(PrimitiveBase):
419        """
420        general one-dimensional minifold in 3D defined by a start and end point.
421        """
422        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              create curve
452            """            """
453            defines a curve form a set of control points            Manifold1D.__init__(self)
454    
455        def __len__(self):
456            """            """
457            super(Curve, self).__init__()            returns the number of control points
458            l=len(args)            """
459            for i in range(l):            return len(self.getControlPoints())
               if not isinstance(args[i],Point):  
                  raise TypeError("%s-th argument is not a Point object.")  
           super(Curve, self).__init__(args[0],args[l-1])  
           self.__nodes=list(args)  
       def __len__(self):  
           return len(self.__nodes)  
460    
461        def getStart(self):      def getStartPoint(self):
462           """           """
463           returns start point           returns start point
464           """           """
465           return self.__nodes[0]           return self.getControlPoints()[0]
466    
467        def getEnd(self):      def getEndPoint(self):
468           """           """
469           returns end point           returns end point
470           """           """
471           return self.__nodes[-1]           return self.getControlPoints()[-1]
472    
473        def getNodes(self):      def getControlPoints(self):
474           """           """
475           returns a list of the nodes           returns a list of the points
476           """           """
477           return self.__nodes           raise NotImplementedError()
478    
479        def __neg__(self):  class Curve(CurveBase, Primitive):
480        """
481        a curve defined through a list of control points.
482        """
483        def __init__(self,*points):
484           """
485           defines a curve form control points
486           """
487           if len(points)<2:
488               raise ValueError("Curve needs at least two points")
489           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 the line segment with swapped start and end points           returns a list of the points
500           """           """
501           return Curve(self.__nodes[::-1])           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):
510            """
511            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            if not sub_dict.has_key(self):
516                new_p=[]
517                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):
530           """
531           returns True curves are on the same position
532           """
533           if hasattr(primitive,"getUnderlyingPrimitive"):
534             if isinstance(primitive.getUnderlyingPrimitive(),self.__class__):
535               if len(primitive) == len(self):
536                 cp0=self.getControlPoints()
537                 cp1=primitive.getControlPoints()
538                 match=True
539                 for i in range(len(cp0)):
540                    if not cp0[i].isColocated(cp1[i]):
541                       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
548           return False
549    
550    class ReverseCurve(CurveBase, ReversePrimitive):
551        """
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):
572        """
573        a spline curve defined through a list of control points.
574        """
575        def getGmshCommand(self,scaling_factor=1.):
576            """
577            returns the Gmsh command(s) to create the Curve
578            """
579            out=""
580            for i in self.getControlPoints():
581                if len(out)>0:
582                    out+=", %s"%i.getDirectedID()
583                else:
584                    out="%s"%i.getDirectedID()
585            return "Spline(%s) = {%s};"%(self.getID(),out)
586        
587    
588  class BezierCurve(Curve):  class BezierCurve(Curve):
589      """      """
590      a Bezier curve      a Bezier curve
591      """      """
592      def __neg__(self):      def getGmshCommand(self,scaling_factor=1.):
593         """          """
594         returns the line segment with swapped start and end points          returns the Gmsh command(s) to create the Curve
595         """          """
596         return BezierCurve(self.getNodesInReversedOrder())          out=""
597            for i in self.getControlPoints():
598                if len(out)>0:
599                    out+=", %s"%i.getDirectedID()
600                else:
601                    out="%s"%i.getDirectedID()
602            return "Bezier(%s) = {%s};"%(self.getID(),out)
603    
604  class BSplineCurve(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 __neg__(self):      def getGmshCommand(self,scaling_factor=1.):
609         """          """
610         returns the line segment with swapped start and end points          returns the Gmsh command(s) to create the Curve
611         """          """
612         return BSplineCurve(self.getNodesInReversedOrder())          out=""
613            for i in self.getControlPoints():
614                if len(out)>0:
615                    out+=", %s"%i.getDirectedID()
616                else:
617                    out="%s"%i.getDirectedID()
618            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 __neg__(self):      def __init__(self,*points):
625            """
626            defines a line with start and end point
627            """
628            if len(points)!=2:
629               raise TypeError("Line needs two points")
630            Curve.__init__(self,*points)
631        def getGmshCommand(self,scaling_factor=1.):
632            """
633            returns the Gmsh command(s) to create the Curve
634            """
635            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 line segment with swapped start and end points         returns the primitives used to construct the Curve
647         """         """
648         return Line(self.getEnd(),self.getStart())         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(Curve):  class Arc(ArcBase, Primitive):
662      """      """
663      defines an arc      defines an arc which is strictly, smaller than Pi
664      """      """
665      def __init__(self,center,start,end):      def __init__(self,center,start,end):
666         """         """
667         creates an arc by the start point, end point and center         creates an arc by the start point, end point and center
668         """         """
669         if not isinstance(center,Point):         if not isinstance(center,Point): raise TypeError("center needs to be a Point object.")
670             raise TypeError("center needs to be a Point object.")         if not isinstance(end,Point): raise TypeError("end needs to be a Point object.")
671         super(Arc, self).__init__(start,end)         if not isinstance(start,Point): raise TypeError("start needs to be a Point object.")
672           # TODO: check length of circle.
673           ArcBase.__init__(self)
674           Primitive.__init__(self)
675         self.__center=center         self.__center=center
676           self.__start=start
677           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 getCenter(self):      def getStartPoint(self):
685           """
686           returns start point
687           """
688           return self.__start
689    
690        def getEndPoint(self):
691           """
692           returns end point
693           """
694           return self.__end
695    
696        def getCenterPoint(self):
697         """         """
698         returns center         returns center
699         """         """
700         return self.__center         return self.__center
701      def __neg__(self):  
702        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 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):
719         """         """
720         returns the line segment with swapped start and end points         returns True curves are on the same position
721         """         """
722         return Arc(self.getCenter(),self.getEnd(),self.getStart())         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  class CurveLoop(Elementary):  class ReverseArc(ArcBase, ReversePrimitive):
730        """
731        defines an arc which is strictly, smaller than Pi
732      """      """
733      An oriented loop of curves.      def __init__(self,arc):
734           """
735           creates an arc by the start point, end point and center
736           """
737           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      The loop must be closed and the L{Curves}s should be oriented consistently.      def getEndPoint(self):
749           """
750           returns end point
751           """
752           return self.getUnderlyingPrimitive().getStartPoint()
753    
754        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 one-dimensional manifolds (= curves and arcs)
763    
764        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         for i in curves:              raise ValueError("at least two curves have to be given.")
772             if not isinstance(curves[i],Curve):         for i in range(len(curves)):
773                raise TypeError("%s-th argument is not a Curve object.")             if not isinstance(curves[i],Manifold1D):
774         if length(curves)>0:                raise TypeError("%s-th argument is not a Manifold1D object."%i)
775            for i in range(len(curves)-1):         # for the curves a loop:
776               if not curves[i].getEnd() == curves[i+1].getStart():         used=[ False for i in curves]
777                   raise ValueError("start point of %s-th curve does not match end point of %s-th curve."%(i,i+1))         self.__curves=[curves[0]]
778            if curves[0].getStart() == curves[len(curves)-1].getEnd():         used[0]=True
779                   raise ValueError("loop is not closed.")         while not min(used):
780         self.__curves=curves            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    
795      def getCurves(self):      def getCurves(self):
796           """
797           returns the curves defining the CurveLoop
798           """
799         return self.__curves         return self.__curves
800    
801      def __neg__(self):      def __neg__(self):
802         return CurveLoop([-c for c in self.__curves[::-1]])         """
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           return the number of curves in the CurveLoop
810           """
811           return len(self.getCurves())
812    
813    
814        def collectPrimitiveBases(self):
815           """
816           returns primitives used to construct the CurveLoop
817           """
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=""
856            for i in self.getCurves():
857                if len(out)>0:
858                    out+=", %s"%i.getDirectedID()
859                else:
860                    out="%s"%i.getDirectedID()
861            return "Line Loop(%s) = {%s};"%(self.getID(),out)
862    
863  class Surface(Elementary):  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        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 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 isinstance(loop,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:
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 getBoundaryLoop(self):  
        return self.__loop  
924      def __neg__(self):      def __neg__(self):
925         return Surface(-self.getBoundaryLoop())            """
926                    returns a view onto the suface with reversed ordering
927  class PlaneSurface(Surface):            """
928              return ReverseRuledSurface(self)
929    
930        def getBoundaryLoop(self):
931            """
932            returns the loop defining the outer boundary
933            """
934            return self.__loop
935    
936        def getBoundary(self):
937            """
938            returns a list of the one-dimensional manifolds forming the boundary of the Surface (including holes)
939            """
940            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        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 isinstance(holes[i],CurveLoop):              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    
1041        def getBoundaryLoop(self):
1042            """
1043            returns the loop defining the boundary
1044            """
1045            return self.__loop
1046    
1047        def getGmshCommand(self,scaling_factor=1.):
1048            """
1049            returns the Gmsh command(s) to create the primitive
1050            """
1051            out=""
1052            for i in self.getHoles():
1053                if len(out)>0:
1054                    out+=", %s"%i.getDirectedID()
1055                else:
1056                    out="%s"%i.getDirectedID()
1057            if len(out)>0:
1058              return "Plane Surface(%s) = {%s, %s};"%(self.getID(),self.getBoundaryLoop().getDirectedID(), out)
1059            else:
1060              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):      def __neg__(self):
1097         return PlaneSurface(-self.getBoundaryLoop(),holes=[-h for h in self.getHoles()] )            """
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 polygon from a list of line curves. The curves must form a closed loop.
1116         """         """
1117         creates a ruled surface from a         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 isinstance(loop,CurveLoop):         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 __neg__(self):          """
1130         return RuledSurface(-self.getBoundaryLoop())          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(Elementary):  #=========================================================================
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         for i in surfaces:              raise ValueError("at least two surfaces have to be given.")
1156             if not isinstance(surfaces[i],Curve):         for i in range(len(surfaces)):
1157                raise TypeError("%s-th argument is not a Curve object.")             if not isinstance(surfaces[i].getUnderlyingPrimitive(),Manifold2D):
1158         self.__surfaces=surfaces                raise TypeError("%s-th argument is not a Manifold2D object."%i)
1159           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    
1204      def getSurfaces(self):      def getSurfaces(self):
1205           """
1206           returns the surfaces defining the SurfaceLoop
1207           """
1208         return self.__surfaces         return self.__surfaces
1209    
1210      def __neg__(self):      def collectPrimitiveBases(self):
1211         return SurfaceLoop(-c for c in self.__surfaces[::-1])         """
1212           returns primitives used to construct the SurfaceLoop
1213           """
1214           out=[self]
1215           for c in self.getSurfaces(): out+=c.collectPrimitiveBases()
1216           return out
1217    
1218        def getGmshCommand(self,scaling_factor=1.):
1219            """
1220            returns the Gmsh command(s) to create the primitive
1221            """
1222            out=""
1223            for i in self.getSurfaces():
1224                if len(out)>0:
1225                    out+=", %s"%i.getDirectedID()
1226                else:
1227                    out="%s"%i.getDirectedID()
1228            return "Surface Loop(%s) = {%s};"%(self.getID(),out)
1229    
1230        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):      def __len__(self):
1284         return len(self.__surfaces)          return len(self.getUnderlyingPrimitive())
1285    
1286  class Volume(Elementary):  #==============================
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 279  class Volume(Elementary): Line 1313  class Volume(Elementary):
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 isinstance(loop,SurfaceLoop):  
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 isinstance(holes[i],SurfaceLoop):              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
     def __neg__(self):  
        return PlaneSurface(-self.getSurfaceLoop(),holes=[-h for h in self.getHoles()] )  
1335    
1336  class PropertySet(Elementary):      def getGmshCommand(self,scaling_factor=1.):
1337            """
1338            returns the Gmsh command(s) to create the primitive
1339            """
1340            out=""
1341            for i in self.getHoles():
1342                if len(out)>0:
1343                    out+=", %s"%i.getDirectedID()
1344                else:
1345                    out="%s"%i.getDirectedID()
1346            if len(out)>0:
1347              return "Volume(%s) = {%s, %s};"%(self.getID(),self.getSurfaceLoop().getDirectedID(), out)
1348            else:
1349              return "Volume(%s) = {%s};"%(self.getID(),self.getSurfaceLoop().getDirectedID())
1350    
1351        def substitute(self,sub_dict):
1352            """
1353            returns a copy of self with substitutes for the primitives used to construct it given by the dictionary C{sub_dict}.
1354            If a substitute for the object is given by C{sub_dict} the value is returned, otherwise a new instance
1355            with substituted arguments is returned.
1356            """
1357            if not sub_dict.has_key(self):
1358                sub_dict[self]=Volume(self.getSurfaceLoop().substitute(sub_dict),[ h.substitute(sub_dict) for h in self.getHoles()])
1359            return sub_dict[self]
1360    
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(PrimitiveBase):
1394      """      """
1395      defines a group L{Elementary} 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 collectPrimitiveBases(self):
1402            out=[self]+self.getBoundaryLoop().collectPrimitiveBases()
1403            for i in self.getHoles(): out+=i.collectPrimitiveBases()
1404            return out

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

  ViewVC Help
Powered by ViewVC 1.1.26