Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /trunk/src/errorlogx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2033 - (show annotations) (download) (as text)
Thu Oct 10 17:33:51 2019 UTC (5 years, 5 months ago) by amb
File MIME type: text/x-csrc
File size: 26477 byte(s)
Reduce memory consumption by writing the index to a file and mapping
it in to memory rather than allocating large amounts of memory.

1 /***************************************
2 Error log processing functions.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2013-2015, 2019 Andrew M. Bishop
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Affero General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ***************************************/
21
22
23 #include "typesx.h"
24 #include "nodesx.h"
25 #include "waysx.h"
26 #include "relationsx.h"
27
28 #include "errorlogx.h"
29 #include "errorlog.h"
30
31 #include "files.h"
32 #include "sorting.h"
33
34
35 /* Global variables */
36
37 /*+ The name of the error log file. +*/
38 extern char *errorlogfilename;
39
40 /*+ The name of the binary error log file. +*/
41 extern char *errorbinfilename;
42
43 /* Local variables */
44
45 /*+ Temporary file-local variables for use by the sort functions (re-initialised for each sort). +*/
46 static latlong_t lat_min,lat_max,lon_min,lon_max;
47
48 /* Local functions */
49
50 static void reindex_nodes(NodesX *nodesx);
51 static void reindex_ways(WaysX *waysx);
52 static void reindex_relations(RelationsX *relationsx);
53
54 static int lookup_lat_long_node(NodesX *nodesx,node_t node,latlong_t *latitude,latlong_t *longitude);
55 static int lookup_lat_long_way(WaysX *waysx,NodesX *nodesx,way_t way,latlong_t *latitude,latlong_t *longitude,index_t error);
56 static int lookup_lat_long_relation(RelationsX *relationsx,WaysX *waysx,NodesX *nodesx,relation_t relation,latlong_t *latitude,latlong_t *longitude,index_t error);
57
58 static int sort_by_lat_long(ErrorLogX *a,ErrorLogX *b);
59 static int measure_lat_long(ErrorLogX *errorlogx,index_t index);
60
61
62 /*++++++++++++++++++++++++++++++++++++++
63 Allocate a new error log list (create a new file).
64
65 ErrorLogsX *NewErrorLogList Returns a pointer to the error log list.
66 ++++++++++++++++++++++++++++++++++++++*/
67
68 ErrorLogsX *NewErrorLogList(void)
69 {
70 ErrorLogsX *errorlogsx;
71
72 errorlogsx=(ErrorLogsX*)calloc_logassert(1,sizeof(ErrorLogsX));
73
74 return(errorlogsx);
75 }
76
77
78 /*++++++++++++++++++++++++++++++++++++++
79 Free an error log list.
80
81 ErrorLogsX *errorlogsx The set of error logs to be freed.
82 ++++++++++++++++++++++++++++++++++++++*/
83
84 void FreeErrorLogList(ErrorLogsX *errorlogsx)
85 {
86 free(errorlogsx);
87 }
88
89
90 /*++++++++++++++++++++++++++++++++++++++
91 Process the binary error log.
92
93 ErrorLogsX *errorlogsx The set of error logs to update.
94
95 NodesX *nodesx The set of nodes.
96
97 WaysX *waysx The set of ways.
98
99 RelationsX *relationsx The set of relations.
100 ++++++++++++++++++++++++++++++++++++++*/
101
102 void ProcessErrorLogs(ErrorLogsX *errorlogsx,NodesX *nodesx,WaysX *waysx,RelationsX *relationsx)
103 {
104 int oldfd,newfd;
105 uint32_t offset=0;
106 int nerrorlogobjects=0;
107 int finished;
108 ErrorLogObject errorlogobjects[8];
109
110 /* Re-index the nodes, ways and relations */
111
112 printf_first("Re-indexing the Data: Nodes=0 Ways=0 Route-Relations=0 Turn-Relations=0");
113
114 reindex_nodes(nodesx);
115
116 printf_middle("Re-indexing the Data: Nodes=%"Pindex_t" Ways=0 Route-Relations=0 Turn-Relations=0",nodesx->number);
117
118 reindex_ways(waysx);
119
120 printf_middle("Re-indexing the Data: Nodes=%"Pindex_t" Ways=%"Pindex_t" Route-Relations=0 Turn-Relations=0",nodesx->number,waysx->number);
121
122 reindex_relations(relationsx);
123
124 printf_last("Re-indexed the Data: Nodes=%"Pindex_t" Ways=%"Pindex_t" Route-Relations=%"Pindex_t" Turn-Relations=%"Pindex_t,nodesx->number,waysx->number,relationsx->rrnumber,relationsx->trnumber);
125
126
127 /* Print the start message */
128
129 printf_first("Calculating Coordinates: Errors=0");
130
131 /* Map into memory / open the files */
132
133 #if !SLIM
134 nodesx->data=MapFile(nodesx->filename);
135 #else
136 nodesx->fd=SlimMapFile(nodesx->filename);
137
138 InvalidateNodeXCache(nodesx->cache);
139 #endif
140
141 waysx->fd=ReOpenFileBuffered(waysx->filename);
142 relationsx->rrfd=ReOpenFileBuffered(relationsx->rrfilename);
143 relationsx->trfd=ReOpenFileBuffered(relationsx->trfilename);
144
145 /* Map the index into memory */
146
147 nodesx->idata=MapFile(nodesx->ifilename_tmp);
148
149 waysx->idata=MapFile(waysx->ifilename_tmp);
150 waysx->odata=MapFile(waysx->ofilename_tmp);
151
152 relationsx->rridata=MapFile(relationsx->rrifilename_tmp);
153 relationsx->rrodata=MapFile(relationsx->rrofilename_tmp);
154 relationsx->tridata=MapFile(relationsx->trifilename_tmp);
155
156 /* Open the binary log file read-only and a new file writeable */
157
158 newfd=ReplaceFileBuffered(errorbinfilename,&oldfd);
159
160 /* Loop through the file and merge the raw data into coordinates */
161
162 errorlogsx->number=0;
163
164 do
165 {
166 ErrorLogObject errorlogobject;
167
168 finished=ReadFileBuffered(oldfd,&errorlogobject,sizeof(ErrorLogObject));
169
170 if(finished)
171 errorlogobject.offset=SizeFile(errorlogfilename);
172
173 if(offset!=errorlogobject.offset)
174 {
175 ErrorLogX errorlogx;
176 latlong_t errorlat=NO_LATLONG,errorlon=NO_LATLONG;
177
178 /* Calculate suitable coordinates */
179
180 if(nerrorlogobjects==1)
181 {
182 if(errorlogobjects[0].type=='N')
183 {
184 node_t node=(node_t)errorlogobjects[0].id;
185
186 lookup_lat_long_node(nodesx,node,&errorlat,&errorlon);
187 }
188 else if(errorlogobjects[0].type=='W')
189 {
190 way_t way=(way_t)errorlogobjects[0].id;
191
192 lookup_lat_long_way(waysx,nodesx,way,&errorlat,&errorlon,errorlogsx->number);
193 }
194 else if(errorlogobjects[0].type=='R')
195 {
196 relation_t relation=(relation_t)errorlogobjects[0].type;
197
198 lookup_lat_long_relation(relationsx,waysx,nodesx,relation,&errorlat,&errorlon,errorlogsx->number);
199 }
200 }
201 else
202 {
203 latlong_t latitude[8],longitude[8];
204 int i;
205 int ncoords=0,nnodes=0,nways=0,nrelations=0;
206
207 for(i=0;i<nerrorlogobjects;i++)
208 {
209 if(errorlogobjects[i].type=='N')
210 {
211 node_t node=(node_t)errorlogobjects[i].id;
212
213 if(lookup_lat_long_node(nodesx,node,&latitude[ncoords],&longitude[ncoords]))
214 ncoords++;
215
216 nnodes++;
217 }
218 else if(errorlogobjects[i].type=='W')
219 nways++;
220 else if(errorlogobjects[i].type=='R')
221 nrelations++;
222 }
223
224 if(nways==0 && nrelations==0) /* only nodes */
225 ;
226 else if(ncoords) /* some good nodes, possibly ways and/or relations */
227 ;
228 else if(nways) /* no good nodes, possibly some good ways */
229 {
230 for(i=0;i<nerrorlogobjects;i++)
231 if(errorlogobjects[i].type=='W')
232 {
233 way_t way=(way_t)errorlogobjects[i].id;
234
235 if(lookup_lat_long_way(waysx,nodesx,way,&latitude[ncoords],&longitude[ncoords],errorlogsx->number))
236 ncoords++;
237 }
238 }
239
240 if(nrelations==0) /* only nodes and/or ways */
241 ;
242 else if(ncoords) /* some good nodes and/or ways, possibly relations */
243 ;
244 else /* if(nrelations) */
245 {
246 for(i=0;i<nerrorlogobjects;i++)
247 if(errorlogobjects[i].type=='R')
248 {
249 relation_t relation=(relation_t)errorlogobjects[i].id;
250
251 if(lookup_lat_long_relation(relationsx,waysx,nodesx,relation,&latitude[ncoords],&longitude[ncoords],errorlogsx->number))
252 ncoords++;
253 }
254 }
255
256 if(ncoords)
257 {
258 errorlat=0;
259 errorlon=0;
260
261 for(i=0;i<ncoords;i++)
262 {
263 errorlat+=latitude[i];
264 errorlon+=longitude[i];
265 }
266
267 errorlat/=ncoords;
268 errorlon/=ncoords;
269 }
270 else
271 {
272 errorlat=NO_LATLONG;
273 errorlon=NO_LATLONG;
274 }
275 }
276
277 /* Write to file */
278
279 errorlogx.offset=offset;
280 errorlogx.length=errorlogobject.offset-offset;
281
282 errorlogx.latitude =errorlat;
283 errorlogx.longitude=errorlon;
284
285 WriteFileBuffered(newfd,&errorlogx,sizeof(ErrorLogX));
286
287 errorlogsx->number++;
288
289 offset=errorlogobject.offset;
290 nerrorlogobjects=0;
291
292 if(!(errorlogsx->number%10000))
293 printf_middle("Calculating Coordinates: Errors=%"Pindex_t,errorlogsx->number);
294 }
295
296 /* Store for later */
297
298 logassert(nerrorlogobjects<8,"Too many error log objects for one error message."); /* Only a limited amount of information stored. */
299
300 errorlogobjects[nerrorlogobjects]=errorlogobject;
301
302 nerrorlogobjects++;
303 }
304 while(!finished);
305
306 /* Unmap from memory / close the files */
307
308 #if !SLIM
309 nodesx->data=UnmapFile(nodesx->data);
310 #else
311 nodesx->fd=SlimUnmapFile(nodesx->fd);
312 #endif
313
314 waysx->fd=CloseFileBuffered(waysx->fd);
315 relationsx->rrfd=CloseFileBuffered(relationsx->rrfd);
316 relationsx->trfd=CloseFileBuffered(relationsx->trfd);
317
318 CloseFileBuffered(oldfd);
319 CloseFileBuffered(newfd);
320
321 /* Unmap the index from memory */
322
323 nodesx->idata=UnmapFile(nodesx->idata);
324
325 waysx->idata=UnmapFile(waysx->idata);
326 waysx->odata=UnmapFile(waysx->odata);
327
328 relationsx->rridata=UnmapFile(relationsx->rridata);
329 relationsx->rrodata=UnmapFile(relationsx->rrodata);
330 relationsx->tridata=UnmapFile(relationsx->tridata);
331
332 /* Print the final message */
333
334 printf_last("Calculated Coordinates: Errors=%"Pindex_t,errorlogsx->number);
335 }
336
337
338 /*++++++++++++++++++++++++++++++++++++++
339 Re-index the nodes that were kept.
340
341 NodesX *nodesx The set of nodes to process (contains the filename and number of nodes).
342 ++++++++++++++++++++++++++++++++++++++*/
343
344 static void reindex_nodes(NodesX *nodesx)
345 {
346 int fd;
347 NodeX nodex;
348
349 nodesx->number=nodesx->knumber;
350
351 /* Open a file for the index */
352
353 nodesx->ifd=OpenFileBufferedNew(nodesx->ifilename_tmp);
354
355 /* Get the node id for each node in the file. */
356
357 fd=ReOpenFileBuffered(nodesx->filename);
358
359 while(!ReadFileBuffered(fd,&nodex,sizeof(NodeX)))
360 WriteFileBuffered(nodesx->ifd,&nodex.id,sizeof(node_t));
361
362 /* Close the files */
363
364 CloseFileBuffered(fd);
365
366 nodesx->ifd=CloseFileBuffered(nodesx->ifd);
367 }
368
369
370 /*++++++++++++++++++++++++++++++++++++++
371 Re-index the ways that were kept.
372
373 WaysX *waysx The set of ways to process (contains the filename and number of ways).
374 ++++++++++++++++++++++++++++++++++++++*/
375
376 static void reindex_ways(WaysX *waysx)
377 {
378 FILESORT_VARINT waysize;
379 int fd;
380 offset_t offset=FILESORT_VARSIZE+sizeof(WayX);
381
382 waysx->number=waysx->knumber;
383
384 /* Open files for the indexes */
385
386 waysx->ifd=OpenFileBufferedNew(waysx->ifilename_tmp);
387 waysx->ofd=OpenFileBufferedNew(waysx->ofilename_tmp);
388
389 /* Get the way id and the offset for each way in the file */
390
391 fd=ReOpenFileBuffered(waysx->filename);
392
393 while(!ReadFileBuffered(fd,&waysize,FILESORT_VARSIZE))
394 {
395 WayX wayx;
396
397 ReadFileBuffered(fd,&wayx,sizeof(WayX));
398
399 WriteFileBuffered(waysx->ifd,&wayx.id,sizeof(way_t));
400 WriteFileBuffered(waysx->ofd,&offset,sizeof(offset_t));
401
402 SkipFileBuffered(fd,waysize-sizeof(WayX));
403
404 offset+=waysize+FILESORT_VARSIZE;
405 }
406
407 /* Close the files */
408
409 CloseFileBuffered(fd);
410
411 waysx->ifd=CloseFileBuffered(waysx->ifd);
412 waysx->ofd=CloseFileBuffered(waysx->ofd);
413 }
414
415
416 /*++++++++++++++++++++++++++++++++++++++
417 Re-index the relations that were kept.
418
419 RelationsX *relationsx The set of relations to process (contains the filenames and numbers of relations).
420 ++++++++++++++++++++++++++++++++++++++*/
421
422 static void reindex_relations(RelationsX *relationsx)
423 {
424 FILESORT_VARINT relationsize;
425 int fd;
426 offset_t offset=FILESORT_VARSIZE+sizeof(RouteRelX);
427 TurnRelX turnrelx;
428
429 /* Route relations */
430
431 relationsx->rrnumber=relationsx->rrknumber;
432
433 /* Open files for the indexes */
434
435 relationsx->rrifd=OpenFileBufferedNew(relationsx->rrifilename_tmp);
436 relationsx->rrofd=OpenFileBufferedNew(relationsx->rrofilename_tmp);
437
438 /* Get the relation id and the offset for each relation in the file */
439
440 fd=ReOpenFileBuffered(relationsx->rrfilename);
441
442 while(!ReadFileBuffered(fd,&relationsize,FILESORT_VARSIZE))
443 {
444 RouteRelX routerelx;
445
446 ReadFileBuffered(fd,&routerelx,sizeof(RouteRelX));
447
448 WriteFileBuffered(relationsx->rrifd,&routerelx.id,sizeof(relation_t));
449 WriteFileBuffered(relationsx->rrofd,&offset,sizeof(offset_t));
450
451 SkipFileBuffered(fd,relationsize-sizeof(RouteRelX));
452
453 offset+=relationsize+FILESORT_VARSIZE;
454 }
455
456 /* Close the files */
457
458 CloseFileBuffered(fd);
459
460 relationsx->rrifd=CloseFileBuffered(relationsx->rrifd);
461 relationsx->rrofd=CloseFileBuffered(relationsx->rrofd);
462
463
464 /* Turn relations */
465
466 relationsx->trnumber=relationsx->trknumber;
467
468 /* Open files for the indexes */
469
470 relationsx->trifd=OpenFileBufferedNew(relationsx->trifilename_tmp);
471
472 /* Get the relation id for each relation in the file */
473
474 fd=ReOpenFileBuffered(relationsx->trfilename);
475
476 while(!ReadFileBuffered(fd,&turnrelx,sizeof(TurnRelX)))
477 WriteFileBuffered(relationsx->trifd,&turnrelx.id,sizeof(relation_t));
478
479 /* Close the files */
480
481 CloseFileBuffered(fd);
482
483 relationsx->trifd=CloseFileBuffered(relationsx->trifd);
484 }
485
486
487 /*++++++++++++++++++++++++++++++++++++++
488 Lookup a node's latitude and longitude.
489
490 int lookup_lat_long_node Returns 1 if a node was found.
491
492 NodesX *nodesx The set of nodes to use.
493
494 node_t node The node number.
495
496 latlong_t *latitude Returns the latitude.
497
498 latlong_t *longitude Returns the longitude.
499 ++++++++++++++++++++++++++++++++++++++*/
500
501 static int lookup_lat_long_node(NodesX *nodesx,node_t node,latlong_t *latitude,latlong_t *longitude)
502 {
503 index_t index=IndexNodeX(nodesx,node);
504
505 if(index==NO_NODE)
506 return 0;
507 else
508 {
509 NodeX *nodex=LookupNodeX(nodesx,index,1);
510
511 *latitude =nodex->latitude;
512 *longitude=nodex->longitude;
513
514 return 1;
515 }
516 }
517
518
519 /*++++++++++++++++++++++++++++++++++++++
520 Lookup a way's latitude and longitude.
521
522 int lookup_lat_long_way Returns 1 if a way was found.
523
524 WaysX *waysx The set of ways to use.
525
526 NodesX *nodesx The set of nodes to use.
527
528 way_t way The way number.
529
530 latlong_t *latitude Returns the latitude.
531
532 latlong_t *longitude Returns the longitude.
533
534 index_t error The index of the error in the complete set of errors.
535 ++++++++++++++++++++++++++++++++++++++*/
536
537 static int lookup_lat_long_way(WaysX *waysx,NodesX *nodesx,way_t way,latlong_t *latitude,latlong_t *longitude,index_t error)
538 {
539 index_t index=IndexWayX(waysx,way);
540
541 if(index==NO_WAY)
542 return 0;
543 else
544 {
545 int count=1;
546 offset_t offset=waysx->odata[index];
547 node_t node1,node2,prevnode,node;
548 latlong_t latitude1,longitude1,latitude2,longitude2;
549
550 SeekFileBuffered(waysx->fd,offset);
551
552 /* Choose a random pair of adjacent nodes */
553
554 if(ReadFileBuffered(waysx->fd,&node1,sizeof(node_t)) || node1==NO_NODE_ID)
555 return 0;
556
557 if(ReadFileBuffered(waysx->fd,&node2,sizeof(node_t)) || node2==NO_NODE_ID)
558 return lookup_lat_long_node(nodesx,node1,latitude,longitude);
559
560 prevnode=node2;
561
562 while(!ReadFileBuffered(waysx->fd,&node,sizeof(node_t)) && node!=NO_NODE_ID)
563 {
564 count++;
565
566 if((error%count)==0) /* A 1/count chance */
567 {
568 node1=prevnode;
569 node2=node;
570 }
571
572 prevnode=node;
573 }
574
575 if(!lookup_lat_long_node(nodesx,node1,&latitude1,&longitude1))
576 return lookup_lat_long_node(nodesx,node2,latitude,longitude);
577
578 if(!lookup_lat_long_node(nodesx,node2,&latitude2,&longitude2))
579 return lookup_lat_long_node(nodesx,node1,latitude,longitude);
580
581 *latitude =(latitude1 +latitude2 )/2;
582 *longitude=(longitude1+longitude2)/2;
583
584 return 1;
585 }
586 }
587
588
589 /*++++++++++++++++++++++++++++++++++++++
590 Lookup a relation's latitude and longitude.
591
592 int lookup_lat_long_relation Returns 1 if a relation was found.
593
594 RelationsX *relationsx The set of relations to use.
595
596 WaysX *waysx The set of ways to use.
597
598 NodesX *nodesx The set of nodes to use.
599
600 relation_t relation The relation number.
601
602 latlong_t *latitude Returns the latitude.
603
604 latlong_t *longitude Returns the longitude.
605
606 index_t error The index of the error in the complete set of errors.
607 ++++++++++++++++++++++++++++++++++++++*/
608
609 static int lookup_lat_long_relation(RelationsX *relationsx,WaysX *waysx,NodesX *nodesx,relation_t relation,latlong_t *latitude,latlong_t *longitude,index_t error)
610 {
611 index_t index=IndexRouteRelX(relationsx,relation);
612
613 if(index==NO_RELATION)
614 {
615 index=IndexTurnRelX(relationsx,relation);
616
617 if(index==NO_RELATION)
618 return 0;
619 else
620 {
621 TurnRelX turnrelx;
622
623 SeekFileBuffered(relationsx->trfd,index*sizeof(TurnRelX));
624 ReadFileBuffered(relationsx->trfd,&turnrelx,sizeof(TurnRelX));
625
626 if(lookup_lat_long_node(nodesx,turnrelx.via,latitude,longitude))
627 return 1;
628
629 if(lookup_lat_long_way(waysx,nodesx,turnrelx.from,latitude,longitude,error))
630 return 1;
631
632 if(lookup_lat_long_way(waysx,nodesx,turnrelx.to,latitude,longitude,error))
633 return 1;
634
635 return 0;
636 }
637 }
638 else
639 {
640 int count;
641 offset_t offset=relationsx->rrodata[index];
642 node_t node=NO_NODE_ID,tempnode;
643 way_t way=NO_WAY_ID,tempway;
644 relation_t relation=NO_RELATION_ID,temprelation;
645
646 SeekFileBuffered(relationsx->rrfd,offset);
647
648 /* Choose a random node */
649
650 count=0;
651
652 while(!ReadFileBuffered(relationsx->rrfd,&tempnode,sizeof(node_t)) && tempnode!=NO_NODE_ID)
653 {
654 count++;
655
656 if((error%count)==0) /* A 1/count chance */
657 node=tempnode;
658 }
659
660 if(count && lookup_lat_long_node(nodesx,node,latitude,longitude))
661 return 1;
662
663 /* Choose a random way */
664
665 count=0;
666
667 while(!ReadFileBuffered(relationsx->rrfd,&tempway,sizeof(way_t)) && tempway!=NO_WAY_ID)
668 {
669 count++;
670
671 if((error%count)==0) /* A 1/count chance */
672 way=tempway;
673 }
674
675 if(count && lookup_lat_long_way(waysx,nodesx,way,latitude,longitude,error))
676 return 1;
677
678 /* Choose a random relation */
679
680 count=0;
681
682 while(!ReadFileBuffered(relationsx->rrfd,&temprelation,sizeof(relation_t)) && temprelation!=NO_RELATION_ID)
683 {
684 count++;
685
686 if((error%count)==0) /* A 1/count chance */
687 relation=temprelation;
688 }
689
690 if(count && lookup_lat_long_relation(relationsx,waysx,nodesx,relation,latitude,longitude,error))
691 return 1;
692
693 return 0;
694 }
695 }
696
697
698 /*++++++++++++++++++++++++++++++++++++++
699 Sort the error logs geographically.
700
701 ErrorLogsX *errorlogsx The set of error logs to sort.
702 ++++++++++++++++++++++++++++++++++++++*/
703
704 void SortErrorLogsGeographically(ErrorLogsX *errorlogsx)
705 {
706 int oldfd,newfd;
707 ll_bin_t lat_min_bin,lat_max_bin,lon_min_bin,lon_max_bin;
708
709 /* Print the start message */
710
711 printf_first("Sorting Errors Geographically");
712
713 /* Work out the range of data */
714
715 lat_min=radians_to_latlong( 2);
716 lat_max=radians_to_latlong(-2);
717 lon_min=radians_to_latlong( 4);
718 lon_max=radians_to_latlong(-4);
719
720 /* Re-open the file read-only and a new file writeable */
721
722 newfd=ReplaceFileBuffered(errorbinfilename,&oldfd);
723
724 /* Sort errors geographically */
725
726 filesort_fixed(oldfd,newfd,sizeof(ErrorLogX),NULL,
727 (int (*)(const void*,const void*))sort_by_lat_long,
728 (int (*)(void*,index_t))measure_lat_long);
729
730 /* Close the files */
731
732 CloseFileBuffered(oldfd);
733 CloseFileBuffered(newfd);
734
735 /* Work out the number of bins */
736
737 lat_min_bin=latlong_to_bin(lat_min);
738 lon_min_bin=latlong_to_bin(lon_min);
739 lat_max_bin=latlong_to_bin(lat_max);
740 lon_max_bin=latlong_to_bin(lon_max);
741
742 errorlogsx->latzero=lat_min_bin;
743 errorlogsx->lonzero=lon_min_bin;
744
745 errorlogsx->latbins=(lat_max_bin-lat_min_bin)+1;
746 errorlogsx->lonbins=(lon_max_bin-lon_min_bin)+1;
747
748 /* Print the final message */
749
750 printf_last("Sorted Errors Geographically: Errors=%"Pindex_t,errorlogsx->number);
751 }
752
753
754 /*++++++++++++++++++++++++++++++++++++++
755 Sort the errors into latitude and longitude order (first by longitude bin
756 number, then by latitude bin number and then by exact longitude and then by
757 exact latitude).
758
759 int sort_by_lat_long Returns the comparison of the latitude and longitude fields.
760
761 ErrorLogX *a The first error location.
762
763 ErrorLogX *b The second error location.
764 ++++++++++++++++++++++++++++++++++++++*/
765
766 static int sort_by_lat_long(ErrorLogX *a,ErrorLogX *b)
767 {
768 ll_bin_t a_lon=latlong_to_bin(a->longitude);
769 ll_bin_t b_lon=latlong_to_bin(b->longitude);
770
771 if(a_lon<b_lon)
772 return(-1);
773 else if(a_lon>b_lon)
774 return(1);
775 else
776 {
777 ll_bin_t a_lat=latlong_to_bin(a->latitude);
778 ll_bin_t b_lat=latlong_to_bin(b->latitude);
779
780 if(a_lat<b_lat)
781 return(-1);
782 else if(a_lat>b_lat)
783 return(1);
784 else
785 {
786 if(a->longitude<b->longitude)
787 return(-1);
788 else if(a->longitude>b->longitude)
789 return(1);
790 else
791 {
792 if(a->latitude<b->latitude)
793 return(-1);
794 else if(a->latitude>b->latitude)
795 return(1);
796 }
797
798 return(FILESORT_PRESERVE_ORDER(a,b));
799 }
800 }
801 }
802
803
804 /*++++++++++++++++++++++++++++++++++++++
805 Measure the extent of the data.
806
807 int measure_lat_long Return 1 if the value is to be kept, otherwise 0.
808
809 ErrorLogX *errorlogx The error location.
810
811 index_t index The number of sorted error locations that have already been written to the output file.
812 ++++++++++++++++++++++++++++++++++++++*/
813
814 static int measure_lat_long(ErrorLogX *errorlogx,index_t index)
815 {
816 if(errorlogx->latitude!=NO_LATLONG)
817 {
818 if(errorlogx->latitude<lat_min)
819 lat_min=errorlogx->latitude;
820 if(errorlogx->latitude>lat_max)
821 lat_max=errorlogx->latitude;
822 if(errorlogx->longitude<lon_min)
823 lon_min=errorlogx->longitude;
824 if(errorlogx->longitude>lon_max)
825 lon_max=errorlogx->longitude;
826 }
827
828 return(1);
829 }
830
831
832 /*++++++++++++++++++++++++++++++++++++++
833 Save the binary error log.
834
835 ErrorLogsX *errorlogsx The set of error logs to write.
836
837 char *filename The name of the final file to write.
838 ++++++++++++++++++++++++++++++++++++++*/
839
840 void SaveErrorLogs(ErrorLogsX *errorlogsx,char *filename)
841 {
842 ErrorLogsFile errorlogsfile;
843 ErrorLogX errorlogx;
844 int oldfd,newfd;
845 ll_bin2_t latlonbin=0,maxlatlonbins;
846 index_t *offsets;
847 index_t number=0,number_geo=0,number_nongeo=0;
848 offset_t size;
849
850 /* Print the start message */
851
852 printf_first("Writing Errors: Geographical=0 Non-geographical=0");
853
854 /* Allocate the memory for the geographical offsets array */
855
856 offsets=(index_t*)malloc_logassert((errorlogsx->latbins*errorlogsx->lonbins+1)*sizeof(index_t));
857
858 latlonbin=0;
859
860 /* Re-open the file */
861
862 oldfd=ReOpenFileBuffered(errorbinfilename);
863
864 newfd=OpenFileBufferedNew(filename);
865
866 /* Write out the geographical errors */
867
868 SeekFileBuffered(newfd,sizeof(ErrorLogsFile)+(errorlogsx->latbins*errorlogsx->lonbins+1)*sizeof(index_t));
869
870 while(!ReadFileBuffered(oldfd,&errorlogx,sizeof(ErrorLogX)))
871 {
872 ErrorLog errorlog={0};
873 ll_bin_t latbin,lonbin;
874 ll_bin2_t llbin;
875
876 if(errorlogx.latitude==NO_LATLONG)
877 continue;
878
879 /* Create the ErrorLog */
880
881 errorlog.latoffset=latlong_to_off(errorlogx.latitude);
882 errorlog.lonoffset=latlong_to_off(errorlogx.longitude);
883
884 errorlog.offset=errorlogx.offset;
885 errorlog.length=errorlogx.length;
886
887 /* Work out the offsets */
888
889 latbin=latlong_to_bin(errorlogx.latitude )-errorlogsx->latzero;
890 lonbin=latlong_to_bin(errorlogx.longitude)-errorlogsx->lonzero;
891 llbin=lonbin*errorlogsx->latbins+latbin;
892
893 for(;latlonbin<=llbin;latlonbin++)
894 offsets[latlonbin]=number_geo;
895
896 /* Write the data */
897
898 WriteFileBuffered(newfd,&errorlog,sizeof(ErrorLog));
899
900 number_geo++;
901 number++;
902
903 if(!(number%10000))
904 printf_middle("Writing Errors: Geographical=%"Pindex_t" Non-geographical=%"Pindex_t,number_geo,number_nongeo);
905 }
906
907 /* Write out the non-geographical errors */
908
909 SeekFileBuffered(oldfd,0);
910
911 while(!ReadFileBuffered(oldfd,&errorlogx,sizeof(ErrorLogX)))
912 {
913 ErrorLog errorlog={0};
914
915 if(errorlogx.latitude!=NO_LATLONG)
916 continue;
917
918 /* Create the ErrorLog */
919
920 errorlog.latoffset=0;
921 errorlog.lonoffset=0;
922
923 errorlog.offset=errorlogx.offset;
924 errorlog.length=errorlogx.length;
925
926 /* Write the data */
927
928 WriteFileBuffered(newfd,&errorlog,sizeof(ErrorLog));
929
930 number_nongeo++;
931 number++;
932
933 if(!(number%10000))
934 printf_middle("Writing Errors: Geographical=%"Pindex_t" Non-geographical=%"Pindex_t,number_geo,number_nongeo);
935 }
936
937 /* Close the input file */
938
939 CloseFileBuffered(oldfd);
940
941 DeleteFile(errorbinfilename);
942
943 /* Append the text from the log file */
944
945 size=SizeFile(errorlogfilename);
946
947 oldfd=ReOpenFileBuffered(errorlogfilename);
948
949 while(size)
950 {
951 int i;
952 char buffer[4096];
953 offset_t chunksize=(size>(offset_t)sizeof(buffer)?(offset_t)sizeof(buffer):size);
954
955 ReadFileBuffered(oldfd,buffer,chunksize);
956
957 for(i=0;i<chunksize;i++)
958 if(buffer[i]=='\n')
959 buffer[i]=0;
960
961 WriteFileBuffered(newfd,buffer,chunksize);
962
963 size-=chunksize;
964 }
965
966 CloseFileBuffered(oldfd);
967
968 /* Finish off the offset indexing and write them out */
969
970 maxlatlonbins=errorlogsx->latbins*errorlogsx->lonbins;
971
972 for(;latlonbin<=maxlatlonbins;latlonbin++)
973 offsets[latlonbin]=number_geo;
974
975 SeekFileBuffered(newfd,sizeof(ErrorLogsFile));
976 WriteFileBuffered(newfd,offsets,(errorlogsx->latbins*errorlogsx->lonbins+1)*sizeof(index_t));
977
978 free(offsets);
979
980 /* Write out the header structure */
981
982 errorlogsfile.number =number;
983 errorlogsfile.number_geo =number_geo;
984 errorlogsfile.number_nongeo=number_nongeo;
985
986 errorlogsfile.latbins=errorlogsx->latbins;
987 errorlogsfile.lonbins=errorlogsx->lonbins;
988
989 errorlogsfile.latzero=errorlogsx->latzero;
990 errorlogsfile.lonzero=errorlogsx->lonzero;
991
992 SeekFileBuffered(newfd,0);
993 WriteFileBuffered(newfd,&errorlogsfile,sizeof(ErrorLogsFile));
994
995 CloseFileBuffered(newfd);
996
997 /* Print the final message */
998
999 printf_last("Wrote Errors: Geographical=%"Pindex_t" Non-geographical=%"Pindex_t,number_geo,number_nongeo);
1000 }