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

  ViewVC Help
Powered by ViewVC 1.1.26