1 | |
---|
2 | SET_COLOUR='red' |
---|
3 | |
---|
4 | class Triangle(MeshObject): |
---|
5 | """ |
---|
6 | A triangle element, defined by 3 vertices. |
---|
7 | Attributes based on the Triangle program. |
---|
8 | """ |
---|
9 | |
---|
10 | def __init__(self, vertex1, vertex2, vertex3, attribute = None, neighbors = None ): |
---|
11 | """ |
---|
12 | Vertices, the initial arguments, are listed in counterclockwise order. |
---|
13 | """ |
---|
14 | self.vertices= [vertex1,vertex2, vertex3 ] |
---|
15 | |
---|
16 | if attribute is None: |
---|
17 | self.attribute ="" |
---|
18 | else: |
---|
19 | self.attribute = attribute #this is a string |
---|
20 | |
---|
21 | if neighbors is None: |
---|
22 | self.neighbors=[] |
---|
23 | else: |
---|
24 | self.neighbors=neighbors |
---|
25 | |
---|
26 | def replace(self,new_triangle): |
---|
27 | self = new_triangle |
---|
28 | |
---|
29 | def longestSideID(self): |
---|
30 | ax = self.vertices[0].x |
---|
31 | ay = self.vertices[0].y |
---|
32 | |
---|
33 | bx = self.vertices[1].x |
---|
34 | by = self.vertices[1].y |
---|
35 | |
---|
36 | cx = self.vertices[2].x |
---|
37 | cy = self.vertices[2].y |
---|
38 | |
---|
39 | lenA = ((cx-bx)**2+(cy-by)**2)**0.5 |
---|
40 | lenB = ((ax-cx)**2+(ay-cy)**2)**0.5 |
---|
41 | lenC = ((bx-ax)**2+(by-ay)**2)**0.5 |
---|
42 | |
---|
43 | len = [lenA,lenB,lenC] |
---|
44 | return len.index(max(len)) |
---|
45 | |
---|
46 | def rotate(self,offset): |
---|
47 | """ |
---|
48 | permute the order of the sides of the triangle |
---|
49 | offset must be 0,1 or 2 |
---|
50 | """ |
---|
51 | |
---|
52 | if offset == 0: |
---|
53 | pass |
---|
54 | else: |
---|
55 | if offset == 1: |
---|
56 | self.vertices = [self.vertices[1],self.vertices[2],self.vertices[0]] |
---|
57 | self.neighbors = [self.neighbors[1],self.neighbors[2],self.neighbors[0]] |
---|
58 | if offset == 2: |
---|
59 | self.vertices = [self.vertices[2],self.vertices[0],self.vertices[1]] |
---|
60 | self.neighbors = [self.neighbors[2],self.neighbors[0],self.neighbors[1]] |
---|
61 | |
---|
62 | def rotate_longest_side(self): |
---|
63 | self.rotate(self.longestSideID()) |
---|
64 | |
---|
65 | def getVertices(self): |
---|
66 | return self.vertices |
---|
67 | |
---|
68 | def get_vertices(self): |
---|
69 | """ |
---|
70 | Return a list of the vertices. The x and y values will be relative |
---|
71 | Easting and Northings for the zone of the current geo_ref. |
---|
72 | """ |
---|
73 | return self.vertices |
---|
74 | |
---|
75 | def calcArea(self): |
---|
76 | ax = self.vertices[0].x |
---|
77 | ay = self.vertices[0].y |
---|
78 | |
---|
79 | bx = self.vertices[1].x |
---|
80 | by = self.vertices[1].y |
---|
81 | |
---|
82 | cx = self.vertices[2].x |
---|
83 | cy = self.vertices[2].y |
---|
84 | |
---|
85 | return abs((bx*ay-ax*by)+(cx*by-bx*cy)+(ax*cy-cx*ay))/2 |
---|
86 | |
---|
87 | def calcP(self): |
---|
88 | #calculate the perimeter |
---|
89 | ax = self.vertices[0].x |
---|
90 | ay = self.vertices[0].y |
---|
91 | |
---|
92 | bx = self.vertices[1].x |
---|
93 | by = self.vertices[1].y |
---|
94 | |
---|
95 | cx = self.vertices[2].x |
---|
96 | cy = self.vertices[2].y |
---|
97 | |
---|
98 | a = ((cx-bx)**2+(cy-by)**2)**0.5 |
---|
99 | b = ((ax-cx)**2+(ay-cy)**2)**0.5 |
---|
100 | c = ((bx-ax)**2+(by-ay)**2)**0.5 |
---|
101 | |
---|
102 | return a+b+c |
---|
103 | |
---|
104 | def setNeighbors(self,neighbor1 = None, neighbor2 = None, neighbor3 = None): |
---|
105 | """ |
---|
106 | neighbor1 is the triangle opposite vertex1 and so on. |
---|
107 | Null represents no neighbor |
---|
108 | """ |
---|
109 | self.neighbors = [neighbor1, neighbor2, neighbor3] |
---|
110 | |
---|
111 | def setAttribute(self,attribute): |
---|
112 | """ |
---|
113 | neighbor1 is the triangle opposite vertex1 and so on. |
---|
114 | Null represents no neighbor |
---|
115 | """ |
---|
116 | self.attribute = attribute #this is a string |
---|
117 | |
---|
118 | def __repr__(self): |
---|
119 | return "[%s,%s]" % (self.vertices,self.attribute) |
---|
120 | |
---|
121 | |
---|
122 | def draw(self, canvas, tags, scale=1, xoffset = 0, yoffset =0, colour = "green"): |
---|
123 | """ |
---|
124 | Draw a triangle, returning the objectID |
---|
125 | """ |
---|
126 | return canvas.create_polygon(scale*(self.vertices[1].x + xoffset), |
---|
127 | scale*-1*(self.vertices[1].y + yoffset), |
---|
128 | scale*(self.vertices[0].x + xoffset), |
---|
129 | scale*-1*(self.vertices[0].y + yoffset), |
---|
130 | scale*(self.vertices[2].x + xoffset), |
---|
131 | scale*-1*(self.vertices[2].y + yoffset), |
---|
132 | tags = tags, |
---|
133 | outline = colour,fill = '') |
---|
134 | |
---|
135 | |
---|
136 | self.setID={} |
---|
137 | #a dictionary of names. |
---|
138 | #multiple sets are allowed, but the gui does not yet |
---|
139 | #support this |
---|
140 | |
---|
141 | self.setID['None']=0 |
---|
142 | #contains the names of the sets pointing to the indexes |
---|
143 | #in the list. |
---|
144 | |
---|
145 | self.sets=[[]] |
---|
146 | #Contains the lists of triangles (triangle sets) |
---|
147 | |
---|
148 | ################## |
---|
149 | |
---|
150 | |
---|
151 | def refineSet(self,setName): |
---|
152 | Triangles = self.sets[self.setID[setName]] |
---|
153 | Refine(self,Triangles) |
---|
154 | |
---|
155 | def selectAllTriangles(self): |
---|
156 | A=[] |
---|
157 | A.extend(self.meshTriangles) |
---|
158 | if not('All' in self.setID.keys()): |
---|
159 | self.setID['All']=len(self.sets) |
---|
160 | self.sets.append(A) |
---|
161 | else: |
---|
162 | self.sets[self.setID['All']]=A |
---|
163 | return 'All' |
---|
164 | # and objectIDs |
---|
165 | |
---|
166 | |
---|
167 | def clearSelection(self): |
---|
168 | A = [] |
---|
169 | if not('None' in self.setID.keys()): |
---|
170 | self.setID['None']=len(self.sets) |
---|
171 | self.sets.append(A) |
---|
172 | return 'None' |
---|
173 | |
---|
174 | def drawSet(self,canvas,setName,SCALE,colour=SET_COLOUR): |
---|
175 | #FIXME Draws over previous triangles - may bloat canvas |
---|
176 | Triangles = self.sets[self.setID[setName]] |
---|
177 | for triangle in Triangles: |
---|
178 | triangle.draw(canvas,1, |
---|
179 | scale = SCALE, |
---|
180 | colour = colour) |
---|
181 | |
---|
182 | def undrawSet(self,canvas,setName,SCALE,colour='green'): |
---|
183 | #FIXME Draws over previous lines - may bloat canvas |
---|
184 | Triangles = self.sets[self.setID[setName]] |
---|
185 | for triangle in Triangles: |
---|
186 | triangle.draw(canvas,1, |
---|
187 | scale = SCALE, |
---|
188 | colour = colour) |
---|
189 | |
---|
190 | def weed(self,Vertices,Segments): |
---|
191 | #Depreciated |
---|
192 | #weed out existing duplicates |
---|
193 | print 'len(self.getUserSegments())' |
---|
194 | print len(self.getUserSegments()) |
---|
195 | print 'len(self.getUserVertices())' |
---|
196 | print len(self.getUserVertices()) |
---|
197 | |
---|
198 | point_keys = {} |
---|
199 | for vertex in Vertices: |
---|
200 | point = (vertex.x,vertex.y) |
---|
201 | point_keys[point]=vertex |
---|
202 | #inlined would looks very ugly |
---|
203 | |
---|
204 | line_keys = {} |
---|
205 | for segment in Segments: |
---|
206 | vertex1 = segment.vertices[0] |
---|
207 | vertex2 = segment.vertices[1] |
---|
208 | point1 = (vertex1.x,vertex1.y) |
---|
209 | point2 = (vertex2.x,vertex2.y) |
---|
210 | segment.vertices[0]=point_keys[point1] |
---|
211 | segment.vertices[1]=point_keys[point2] |
---|
212 | vertex1 = segment.vertices[0] |
---|
213 | vertex2 = segment.vertices[1] |
---|
214 | point1 = (vertex1.x,vertex1.y) |
---|
215 | point2 = (vertex2.x,vertex2.y) |
---|
216 | line1 = (point1,point2) |
---|
217 | line2 = (point2,point1) |
---|
218 | if not (line_keys.has_key(line1) \ |
---|
219 | or line_keys.has_key(line2)): |
---|
220 | line_keys[line1]=segment |
---|
221 | Vertices=point_keys.values() |
---|
222 | Segments=line_keys.values() |
---|
223 | return Vertices,Segments |
---|
224 | |
---|
225 | def segs_to_dict(self,segments): |
---|
226 | dict={} |
---|
227 | for segment in segments: |
---|
228 | vertex1 = segment.vertices[0] |
---|
229 | vertex2 = segment.vertices[1] |
---|
230 | point1 = (vertex1.x,vertex1.y) |
---|
231 | point2 = (vertex2.x,vertex2.y) |
---|
232 | line = (point1,point2) |
---|
233 | dict[line]=segment |
---|
234 | return dict |
---|
235 | |
---|
236 | def seg2line(self,s): |
---|
237 | return ((s.vertices[0].x,s.vertices[0].y,)\ |
---|
238 | (s.vertices[1].x,s.vertices[1].y)) |
---|
239 | |
---|
240 | def line2seg(self,line,tag=None): |
---|
241 | point0 = self.point2ver(line[0]) |
---|
242 | point1 = self.point2ver(line[1]) |
---|
243 | return Segment(point0,point1,tag=tag) |
---|
244 | |
---|
245 | def ver2point(self,vertex): |
---|
246 | return (vertex.x,vertex.y) |
---|
247 | |
---|
248 | def point2ver(self,point): |
---|
249 | return Vertex(point[0],point[1]) |
---|
250 | |
---|
251 | def smooth_polySet(self,min_radius=0.05): |
---|
252 | #for all pairs of connecting segments: |
---|
253 | # propose a new segment that replaces the 2 |
---|
254 | |
---|
255 | # If the difference between the new segment |
---|
256 | # and the old lines is small: replace the |
---|
257 | # old lines. |
---|
258 | |
---|
259 | seg2line = self.seg2line |
---|
260 | ver2point= self.ver2point |
---|
261 | line2seg = self.line2seg |
---|
262 | point2ver= self.point2ver |
---|
263 | |
---|
264 | #create dictionaries of lines -> segments |
---|
265 | userSegments = self.segs_to_dict(self.userSegments) |
---|
266 | alphaSegments = self.segs_to_dict(self.alphaUserSegments) |
---|
267 | |
---|
268 | #lump user and alpha segments |
---|
269 | for key in alphaSegments.keys(): |
---|
270 | userSegments[key]=alphaSegments[key] |
---|
271 | |
---|
272 | #point_keys = tuple -> vertex |
---|
273 | #userVertices = vertex -> [line,line] - lines from that node |
---|
274 | point_keys = {} |
---|
275 | userVertices={} |
---|
276 | for vertex in self.getUserVertices(): |
---|
277 | point = ver2point(vertex) |
---|
278 | if not point_keys.has_key(point): |
---|
279 | point_keys[point]=vertex |
---|
280 | userVertices[vertex]=[] |
---|
281 | for key in userSegments.keys(): |
---|
282 | line = key |
---|
283 | point_0 = key[0] |
---|
284 | point_1 = key[1] |
---|
285 | userVertices[point_keys[point_0]].append(line) |
---|
286 | userVertices[point_keys[point_1]].append(line) |
---|
287 | |
---|
288 | for point in point_keys.keys(): |
---|
289 | try: |
---|
290 | #removed keys can cause keyerrors |
---|
291 | vertex = point_keys[point] |
---|
292 | lines = userVertices[vertex] |
---|
293 | |
---|
294 | #if there are 2 lines on the node |
---|
295 | if len(lines)==2: |
---|
296 | line_0 = lines[0] |
---|
297 | line_1 = lines[1] |
---|
298 | |
---|
299 | #if the tags are the the same on the 2 lines |
---|
300 | if userSegments[line_0].tag == userSegments[line_1].tag: |
---|
301 | tag = userSegments[line_0].tag |
---|
302 | |
---|
303 | #point_a is one of the next nodes, point_b is the other |
---|
304 | if point==line_0[0]: |
---|
305 | point_a = line_0[1] |
---|
306 | if point==line_0[1]: |
---|
307 | point_a = line_0[0] |
---|
308 | if point==line_1[0]: |
---|
309 | point_b = line_1[1] |
---|
310 | if point==line_1[1]: |
---|
311 | point_b = line_1[0] |
---|
312 | |
---|
313 | |
---|
314 | #line_2 is proposed |
---|
315 | line_2 = (point_a,point_b) |
---|
316 | |
---|
317 | #calculate the area of the triangle between |
---|
318 | #the two existing segments and the proposed |
---|
319 | #new segment |
---|
320 | ax = point_a[0] |
---|
321 | ay = point_a[1] |
---|
322 | bx = point_b[0] |
---|
323 | by = point_b[1] |
---|
324 | cx = point[0] |
---|
325 | cy = point[1] |
---|
326 | area=abs((bx*ay-ax*by)+(cx*by-bx*cy)+(ax*cy-cx*ay))/2 |
---|
327 | |
---|
328 | #calculate the perimeter |
---|
329 | len_a = ((cx-bx)**2+(cy-by)**2)**0.5 |
---|
330 | len_b = ((ax-cx)**2+(ay-cy)**2)**0.5 |
---|
331 | len_c = ((bx-ax)**2+(by-ay)**2)**0.5 |
---|
332 | perimeter = len_a+len_b+len_c |
---|
333 | |
---|
334 | #calculate the radius |
---|
335 | r = area/(2*perimeter) |
---|
336 | |
---|
337 | #if the radius is small: then replace the existing |
---|
338 | #segments with the new one |
---|
339 | if r < min_radius: |
---|
340 | if len_c < min_radius: append = False |
---|
341 | else: append = True |
---|
342 | #if the new seg is also time, don't add it |
---|
343 | if append: |
---|
344 | segment = self.line2seg(line_2,tag=tag) |
---|
345 | |
---|
346 | list_a=userVertices[point_keys[point_a]] |
---|
347 | list_b=userVertices[point_keys[point_b]] |
---|
348 | |
---|
349 | if line_0 in list_a: |
---|
350 | list_a.remove(line_0) |
---|
351 | else: |
---|
352 | list_a.remove(line_1) |
---|
353 | |
---|
354 | if line_0 in list_b: |
---|
355 | list_b.remove(line_0) |
---|
356 | else: |
---|
357 | list_b.remove(line_1) |
---|
358 | |
---|
359 | if append: |
---|
360 | list_a.append(line_2) |
---|
361 | list_b.append(line_2) |
---|
362 | else: |
---|
363 | if len(list_a)==0: |
---|
364 | userVertices.pop(point_keys[point_a]) |
---|
365 | point_keys.pop(point_a) |
---|
366 | if len(list_b)==0: |
---|
367 | userVertices.pop(point_keys[point_b]) |
---|
368 | point_keys.pop(point_b) |
---|
369 | |
---|
370 | userVertices.pop(point_keys[point]) |
---|
371 | point_keys.pop(point) |
---|
372 | userSegments.pop(line_0) |
---|
373 | userSegments.pop(line_1) |
---|
374 | |
---|
375 | if append: |
---|
376 | userSegments[line_2]=segment |
---|
377 | except: |
---|
378 | pass |
---|
379 | |
---|
380 | #self.userVerticies = userVertices.keys() |
---|
381 | #self.userSegments = [] |
---|
382 | #for key in userSegments.keys(): |
---|
383 | # self.userSegments.append(userSegments[key]) |
---|
384 | #self.alphaUserSegments = [] |
---|
385 | |
---|
386 | self.userVerticies = [] |
---|
387 | self.userSegments = [] |
---|
388 | self.alphaUserSegments = [] |
---|
389 | |
---|
390 | return userVertices,userSegments,alphaSegments |
---|
391 | |
---|
392 | def triangles_to_polySet(self,setName): |
---|
393 | #self.smooth_polySet() |
---|
394 | |
---|
395 | seg2line = self.seg2line |
---|
396 | ver2point= self.ver2point |
---|
397 | line2seg = self.line2seg |
---|
398 | point2ver= self.point2ver |
---|
399 | |
---|
400 | from Numeric import array,allclose |
---|
401 | #turn the triangles into a set |
---|
402 | Triangles = self.sets[self.setID[setName]] |
---|
403 | Triangles_dict = {} |
---|
404 | for triangle in Triangles: |
---|
405 | Triangles_dict[triangle]=None |
---|
406 | |
---|
407 | |
---|
408 | #create a dict of points to vertexes (tuple -> object) |
---|
409 | #also create a set of vertexes (object -> True) |
---|
410 | point_keys = {} |
---|
411 | userVertices={} |
---|
412 | for vertex in self.getUserVertices(): |
---|
413 | point = ver2point(vertex) |
---|
414 | if not point_keys.has_key(point): |
---|
415 | point_keys[point]=vertex |
---|
416 | userVertices[vertex]=True |
---|
417 | |
---|
418 | #create a dict of lines to segments (tuple -> object) |
---|
419 | userSegments = self.segs_to_dict(self.userSegments) |
---|
420 | #append the userlines in an affine linespace |
---|
421 | affine_lines = Affine_Linespace() |
---|
422 | for line in userSegments.keys(): |
---|
423 | affine_lines.append(line) |
---|
424 | alphaSegments = self.segs_to_dict(self.alphaUserSegments) |
---|
425 | for line in alphaSegments.keys(): |
---|
426 | affine_lines.append(line) |
---|
427 | |
---|
428 | for triangle in Triangles: |
---|
429 | for i in (0,1,2): |
---|
430 | #for every triangles neighbour: |
---|
431 | if not Triangles_dict.has_key(triangle.neighbors[i]): |
---|
432 | #if the neighbour is not in the set: |
---|
433 | a = triangle.vertices[i-1] |
---|
434 | b = triangle.vertices[i-2] |
---|
435 | #Get possible matches: |
---|
436 | point_a = ver2point(a) |
---|
437 | point_b = ver2point(b) |
---|
438 | midpoint = ((a.x+b.x)/2,(a.y+b.y)/2) |
---|
439 | line = (point_a,point_b) |
---|
440 | tag = None |
---|
441 | |
---|
442 | |
---|
443 | #this bit checks for matching lines |
---|
444 | possible_lines = affine_lines[line] |
---|
445 | possible_lines = unique(possible_lines) |
---|
446 | found = 0 |
---|
447 | for user_line in possible_lines: |
---|
448 | if self.point_on_line(midpoint,user_line): |
---|
449 | found+=1 |
---|
450 | assert found<2 |
---|
451 | if userSegments.has_key(user_line): |
---|
452 | parent_segment = userSegments.pop(user_line) |
---|
453 | if alphaSegments.has_key(user_line): |
---|
454 | parent_segment = alphaSegments.pop(user_line) |
---|
455 | tag = parent_segment.tag |
---|
456 | offspring = [line] |
---|
457 | offspring.extend(self.subtract_line(user_line, |
---|
458 | line)) |
---|
459 | affine_lines.remove(user_line) |
---|
460 | for newline in offspring: |
---|
461 | line_vertices = [] |
---|
462 | for point in newline: |
---|
463 | if point_keys.has_key(point): |
---|
464 | vert = point_keys[point] |
---|
465 | else: |
---|
466 | vert = Vertex(point[0],point[1]) |
---|
467 | userVertices[vert]=True |
---|
468 | point_keys[point]=vert |
---|
469 | line_vertices.append(vert) |
---|
470 | segment = Segment(line_vertices[0], |
---|
471 | line_vertices[1],tag) |
---|
472 | userSegments[newline]=segment |
---|
473 | affine_lines.append(newline) |
---|
474 | #break |
---|
475 | assert found<2 |
---|
476 | |
---|
477 | |
---|
478 | |
---|
479 | #if no matching lines |
---|
480 | if not found: |
---|
481 | line_vertices = [] |
---|
482 | for point in line: |
---|
483 | if point_keys.has_key(point): |
---|
484 | vert = point_keys[point] |
---|
485 | else: |
---|
486 | vert = Vertex(point[0],point[1]) |
---|
487 | userVertices[vert]=True |
---|
488 | point_keys[point]=vert |
---|
489 | line_vertices.append(vert) |
---|
490 | segment = Segment(line_vertices[0], |
---|
491 | line_vertices[1],tag) |
---|
492 | userSegments[line]=segment |
---|
493 | affine_lines.append(line) |
---|
494 | |
---|
495 | self.userVerticies = [] |
---|
496 | self.userSegments = [] |
---|
497 | self.alphaUserSegments = [] |
---|
498 | |
---|
499 | return userVertices,userSegments,alphaSegments |
---|
500 | |
---|
501 | def subtract_line(self,parent,child): |
---|
502 | #Subtracts child from parent |
---|
503 | #Requires that the child is a |
---|
504 | #subline of parent to work. |
---|
505 | |
---|
506 | from Numeric import allclose,dot,array |
---|
507 | A= parent[0] |
---|
508 | B= parent[1] |
---|
509 | a = child[0] |
---|
510 | b = child[1] |
---|
511 | |
---|
512 | A_array = array(parent[0]) |
---|
513 | B_array = array(parent[1]) |
---|
514 | a_array = array(child[0]) |
---|
515 | b_array = array(child[1]) |
---|
516 | |
---|
517 | assert not A == B |
---|
518 | assert not a == b |
---|
519 | |
---|
520 | answer = [] |
---|
521 | |
---|
522 | #if the new line does not share a |
---|
523 | #vertex with the old one |
---|
524 | if not (allclose(A_array,a_array)\ |
---|
525 | or allclose(B_array,b_array)\ |
---|
526 | or allclose(A_array,b_array)\ |
---|
527 | or allclose(a_array,B_array)): |
---|
528 | if dot(A_array-a_array,A_array-a_array) \ |
---|
529 | < dot(A_array-b_array,A_array-b_array): |
---|
530 | sibling1 = (A,a) |
---|
531 | sibling2 = (B,b) |
---|
532 | return [sibling1,sibling2] |
---|
533 | else: |
---|
534 | sibling1 = (A,b) |
---|
535 | sibling2 = (B,a) |
---|
536 | return [sibling1,sibling2] |
---|
537 | |
---|
538 | elif allclose(A_array,a_array): |
---|
539 | if allclose(B_array,b_array): |
---|
540 | return [] |
---|
541 | else: |
---|
542 | sibling = (b,B) |
---|
543 | return [sibling] |
---|
544 | elif allclose(B_array,b_array): |
---|
545 | sibling = (a,A) |
---|
546 | return [sibling] |
---|
547 | |
---|
548 | elif allclose(A_array,b_array): |
---|
549 | if allclose(B,a): |
---|
550 | return [] |
---|
551 | else: |
---|
552 | sibling = (a,B) |
---|
553 | return [sibling] |
---|
554 | elif allclose(a_array,B_array): |
---|
555 | sibling = (b,A) |
---|
556 | return [sibling] |
---|
557 | |
---|
558 | def point_on_line(self,point,line): |
---|
559 | #returns true within a tolerance of 3 degrees |
---|
560 | x=point[0] |
---|
561 | y=point[1] |
---|
562 | x0=line[0][0] |
---|
563 | x1=line[1][0] |
---|
564 | y0=line[0][1] |
---|
565 | y1=line[1][1] |
---|
566 | from Numeric import array, dot, allclose |
---|
567 | from math import sqrt |
---|
568 | tol = 3. #DEGREES |
---|
569 | tol = tol*3.1415/180 |
---|
570 | |
---|
571 | a = array([x - x0, y - y0]) |
---|
572 | a_normal = array([a[1], -a[0]]) |
---|
573 | len_a_normal = sqrt(sum(a_normal**2)) |
---|
574 | |
---|
575 | b = array([x1 - x0, y1 - y0]) |
---|
576 | len_b = sqrt(sum(b**2)) |
---|
577 | |
---|
578 | if abs(dot(a_normal, b)/(len_b*len_a_normal))< tol: |
---|
579 | #Point is somewhere on the infinite extension of the line |
---|
580 | |
---|
581 | len_a = sqrt(sum(a**2)) |
---|
582 | if dot(a, b) >= 0 and len_a <= len_b: |
---|
583 | return True |
---|
584 | else: |
---|
585 | return False |
---|
586 | else: |
---|
587 | return False |
---|
588 | |
---|
589 | def line_length(self,line): |
---|
590 | x0=line[0][0] |
---|
591 | x1=line[1][0] |
---|
592 | y0=line[0][1] |
---|
593 | y1=line[1][1] |
---|
594 | return ((x1-x0)**2-(y1-y0)**2)**0.5 |
---|
595 | |
---|
596 | def threshold(self,setName,min=None,max=None,attribute_name='elevation'): |
---|
597 | """ |
---|
598 | threshold using d |
---|
599 | """ |
---|
600 | triangles = self.sets[self.setID[setName]] |
---|
601 | A = [] |
---|
602 | |
---|
603 | if attribute_name in self.attributeTitles: |
---|
604 | i = self.attributeTitles.index(attribute_name) |
---|
605 | else: i = -1#no attribute |
---|
606 | if not max == None: |
---|
607 | for t in triangles: |
---|
608 | if (min<self.av_att(t,i)<max): |
---|
609 | A.append(t) |
---|
610 | else: |
---|
611 | for t in triangles: |
---|
612 | if (min<self.av_att(t,i)): |
---|
613 | A.append(t) |
---|
614 | self.sets[self.setID[setName]] = A |
---|
615 | |
---|
616 | def general_threshold(self,setName,min=None,max=None\ |
---|
617 | ,attribute_name = 'elevation',function=None): |
---|
618 | """ |
---|
619 | Thresholds the triangles |
---|
620 | """ |
---|
621 | from visual.graph import arange,ghistogram,color as colour |
---|
622 | triangles = self.sets[self.setID[setName]] |
---|
623 | A = [] |
---|
624 | data=[] |
---|
625 | #data is for the graph |
---|
626 | |
---|
627 | if attribute_name in self.attributeTitles: |
---|
628 | i = self.attributeTitles.index(attribute_name) |
---|
629 | else: i = -1 |
---|
630 | if not max == None: |
---|
631 | for t in triangles: |
---|
632 | value=function(t,i) |
---|
633 | if (min<value<max): |
---|
634 | A.append(t) |
---|
635 | data.append(value) |
---|
636 | else: |
---|
637 | for t in triangles: |
---|
638 | value=function(t,i) |
---|
639 | if (min<value): |
---|
640 | A.append(t) |
---|
641 | data.append(value) |
---|
642 | self.sets[self.setID[setName]] = A |
---|
643 | |
---|
644 | if self.visualise_graph: |
---|
645 | if len(data)>0: |
---|
646 | max=data[0] |
---|
647 | min=data[0] |
---|
648 | for value in data: |
---|
649 | if value > max: |
---|
650 | max = value |
---|
651 | if value < min: |
---|
652 | min = value |
---|
653 | |
---|
654 | inc = (max-min)/100 |
---|
655 | |
---|
656 | histogram = ghistogram(bins=arange(min,max,inc),\ |
---|
657 | color = colour.red) |
---|
658 | histogram.plot(data=data) |
---|
659 | |
---|
660 | def av_att(self,triangle,i): |
---|
661 | if i==-1: return 1 |
---|
662 | else: |
---|
663 | #evaluates the average attribute of the vertices of a triangle. |
---|
664 | V = triangle.getVertices() |
---|
665 | a0 = (V[0].attributes[i]) |
---|
666 | a1 = (V[1].attributes[i]) |
---|
667 | a2 = (V[2].attributes[i]) |
---|
668 | return (a0+a1+a2)/3 |
---|
669 | |
---|
670 | def Courant_ratio(self,triangle,index): |
---|
671 | """ |
---|
672 | Uses the courant threshold |
---|
673 | """ |
---|
674 | e = self.av_att(triangle,index) |
---|
675 | A = triangle.calcArea() |
---|
676 | P = triangle.calcP() |
---|
677 | r = A/(2*P) |
---|
678 | e = max(0.1,abs(e)) |
---|
679 | return r/e**0.5 |
---|
680 | |
---|
681 | def Gradient(self,triangle,index): |
---|
682 | V = triangle.vertices |
---|
683 | x0, y0, x1, y1, x2, y2, q0, q1, q2 = V[0].x,V[0].y,V[1].x,V[1].y,V[2].x,V[2].y,V[0].attributes[index],V[1].attributes[index],V[2].attributes[index] |
---|
684 | grad_x,grad_y = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2) |
---|
685 | if ((grad_x**2)+(grad_y**2))**(0.5)<0: |
---|
686 | print ((grad_x**2)+(grad_y**2))**(0.5) |
---|
687 | return ((grad_x**2)+(grad_y**2))**(0.5) |
---|
688 | |
---|
689 | |
---|
690 | def append_triangle(self,triangle): |
---|
691 | self.meshTriangles.append(triangle) |
---|
692 | |
---|
693 | def replace_triangle(self,triangle,replacement): |
---|
694 | i = self.meshTriangles.index(triangle) |
---|
695 | self.meshTriangles[i]=replacement |
---|
696 | assert replacement in self.meshTriangles |
---|
697 | |
---|
698 | |
---|
699 | """Refines triangles |
---|
700 | |
---|
701 | Implements the #triangular bisection?# algorithm. |
---|
702 | |
---|
703 | |
---|
704 | """ |
---|
705 | |
---|
706 | def Refine(mesh, triangles): |
---|
707 | """ |
---|
708 | Given a general_mesh, and a triangle number, split |
---|
709 | that triangle in the mesh in half. Then to prevent |
---|
710 | vertices and edges from meeting, keep refining |
---|
711 | neighbouring triangles until the mesh is clean. |
---|
712 | """ |
---|
713 | state = BisectionState(mesh) |
---|
714 | for triangle in triangles: |
---|
715 | if not state.refined_triangles.has_key(triangle): |
---|
716 | triangle.rotate_longest_side() |
---|
717 | state.start(triangle) |
---|
718 | Refine_mesh(mesh, state) |
---|
719 | |
---|
720 | def Refine_mesh(mesh, state): |
---|
721 | """ |
---|
722 | """ |
---|
723 | state.getState(mesh) |
---|
724 | refine_triangle(mesh,state) |
---|
725 | state.evolve() |
---|
726 | if not state.end: |
---|
727 | Refine_mesh(mesh,state) |
---|
728 | |
---|
729 | def refine_triangle(mesh,state): |
---|
730 | split(mesh,state.current_triangle,state.new_point) |
---|
731 | if state.case == 'one': |
---|
732 | state.r[3]=state.current_triangle#triangle 2 |
---|
733 | |
---|
734 | new_triangle_id = len(mesh.meshTriangles)-1 |
---|
735 | new_triangle = mesh.meshTriangles[new_triangle_id] |
---|
736 | |
---|
737 | split(mesh,new_triangle,state.old_point) |
---|
738 | state.r[2]=new_triangle#triangle 1.2 |
---|
739 | state.r[4]=mesh.meshTriangles[len(mesh.meshTriangles)-1]#triangle 1.1 |
---|
740 | r = state.r |
---|
741 | state.repairCaseOne() |
---|
742 | |
---|
743 | if state.case == 'two': |
---|
744 | state.r[2]=mesh.meshTriangles[len(mesh.meshTriangles)-1]#triangle 1 |
---|
745 | |
---|
746 | new_triangle = state.current_triangle |
---|
747 | |
---|
748 | split(mesh,new_triangle,state.old_point) |
---|
749 | |
---|
750 | state.r[3]=mesh.meshTriangles[len(mesh.meshTriangles)-1]#triangle 2.1 |
---|
751 | state.r[4]=new_triangle#triangle 2.2 |
---|
752 | r = state.r |
---|
753 | |
---|
754 | state.repairCaseTwo() |
---|
755 | |
---|
756 | if state.case == 'vertex': |
---|
757 | state.r[2]=state.current_triangle#triangle 2 |
---|
758 | state.r[3]=mesh.meshTriangles[len(mesh.meshTriangles)-1]#triangle 1 |
---|
759 | r = state.r |
---|
760 | state.repairCaseVertex() |
---|
761 | |
---|
762 | if state.case == 'start': |
---|
763 | state.r[2]=mesh.meshTriangles[len(mesh.meshTriangles)-1]#triangle 1 |
---|
764 | state.r[3]=state.current_triangle#triangle 2 |
---|
765 | |
---|
766 | if state.next_case == 'boundary': |
---|
767 | state.repairCaseBoundary() |
---|
768 | |
---|
769 | |
---|
770 | def split(mesh, triangle, new_point): |
---|
771 | """ |
---|
772 | Given a mesh, triangle_id and a new point, |
---|
773 | split the corrosponding triangle into two |
---|
774 | new triangles and update the mesh. |
---|
775 | """ |
---|
776 | |
---|
777 | new_triangle1 = Triangle(new_point,triangle.vertices[0], |
---|
778 | triangle.vertices[1], |
---|
779 | attribute = triangle.attribute, |
---|
780 | neighbors = None) |
---|
781 | new_triangle2 = Triangle(new_point,triangle.vertices[2], |
---|
782 | triangle.vertices[0], |
---|
783 | attribute = triangle.attribute, |
---|
784 | neighbors = None) |
---|
785 | |
---|
786 | new_triangle1.setNeighbors(triangle.neighbors[2],None,new_triangle2) |
---|
787 | new_triangle2.setNeighbors(triangle.neighbors[1],new_triangle1,None) |
---|
788 | |
---|
789 | mesh.meshTriangles.append(new_triangle1) |
---|
790 | |
---|
791 | triangle.vertices = new_triangle2.vertices |
---|
792 | triangle.neighbors = new_triangle2.neighbors |
---|
793 | |
---|
794 | |
---|
795 | class State: |
---|
796 | |
---|
797 | def __init__(self): |
---|
798 | pass |
---|
799 | |
---|
800 | class BisectionState(State): |
---|
801 | |
---|
802 | |
---|
803 | def __init__(self,mesh): |
---|
804 | self.len = len(mesh.meshTriangles) |
---|
805 | self.refined_triangles = {} |
---|
806 | self.mesh = mesh |
---|
807 | self.current_triangle = None |
---|
808 | self.case = 'start' |
---|
809 | self.end = False |
---|
810 | self.r = [None,None,None,None,None] |
---|
811 | |
---|
812 | def start(self, triangle): |
---|
813 | self.current_triangle = triangle |
---|
814 | self.case = 'start' |
---|
815 | self.end = False |
---|
816 | self.r = [None,None,None,None,None] |
---|
817 | |
---|
818 | def getState(self,mesh): |
---|
819 | if not self.case == 'vertex': |
---|
820 | self.new_point=self.getNewVertex(mesh, self.current_triangle) |
---|
821 | #self.neighbour=self.getNeighbour(mesh, self.current_triangle) |
---|
822 | self.neighbour = self.current_triangle.neighbors[0] |
---|
823 | if not self.neighbour is None: |
---|
824 | self.neighbour.rotate_longest_side() |
---|
825 | self.next_case = self.get_next_case(mesh,self.neighbour, |
---|
826 | self.current_triangle) |
---|
827 | if self.case == 'vertex': |
---|
828 | self.new_point=self.old_point |
---|
829 | |
---|
830 | |
---|
831 | def evolve(self): |
---|
832 | if self.case == 'vertex': |
---|
833 | self.end = True |
---|
834 | |
---|
835 | self.last_case = self.case |
---|
836 | self.case = self.next_case |
---|
837 | |
---|
838 | self.old_point = self.new_point |
---|
839 | self.current_triangle = self.neighbour |
---|
840 | |
---|
841 | if self.case == 'boundary': |
---|
842 | self.end = True |
---|
843 | self.refined_triangles[self.r[2]]=1 |
---|
844 | self.refined_triangles[self.r[3]]=1 |
---|
845 | if not self.r[4] is None: |
---|
846 | self.refined_triangles[self.r[4]]=1 |
---|
847 | self.r[0]=self.r[2] |
---|
848 | self.r[1]=self.r[3] |
---|
849 | |
---|
850 | |
---|
851 | def getNewVertex(self,mesh,triangle): |
---|
852 | coordinate1 = triangle.vertices[1] |
---|
853 | coordinate2 = triangle.vertices[2] |
---|
854 | a = ([coordinate1.x*1.,coordinate1.y*1.]) |
---|
855 | b = ([coordinate2.x*1.,coordinate2.y*1.]) |
---|
856 | attributes = [] |
---|
857 | for i in range(len(coordinate1.attributes)): |
---|
858 | att = (coordinate1.attributes[i]+coordinate2.attributes[i])/2 |
---|
859 | attributes.append(att) |
---|
860 | new_coordinate = [((a[0]-b[0])/2+b[0]),((a[1]-b[1])/2+b[1])] |
---|
861 | newVertex = Vertex(new_coordinate[0],new_coordinate[1], |
---|
862 | attributes = attributes) |
---|
863 | mesh.maxVertexIndex+=1 |
---|
864 | newVertex.index = mesh.maxVertexIndex |
---|
865 | mesh.meshVertices.append(newVertex) |
---|
866 | return newVertex |
---|
867 | |
---|
868 | def get_next_case(self, mesh,neighbour,triangle): |
---|
869 | """ |
---|
870 | Given the locations of two neighbouring triangles, |
---|
871 | examine the interior indices of their vertices (i.e. |
---|
872 | 0,1 or 2) to determine what how the neighbour needs |
---|
873 | to be refined. |
---|
874 | """ |
---|
875 | if (neighbour is None): |
---|
876 | next_case = 'boundary' |
---|
877 | else: |
---|
878 | if triangle.vertices[1].x==neighbour.vertices[2].x: |
---|
879 | if triangle.vertices[1].y==neighbour.vertices[2].y: |
---|
880 | next_case = 'vertex' |
---|
881 | if triangle.vertices[1].x==neighbour.vertices[0].x: |
---|
882 | if triangle.vertices[1].y==neighbour.vertices[0].y: |
---|
883 | next_case = 'two' |
---|
884 | if triangle.vertices[1].x==neighbour.vertices[1].x: |
---|
885 | if triangle.vertices[1].y==neighbour.vertices[1].y: |
---|
886 | next_case = 'one' |
---|
887 | return next_case |
---|
888 | |
---|
889 | |
---|
890 | |
---|
891 | def repairCaseVertex(self): |
---|
892 | |
---|
893 | r = self.r |
---|
894 | |
---|
895 | |
---|
896 | self.link(r[0],r[2]) |
---|
897 | self.repair(r[0]) |
---|
898 | |
---|
899 | self.link(r[1],r[3]) |
---|
900 | self.repair(r[1]) |
---|
901 | |
---|
902 | self.repair(r[2]) |
---|
903 | |
---|
904 | self.repair(r[3]) |
---|
905 | |
---|
906 | |
---|
907 | def repairCaseOne(self): |
---|
908 | r = self.rkey |
---|
909 | |
---|
910 | |
---|
911 | self.link(r[0],r[2]) |
---|
912 | self.repair(r[0]) |
---|
913 | |
---|
914 | self.link(r[1],r[4]) |
---|
915 | self.repair(r[1]) |
---|
916 | |
---|
917 | self.repair(r[4]) |
---|
918 | |
---|
919 | def repairCaseTwo(self): |
---|
920 | r = self.r |
---|
921 | |
---|
922 | self.link(r[0],r[4]) |
---|
923 | self.repair(r[0]) |
---|
924 | |
---|
925 | self.link(r[1],r[3]) |
---|
926 | self.repair(r[1]) |
---|
927 | |
---|
928 | self.repair(r[4]) |
---|
929 | |
---|
930 | def repairCaseBoundary(self): |
---|
931 | r = self.r |
---|
932 | self.repair(r[2]) |
---|
933 | self.repair(r[3]) |
---|
934 | |
---|
935 | |
---|
936 | |
---|
937 | def repair(self,triangle): |
---|
938 | """ |
---|
939 | Given a triangle that knows its neighbours, this will |
---|
940 | force the neighbours to comply. |
---|
941 | |
---|
942 | However, it needs to compare the vertices of triangles |
---|
943 | for this implementation |
---|
944 | |
---|
945 | But it doesn't work for invalid neighbour structures |
---|
946 | """ |
---|
947 | n=triangle.neighbors |
---|
948 | for i in (0,1,2): |
---|
949 | if not n[i] is None: |
---|
950 | for j in (0,1,2):#to find which side of the list is broken |
---|
951 | if not (n[i].vertices[j] in triangle.vertices): |
---|
952 | #ie if j is the side of n that needs fixing |
---|
953 | k = j |
---|
954 | n[i].neighbors[k]=triangle |
---|
955 | |
---|
956 | |
---|
957 | |
---|
958 | def link(self,triangle1,triangle2): |
---|
959 | """ |
---|
960 | make triangle1 neighbors point to t |
---|
961 | #count = 0riangle2 |
---|
962 | """ |
---|
963 | count = 0 |
---|
964 | for i in (0,1,2):#to find which side of the list is broken |
---|
965 | if not (triangle1.vertices[i] in triangle2.vertices): |
---|
966 | j = i |
---|
967 | count+=1 |
---|
968 | assert count == 1 |
---|
969 | triangle1.neighbors[j]=triangle2 |
---|
970 | |
---|
971 | class Discretised_Tuple_Set: |
---|
972 | """ |
---|
973 | if a={(0.0):[(0.01),(0.02)],(0.2):[(0.17)]} |
---|
974 | a[(0.01)]=a[(0.0)]=[(0.01),(0.02)] |
---|
975 | a[(10000)]=[] #NOT KEYERROR |
---|
976 | |
---|
977 | a.append[(0.01)] |
---|
978 | => {0.0:[(0.01),(0.02),(0.01)],0.2:[(0.17)]} |
---|
979 | |
---|
980 | #NOT IMPLIMENTED |
---|
981 | a.remove[(0.01)] |
---|
982 | => {(0.0):[(0.02),(0.01)],0.2:[(0.17)]} |
---|
983 | |
---|
984 | a.remove[(0.17)] |
---|
985 | => {(0.0):[(0.02),(0.01)],0.2:[]} |
---|
986 | #NOT IMPLIMENTED |
---|
987 | at a.precision = 2: |
---|
988 | a.round_up_rel[0.0]= |
---|
989 | a.round_flat[0.0]= |
---|
990 | a.round_down_rel[0.0]= |
---|
991 | |
---|
992 | a.up((0.1,2.04))= |
---|
993 | |
---|
994 | If t_rel = 0, nothing gets rounded into |
---|
995 | two bins. If t_rel = 0.5, everything does. |
---|
996 | |
---|
997 | Ideally, precision can be set high, so that multiple |
---|
998 | entries are rarely in the same bin. And t_rel should |
---|
999 | be low (<0.1 for 1 dimension!,<(0.1/n) for small n!!) |
---|
1000 | so that it is rare to put items in mutiple bins. |
---|
1001 | |
---|
1002 | Ex bins per entry = product(a,b,c...,n) |
---|
1003 | a = 1 or 2 s.t. Ex(a) = 1+2*t_rel |
---|
1004 | b = 1 or 2 ... |
---|
1005 | |
---|
1006 | BUT!!! to avoid missing the right bin: |
---|
1007 | (-10)**(precision+1)*t_rel must be greater than the |
---|
1008 | greatest possible variation that an identical element |
---|
1009 | can display. |
---|
1010 | |
---|
1011 | |
---|
1012 | Note that if tol = 0.5 (the max allowed) 0.6 will round to .7 and .5 |
---|
1013 | but not .6 - this looks wrong, but note that *everything* will round, |
---|
1014 | so .6 wont be missed as everything close to it will check in .7 and .5. |
---|
1015 | """ |
---|
1016 | def __init__(self,p_rel = 6,t_rel = 0.01): |
---|
1017 | self.__p_rel__ = p_rel |
---|
1018 | self.__t_rel__ = t_rel |
---|
1019 | |
---|
1020 | self.__p_abs__ = p_rel+1 |
---|
1021 | self.__t_abs__ = t_rel |
---|
1022 | |
---|
1023 | assert t_rel <= 0.5 |
---|
1024 | self.__items__ = {} |
---|
1025 | from math import frexp |
---|
1026 | self.frexp = frexp |
---|
1027 | roundings = [self.round_up_rel,\ |
---|
1028 | self.round_down_rel,self.round_flat_rel,\ |
---|
1029 | self.round_down_abs,self.round_up_abs,\ |
---|
1030 | self.round_flat_abs]# |
---|
1031 | |
---|
1032 | self.roundings = roundings |
---|
1033 | |
---|
1034 | def __repr__(self): |
---|
1035 | return '%s'%self.__items__ |
---|
1036 | |
---|
1037 | def rounded_keys(self,key): |
---|
1038 | key = tuple(key) |
---|
1039 | keys = [key] |
---|
1040 | keys = self.__rounded_keys__(key) |
---|
1041 | return (keys) |
---|
1042 | |
---|
1043 | def __rounded_keys__(self,key): |
---|
1044 | keys = [] |
---|
1045 | rounded_key=list(key) |
---|
1046 | rounded_values=list(key) |
---|
1047 | |
---|
1048 | roundings = list(self.roundings) |
---|
1049 | |
---|
1050 | #initialise rounded_values |
---|
1051 | round = roundings.pop(0) |
---|
1052 | for i in range(len(rounded_values)): |
---|
1053 | rounded_key[i]=round(key[i]) |
---|
1054 | rounded_values[i]={} |
---|
1055 | rounded_values[i][rounded_key[i]]=None |
---|
1056 | keys.append(tuple(rounded_key)) |
---|
1057 | |
---|
1058 | for round in roundings: |
---|
1059 | for i in range(len(rounded_key)): |
---|
1060 | rounded_value=round(key[i]) |
---|
1061 | if not rounded_values[i].has_key(rounded_value): |
---|
1062 | #ie unless round_up_rel = round_down_rel |
---|
1063 | #so the keys stay unique |
---|
1064 | for j in range(len(keys)): |
---|
1065 | rounded_key = list(keys[j]) |
---|
1066 | rounded_key[i]=rounded_value |
---|
1067 | keys.append(tuple(rounded_key)) |
---|
1068 | return keys |
---|
1069 | |
---|
1070 | def append(self,item): |
---|
1071 | keys = self.rounded_keys(item) |
---|
1072 | for key in keys: |
---|
1073 | if self.__items__.has_key(key): |
---|
1074 | self.__items__[key].append(item) |
---|
1075 | else: |
---|
1076 | self.__items__[key]=[item] |
---|
1077 | |
---|
1078 | def __getitem__(self,key): |
---|
1079 | answer = [] |
---|
1080 | keys = self.rounded_keys(key) |
---|
1081 | for key in keys: |
---|
1082 | if self.__items__.has_key(key): |
---|
1083 | answer.extend(self.__items__[key]) |
---|
1084 | #if len(answer)==0: |
---|
1085 | # raise KeyError#FIXME or return KeyError |
---|
1086 | # #FIXME or just return []? |
---|
1087 | else: |
---|
1088 | return answer #FIXME or unique(answer)? |
---|
1089 | |
---|
1090 | def __delete__(self,item): |
---|
1091 | keys = self.rounded_keys(item) |
---|
1092 | answer = False |
---|
1093 | #if any of the possible keys contains |
---|
1094 | #a list, return true |
---|
1095 | for key in keys: |
---|
1096 | if self.__items__.has_key(key): |
---|
1097 | if item in self.__items__[key]: |
---|
1098 | self.__items__[key].remove(item) |
---|
1099 | |
---|
1100 | def remove(self,item): |
---|
1101 | self.__delete__(item) |
---|
1102 | |
---|
1103 | def __contains__(self,item): |
---|
1104 | |
---|
1105 | keys = self.rounded_keys(item) |
---|
1106 | answer = False |
---|
1107 | #if any of the possible keys contains |
---|
1108 | #a list, return true |
---|
1109 | for key in keys: |
---|
1110 | if self.__items__.has_key(key): |
---|
1111 | if item in self.__items__[key]: |
---|
1112 | answer = True |
---|
1113 | return answer |
---|
1114 | |
---|
1115 | |
---|
1116 | def has_item(self,item): |
---|
1117 | return self.__contains__(item) |
---|
1118 | |
---|
1119 | def round_up_rel2(self,value): |
---|
1120 | t_rel=self.__t_rel__ |
---|
1121 | #Rounding up the value |
---|
1122 | m,e = self.frexp(value) |
---|
1123 | m = m/2 |
---|
1124 | e = e + 1 |
---|
1125 | #m is the mantissa, e the exponent |
---|
1126 | # 0.5 < |m| < 1.0 |
---|
1127 | m = m+t_rel*(10**-(self.__p_rel__)) |
---|
1128 | #bump m up |
---|
1129 | m = round(m,self.__p_rel__) |
---|
1130 | return m*(2.**e) |
---|
1131 | |
---|
1132 | def round_down_rel2(self,value): |
---|
1133 | t_rel=self.__t_rel__ |
---|
1134 | #Rounding down the value |
---|
1135 | m,e = self.frexp(value) |
---|
1136 | m = m/2 |
---|
1137 | e = e + 1 |
---|
1138 | #m is the mantissa, e the exponent |
---|
1139 | # 0.5 < m < 1.0 |
---|
1140 | m = m-t_rel*(10**-(self.__p_rel__)) |
---|
1141 | #bump the |m| down, by 5% or whatever |
---|
1142 | #self.p_rel dictates |
---|
1143 | m = round(m,self.__p_rel__) |
---|
1144 | return m*(2.**e) |
---|
1145 | |
---|
1146 | def round_flat_rel2(self,value): |
---|
1147 | #redundant |
---|
1148 | m,e = self.frexp(value) |
---|
1149 | m = m/2 |
---|
1150 | e = e + 1 |
---|
1151 | m = round(m,self.__p_rel__) |
---|
1152 | return m*(2.**e) |
---|
1153 | |
---|
1154 | def round_up_rel(self,value): |
---|
1155 | t_rel=self.__t_rel__ |
---|
1156 | #Rounding up the value |
---|
1157 | m,e = self.frexp(value) |
---|
1158 | #m is the mantissa, e the exponent |
---|
1159 | # 0.5 < |m| < 1.0 |
---|
1160 | m = m+t_rel*(10**-(self.__p_rel__)) |
---|
1161 | #bump m up |
---|
1162 | m = round(m,self.__p_rel__) |
---|
1163 | return m*(2.**e) |
---|
1164 | |
---|
1165 | def round_down_rel(self,value): |
---|
1166 | t_rel=self.__t_rel__ |
---|
1167 | #Rounding down the value |
---|
1168 | m,e = self.frexp(value) |
---|
1169 | #m is the mantissa, e the exponent |
---|
1170 | # 0.5 < m < 1.0 |
---|
1171 | m = m-t_rel*(10**-(self.__p_rel__)) |
---|
1172 | #bump the |m| down, by 5% or whatever |
---|
1173 | #self.p_rel dictates |
---|
1174 | m = round(m,self.__p_rel__) |
---|
1175 | return m*(2.**e) |
---|
1176 | |
---|
1177 | def round_flat_rel(self,value): |
---|
1178 | #redundant |
---|
1179 | m,e = self.frexp(value) |
---|
1180 | m = round(m,self.__p_rel__) |
---|
1181 | return m*(2.**e) |
---|
1182 | |
---|
1183 | def round_up_abs(self,value): |
---|
1184 | t_abs=self.__t_abs__ |
---|
1185 | #Rounding up the value |
---|
1186 | m = value+t_abs*(10**-(self.__p_abs__)) |
---|
1187 | #bump m up |
---|
1188 | m = round(m,self.__p_abs__) |
---|
1189 | return m |
---|
1190 | |
---|
1191 | def round_down_abs(self,value): |
---|
1192 | t_abs=self.__t_abs__ |
---|
1193 | #Rounding down the value |
---|
1194 | m = value-t_abs*(10**-(self.__p_abs__)) |
---|
1195 | #bump the |m| down, by 5% or whatever |
---|
1196 | #self.p_rel dictates |
---|
1197 | m = round(m,self.__p_abs__) |
---|
1198 | return m |
---|
1199 | |
---|
1200 | def round_flat_abs(self,value): |
---|
1201 | #redundant? |
---|
1202 | m = round(value,self.__p_abs__) |
---|
1203 | return m |
---|
1204 | |
---|
1205 | def keys(self): |
---|
1206 | return self.__items__.keys() |
---|
1207 | |
---|
1208 | |
---|
1209 | class Mapped_Discretised_Tuple_Set(Discretised_Tuple_Set): |
---|
1210 | """ |
---|
1211 | This is a discretised tuple set, but |
---|
1212 | based on a mapping. The mapping MUST |
---|
1213 | return a sequence. |
---|
1214 | |
---|
1215 | example: |
---|
1216 | def weight(animal): |
---|
1217 | return [animal.weight] |
---|
1218 | |
---|
1219 | a = Mapped_Discretised_Tuple_Set(weight) |
---|
1220 | a.append[cow] |
---|
1221 | a.append[fox] |
---|
1222 | a.append[horse] |
---|
1223 | |
---|
1224 | a[horse] -> [cow,horse] |
---|
1225 | a[dog] -> [fox] |
---|
1226 | a[elephant] -> [] |
---|
1227 | """ |
---|
1228 | def __init__(self,mapping,p_rel = 6, t_rel=0.01): |
---|
1229 | Discretised_Tuple_Set.__init__\ |
---|
1230 | (self,p_rel,t_rel = t_rel) |
---|
1231 | self.mapping = mapping |
---|
1232 | |
---|
1233 | def rounded_keys(self,key): |
---|
1234 | mapped_key = tuple(self.mapping(key)) |
---|
1235 | keys = self.__rounded_keys__(mapped_key) |
---|
1236 | return keys |
---|
1237 | |
---|
1238 | class Affine_Linespace(Mapped_Discretised_Tuple_Set): |
---|
1239 | """ |
---|
1240 | The affine linespace creates a way to record and compare lines. |
---|
1241 | Precision is a bit of a hack, but it creates a way to avoid |
---|
1242 | misses caused by round offs (between two lines of different |
---|
1243 | lenghts, the short one gets rounded off more). |
---|
1244 | I am starting to think that a quadratic search would be faster. |
---|
1245 | Nearly. |
---|
1246 | """ |
---|
1247 | def __init__(self,p_rel=4,t_rel=0.2): |
---|
1248 | Mapped_Discretised_Tuple_Set.__init__\ |
---|
1249 | (self,self.affine_line,\ |
---|
1250 | p_rel=p_rel,t_rel=t_rel) |
---|
1251 | |
---|
1252 | roundings = \ |
---|
1253 | [self.round_down_rel,self.round_up_rel,self.round_flat_rel] |
---|
1254 | self.roundings = roundings |
---|
1255 | #roundings = \ |
---|
1256 | #[self.round_down_abs,self.round_up_abs,self.round_flat_abs] |
---|
1257 | #self.roundings = roundings |
---|
1258 | |
---|
1259 | def affine_line(self,line): |
---|
1260 | point_1 = line[0] |
---|
1261 | point_2 = line[1] |
---|
1262 | #returns the equation of a line |
---|
1263 | #between two points, in the from |
---|
1264 | #(a,b,-c), as in ax+by-c=0 |
---|
1265 | #or line *dot* (x,y,1) = (0,0,0) |
---|
1266 | |
---|
1267 | #Note that it normalises the line |
---|
1268 | #(a,b,-c) so Line*Line = 1. |
---|
1269 | #This does not change the mathematical |
---|
1270 | #properties, but it makes comparism |
---|
1271 | #easier. |
---|
1272 | |
---|
1273 | #There are probably better algorithms. |
---|
1274 | x1 = point_1[0] |
---|
1275 | x2 = point_2[0] |
---|
1276 | y1 = point_1[1] |
---|
1277 | y2 = point_2[1] |
---|
1278 | dif_x = x1-x2 |
---|
1279 | dif_y = y1-y2 |
---|
1280 | |
---|
1281 | if dif_x == dif_y == 0: |
---|
1282 | msg = 'points are the same' |
---|
1283 | raise msg |
---|
1284 | elif abs(dif_x)>=abs(dif_y): |
---|
1285 | alpha = (-dif_y)/dif_x |
---|
1286 | #a = alpha * b |
---|
1287 | b = -1. |
---|
1288 | c = (x1*alpha+x2*alpha+y1+y2)/2. |
---|
1289 | a = alpha*b |
---|
1290 | else: |
---|
1291 | beta = dif_x/(-dif_y) |
---|
1292 | #b = beta * a |
---|
1293 | a = 1. |
---|
1294 | c = (x1+x2+y1*beta+y2*beta)/2. |
---|
1295 | b = beta*a |
---|
1296 | mag = abs(a)+abs(b) |
---|
1297 | #This does not change the mathematical |
---|
1298 | #properties, but it makes comparism possible. |
---|
1299 | |
---|
1300 | #note that the gradient is b/a, or (a/b)**-1. |
---|
1301 | #so |
---|
1302 | |
---|
1303 | #if a == 0: |
---|
1304 | # sign_a = 1. |
---|
1305 | #else: |
---|
1306 | # sign_a = a/((a**2)**0.5) |
---|
1307 | #if b == 0: |
---|
1308 | # sign_b = 1. |
---|
1309 | #else: |
---|
1310 | # sign_b = b/((b**2)**0.5) |
---|
1311 | #if c == 0: |
---|
1312 | # sign_c = 1. |
---|
1313 | #else: |
---|
1314 | # sign_c = c/((c**2)**0.5) |
---|
1315 | #a = a/mag*sign_a |
---|
1316 | #b = b/mag*sign_b |
---|
1317 | #c = c/mag*sign_c |
---|
1318 | a = a/mag |
---|
1319 | b = b/mag |
---|
1320 | c = c/mag |
---|
1321 | return a,b,c |
---|