source: inundation/ga/storm_surge/pyvolution/cell.py @ 479

Last change on this file since 479 was 478, checked in by duncan, 20 years ago

adding quadtree

File size: 9.8 KB
Line 
1
2#from point import Point
3#from waypoint import Waypoint
4from treenode import TreeNode
5import string, types, sys
6
7#FIXME remove point, waypoint
8
9#FIXME verts are added one at a time.
10#FIXME add max min x y in general_mesh
11
12#FIXME hacky.  maybe have as an attribute (or class att') for cell?
13MAX_WAY_POINTS = 4
14
15class Cell(TreeNode):
16    """class Cell
17
18    One cell on the planet surface delimited by southern, northern,
19    western, eastern boundaries.
20
21    Public Methods:
22        Prune()
23        Insert(Waypoint w)
24        Search(Point p, [keywords c])
25        Collapse()
26        Split()
27        Store()
28        Retrieve()
29        Count()
30    """
31 
32    def __init__(self, southern, northern, western, eastern, name):
33 
34        # Initialise base classes
35        TreeNode.__init__(self, string.lower(name))
36        # Initialise cell
37        self.southern = round(southern,5)   
38        self.northern = round(northern,5)
39        self.western = round(western,5)   
40        self.eastern = round(eastern,5)
41
42        # Corners
43        #self.SW = Point(self.southern,self.western)
44        #self.NW = Point(self.northern,self.western)
45        #self.NE = Point(self.northern,self.eastern)
46        #self.SE = Point(self.southern,self.eastern)
47
48        # The points in this cell     
49        self.points = []
50       
51    def __repr__(self):
52        return self.name 
53
54
55    def Spawn(self):
56        """Create four child cells unless they already exist
57        """
58
59        if self.children:
60            return
61        else:
62            self.children = []
63
64        # convenience variables
65        cs = self.southern   
66        cn = self.northern
67        cw = self.western   
68        ce = self.eastern
69
70        # create 4 child cells
71        self.AddChild(Cell((cn+cs)/2,cn,cw,(cw+ce)/2,self.name+'_nw'))
72        self.AddChild(Cell((cn+cs)/2,cn,(cw+ce)/2,ce,self.name+'_ne'))
73        self.AddChild(Cell(cs,(cn+cs)/2,(cw+ce)/2,ce,self.name+'_se'))
74        self.AddChild(Cell(cs,(cn+cs)/2,cw,(cw+ce)/2,self.name+'_sw'))
75     
76 
77
78    def Search(self, x,y):
79        """Find all waypoints within given radius from point P meeting
80        specified keywords (an optional comma-separated string).
81        """
82     
83        waypoints = []
84        if self.children:
85            for child in self:
86                if child.Contains(None,x=x,y=y):
87                     waypoints += child.Search(x,y)
88        else:
89            # Leaf node: Get actual waypoints
90            waypoints = self.Retrieve()
91           
92        return waypoints
93
94
95
96    def Contains(self, point_id, x= 0, y= 0):
97        """True only if P's coordinates lie within cell boundaries
98        """
99
100        if point_id <> None:
101            x = self.__class__.domain.coordinates[point_id][0]
102            y = self.__class__.domain.coordinates[point_id][1]
103        #print "x",x
104        #print "y",y
105        #print "self.southern",self.southern
106        #print "self.northern",self.northern
107        #print "self.western",self.western
108        #print "self.eastern",self.eastern
109        if y <  self.southern: return 0
110        if y >= self.northern: return 0
111        if x <  self.western:  return 0
112        if x >= self.eastern:  return 0
113        return 1
114   
115    def Contains_old(self, P):
116        """True only if P's coordinates lie within cell boundaries
117        """
118   
119        if P.latitude  <  self.southern: return 0
120        if P.latitude  >= self.northern: return 0
121        if P.longitude <  self.western:  return 0
122        if P.longitude >= self.eastern:  return 0
123        return 1
124   
125   
126    def Insert(self, W):
127        """Insert waypoint in existing tree structure below self
128           and split if necessary
129        """
130 
131        # Call insert for each element of a list of waypoints
132        if type(W) == types.ListType:
133            for w in W:
134                self.Insert(w)
135            return
136   
137        # Find appropriate cell
138        if self.children:
139            for child in self:
140                if child.Contains(W):
141                    child.Insert(W)
142                    break
143        else:
144            # Cell is a leaf cell. Insert waypoint in database table
145            if self.Contains(W):
146                self.Store(W)
147               
148                #FIXME? - where was this called before? 
149                self.Split()
150            else:
151                #FIXME rasie exception
152               raise "point not in region"
153
154
155    def Store(self,objects):
156        #import storage
157        #storage = storage.Factory()
158       
159        if type(objects) not in [types.ListType,types.TupleType]:
160            self.points.append(objects)
161        else:
162            self.points.extend(objects)
163           
164        #for object in objects:
165        #    storage.Store(self.name,object)
166
167
168
169    def Retrieve(self):
170         objects = []
171         if self.children is None:
172             objects = self.points
173         else: 
174             for child in self:
175                 objects += child.Retrieve()
176         return objects 
177
178
179    def Count(self, keywords=None):
180        """Retrieve number of stored objects beneath this node inclusive
181        """
182       
183        num_waypoint = 0
184        if self.children:
185            for child in self:
186                num_waypoint = num_waypoint + child.Count()
187        else:
188            num_waypoint = len(self.points)
189        return num_waypoint
190 
191
192    def Clear(self):
193        self.Prune()   # TreeNode method
194
195
196    def ClearLeafNode(self):
197        self.points = []
198
199
200
201    def Split(self, threshold=None):
202        """
203        Partition cell when number of contained waypoints exceeds
204        threshold.  All waypoints are then moved into correct
205        child cell.
206        """
207        if  threshold == None:
208            threshold = MAX_WAY_POINTS
209        #FIXME, mincellsize removed.  base it on side lenght, if needed
210       
211        if not self.children:               # Leaf cell
212            if self.Count() > threshold : #and self.radius > mincellsize:
213               
214                waypoints = self.Retrieve() # Get waypoints from leaf cell
215                self.Clear()                # and remove them from storage
216               
217                self.Spawn()                # Spawn child cells and move
218                for wp in waypoints:        # waypoints to appropriate child
219                    for child in self:
220                        if child.Contains(wp):
221                            child.Insert(wp) 
222                            break
223   
224        if self.children:                   # Parent cell
225            for child in self:              # Split (possibly newly created)
226                child.Split(threshold)      # child cells recursively
227               
228
229
230    def Collapse(self,threshold=None):
231        """
232        Collapse child cells into immediate parent if total number of contained waypoints
233        in subtree below is less than or equal to threshold.
234        All waypoints are then moved into parent cell and
235        children are removed. If self is a leaf node initially, do nothing.
236        """
237       
238        if threshold is None:
239            threshold = config['maxwaypoints']
240
241        if self.children:                   # Parent cell   
242            if self.Count() <= threshold:   # Collapse
243                waypoints = self.Retrieve() # Get all waypoints from child cells
244                self.Clear()                # Remove children, self is now a leaf node
245                self.Insert(waypoints)      # Insert all waypoints in local storage
246            else:                         
247                for child in self:          # Check if any sub tree can be collapsed
248                    child.Collapse(threshold)
249
250
251    def Get_tree(self,depth=0):
252        """Traverse tree below self
253           Print for each node the name and
254           if it is a leaf the number of objects
255        """
256        s = ''
257        if depth == 0:
258            s = '\n'
259           
260        s += "%s%s:" % ('  '*depth, self.name)
261        if self.children:
262            s += '\n'
263            for child in self.children:
264                s += child.Get_tree(depth+1)
265        else:
266            s += '(#wp=%d)\n' %(self.Count())
267
268        return s
269
270    def Show(self,depth=0):
271        """Traverse tree below self
272           Print for each node the name and
273           if it is a leaf the number of objects
274        """
275        if depth == 0:
276            print 
277        print "%s%s:" % ('  '*depth, self.name),
278        if self.children:
279            print
280            for child in self.children:
281                child.Show(depth+1)
282        else:
283            print '#wp=%d, c=(%.2f,%.2f)'\
284                  %(self.Count(), self.latitude, self.longitude)
285
286           
287
288    def ShowAll(self,depth=0):
289        """Traverse tree below self
290           Print for each node the name and if it is a leaf all its objects
291        """
292        if depth == 0:
293            print 
294        print "%s%s:" % ('  '*depth, self.name),
295        if self.children:
296            print
297            for child in self.children:
298                child.ShowAll(depth+1)
299        else:
300            print '%s' %self.Retrieve()
301
302
303    def Stats(self,depth=0,min_rad=sys.maxint,max_depth=0,max_points=0):
304        """Traverse tree below self and find minimal cell radius,
305           maximumtree depth and maximum number of waypoints per leaf.
306        """
307
308        if self.children:
309            for child in self.children:
310                min_rad, max_depth, max_points =\
311                         child.Stats(depth+1,min_rad,max_depth,max_points)
312        else:
313            #FIXME remvoe radius stuff
314            min_rad = sys.maxint
315            #if self.radius < min_rad:   min_rad = self.radius
316            if depth > max_depth:       max_depth = depth
317            num_points = self.Count()
318            if num_points > max_points: max_points = num_points
319
320        return min_rad, max_depth, max_points   
321
322    def initialise(cls,domain):
323        cls.domain = domain
324
325    initialise = classmethod(initialise)
Note: See TracBrowser for help on using the repository browser.