/[escript]/branches/arrexp_2137_win_merge/pycad/py_src/primitives.py
ViewVC logotype

Annotation of /branches/arrexp_2137_win_merge/pycad/py_src/primitives.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2214 - (hide annotations)
Wed Jan 14 03:39:41 2009 UTC (10 years, 7 months ago) by jfenwick
File MIME type: text/x-python
File size: 49902 byte(s)
Accepting some changes which should be ok.

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

  ViewVC Help
Powered by ViewVC 1.1.26