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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1312 - (hide annotations)
Mon Sep 24 06:18:44 2007 UTC (11 years, 11 months ago) by ksteube
File MIME type: text/x-python
File size: 49275 byte(s)
The MPI branch is hereby closed. All future work should be in trunk.

Previously in revision 1295 I merged the latest changes to trunk into trunk-mpi-branch.
In this revision I copied all files from trunk-mpi-branch over the corresponding
trunk files. I did not use 'svn merge', it was a copy.

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

  ViewVC Help
Powered by ViewVC 1.1.26