1 /*
2 / Network.cpp
3 / methods related to Network building
4 /
5 / version 1.7, 2013 May 8
6 /
7 / Author: Sandro Furieri a-furieri@lqt.it
8 /
9 / Copyright (C) 2008-2013 Alessandro Furieri
10 /
11 / This program is free software: you can redistribute it and/or modify
12 / it under the terms of the GNU General Public License as published by
13 / the Free Software Foundation, either version 3 of the License, or
14 / (at your option) any later version.
15 /
16 / This program is distributed in the hope that it will be useful,
17 / but WITHOUT ANY WARRANTY; without even the implied warranty of
18 / MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 / GNU General Public License for more details.
20 /
21 / You should have received a copy of the GNU General Public License
22 / along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /
24 */
25
26 #include "Classdef.h"
27 #include <float.h>
28
29 #if defined(_WIN32) && !defined(__MINGW32__)
30 #define strcasecmp _stricmp
31 #endif
32
33 #define MAX_BLOCK 1048576
34
35 void
BuildNetwork(wxString & table,wxString & from,wxString & to,wxString & geometry,wxString & name,bool cost_length,wxString & cost,bool bidirectional,bool one_way,wxString & one_way_from_to,wxString & one_way_to_from,bool aStarSupported)36 MyFrame::BuildNetwork(wxString & table, wxString & from, wxString & to,
37 wxString & geometry, wxString & name, bool cost_length,
38 wxString & cost, bool bidirectional, bool one_way,
39 wxString & one_way_from_to, wxString & one_way_to_from,
40 bool aStarSupported)
41 {
42 //
43 // trying to build a Network
44 //
45 int ret;
46 sqlite3_stmt *stmt;
47 Network *p_graph = NULL;
48 wxString sql;
49 char xsql[2048];
50 char **results;
51 int n_rows;
52 int n_columns;
53 int i;
54 char *errMsg = NULL;
55 char *col_name;
56 int type;
57 bool ok_from_column = false;
58 bool ok_to_column = false;
59 bool ok_cost_column = false;
60 bool ok_geom_column = false;
61 bool ok_name_column = false;
62 bool ok_oneway_tofrom = false;
63 bool ok_oneway_fromto = false;
64 bool from_null = false;
65 bool from_int = false;
66 bool from_double = false;
67 bool from_text = false;
68 bool from_blob = false;
69 bool to_null = false;
70 bool to_int = false;
71 bool to_double = false;
72 bool to_text = false;
73 bool to_blob = false;
74 bool cost_null = false;
75 bool cost_text = false;
76 bool cost_blob = false;
77 bool tofrom_null = false;
78 bool tofrom_double = false;
79 bool tofrom_text = false;
80 bool tofrom_blob = false;
81 bool fromto_null = false;
82 bool fromto_double = false;
83 bool fromto_text = false;
84 bool fromto_blob = false;
85 bool geom_null = false;
86 bool geom_not_linestring = false;
87 int col_n;
88 int fromto_n = 0;
89 int tofrom_n = 0;
90 sqlite3_int64 rowid;
91 sqlite3_int64 id_from = -1;
92 sqlite3_int64 id_to = -1;
93 char code_from[1024];
94 char code_to[1024];
95 double node_from_x;
96 double node_from_y;
97 double node_to_x;
98 double node_to_y;
99 double cost_val;
100 int fromto;
101 int tofrom;
102 wxString endMsg;
103 wxString msg;
104 bool wr;
105 bool aStarLength;
106 double a_star_length;
107 double a_star_coeff;
108 double min_a_star_coeff = DBL_MAX;
109 char xname[1024];
110 ::wxBeginBusyCursor();
111 // checking for table existence
112 sql =
113 wxT("SELECT tbl_name FROM sqlite_master WHERE Lower(tbl_name) = Lower('");
114 strcpy(xname, table.ToUTF8());
115 CleanSqlString(xname);
116 sql += wxString::FromUTF8(xname);
117 sql += wxT("') AND type = 'table'");
118 strcpy(xsql, sql.ToUTF8());
119 ret =
120 sqlite3_get_table(SqliteHandle, xsql, &results, &n_rows, &n_columns,
121 &errMsg);
122 if (ret != SQLITE_OK)
123 {
124 // some error occurred
125 wxMessageBox(wxT("SQLite SQL error: ") + wxString::FromUTF8(errMsg),
126 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
127 sqlite3_free(errMsg);
128 goto abort;
129 }
130 if (n_rows == 0)
131 {
132 // required table does not exists
133 wxMessageBox(wxT("ERROR: table ") + table + wxT(" does not exists"),
134 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
135 goto abort;
136 } else
137 sqlite3_free_table(results);
138 // checking for columns existence
139 sql = wxT("PRAGMA table_info(");
140 strcpy(xname, table.ToUTF8());
141 DoubleQuotedSql(xname);
142 sql += wxString::FromUTF8(xname);
143 sql += wxT(")");
144 strcpy(xsql, sql.ToUTF8());
145 ret =
146 sqlite3_get_table(SqliteHandle, xsql, &results, &n_rows, &n_columns,
147 &errMsg);
148 if (ret != SQLITE_OK)
149 {
150 // some error occurred
151 wxMessageBox(wxT("SQLite SQL error: ") + wxString::FromUTF8(errMsg),
152 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
153 sqlite3_free(errMsg);
154 goto abort;
155 }
156 if (n_rows > 1)
157 {
158 for (i = 1; i <= n_rows; i++)
159 {
160 char xcol[256];
161 col_name = results[(i * n_columns) + 1];
162 strcpy(xcol, from.ToUTF8());
163 if (strcasecmp(xcol, col_name) == 0)
164 ok_from_column = true;
165 strcpy(xcol, to.ToUTF8());
166 if (strcasecmp(xcol, col_name) == 0)
167 ok_to_column = true;
168 if (cost_length == false)
169 {
170 strcpy(xcol, cost.ToUTF8());
171 if (strcasecmp(xcol, col_name) == 0)
172 ok_cost_column = true;
173 }
174 strcpy(xcol, geometry.ToUTF8());
175 if (strcasecmp(xcol, col_name) == 0)
176 ok_geom_column = true;
177 if (name.Len() > 0)
178 {
179 strcpy(xcol, name.ToUTF8());
180 if (strcasecmp(xcol, col_name) == 0)
181 ok_name_column = true;
182 }
183 if (one_way == true)
184 {
185 strcpy(xcol, one_way_from_to.ToUTF8());
186 if (strcasecmp(xcol, col_name) == 0)
187 ok_oneway_tofrom = true;
188 }
189 if (one_way == true)
190 {
191 strcpy(xcol, one_way_to_from.ToUTF8());
192 if (strcasecmp(xcol, col_name) == 0)
193 ok_oneway_fromto = true;
194 }
195 }
196 sqlite3_free_table(results);
197 }
198 if (ok_from_column == true && ok_to_column == true && ok_geom_column == true)
199 ;
200 else
201 goto abort;
202 if (name.Len() > 0 && ok_name_column == false)
203 goto abort;
204 if (cost_length == false && ok_cost_column == false)
205 goto abort;
206 if (one_way == true && ok_oneway_tofrom == false)
207 goto abort;
208 if (one_way == true && ok_oneway_fromto == false)
209 goto abort;
210 // checking column types
211 p_graph = new Network();
212 strcpy(xname, from.ToUTF8());
213 DoubleQuotedSql(xname);
214 sql = wxT("SELECT ") + wxString::FromUTF8(xname);
215 strcpy(xname, to.ToUTF8());
216 DoubleQuotedSql(xname);
217 sql += wxT(", ") + wxString::FromUTF8(xname);
218 strcpy(xname, geometry.ToUTF8());
219 DoubleQuotedSql(xname);
220 sql += wxT(", GeometryType(") + wxString::FromUTF8(xname) + wxT(")");
221 col_n = 3;
222 if (cost_length == false)
223 {
224 strcpy(xname, cost.ToUTF8());
225 DoubleQuotedSql(xname);
226 sql += wxT(", ") + wxString::FromUTF8(xname);
227 col_n++;
228 }
229 if (one_way == true)
230 {
231 strcpy(xname, one_way_to_from.ToUTF8());
232 DoubleQuotedSql(xname);
233 sql += wxT(", ") + wxString::FromUTF8(xname);
234 tofrom_n = col_n;
235 col_n++;
236 strcpy(xname, one_way_from_to.ToUTF8());
237 DoubleQuotedSql(xname);
238 sql += wxT(", ") + wxString::FromUTF8(xname);
239 fromto_n = col_n;
240 col_n++;
241 }
242 strcpy(xname, table.ToUTF8());
243 DoubleQuotedSql(xname);
244 sql += wxT(" FROM ") + wxString::FromUTF8(xname);
245 strcpy(xsql, sql.ToUTF8());
246 ret = sqlite3_prepare_v2(SqliteHandle, xsql, strlen(xsql), &stmt, NULL);
247 if (ret != SQLITE_OK)
248 {
249 wxString err = wxString::FromUTF8(sqlite3_errmsg(SqliteHandle));
250 wxMessageBox(wxT("SQL error: ") + err, wxT("spatialite_gui"),
251 wxOK | wxICON_ERROR, this);
252 goto abort;
253 }
254 n_columns = sqlite3_column_count(stmt);
255 while (1)
256 {
257 ret = sqlite3_step(stmt);
258 if (ret == SQLITE_DONE)
259 break;
260 if (ret == SQLITE_ROW)
261 {
262 // the NodeFrom type
263 type = sqlite3_column_type(stmt, 0);
264 if (type == SQLITE_NULL)
265 from_null = true;
266 if (type == SQLITE_INTEGER)
267 {
268 from_int = true;
269 id_from = sqlite3_column_int(stmt, 0);
270 p_graph->InsertNode(id_from);
271 }
272 if (type == SQLITE_FLOAT)
273 from_double = true;
274 if (type == SQLITE_TEXT)
275 {
276 from_text = true;
277 strcpy(code_from, (char *) sqlite3_column_text(stmt, 0));
278 p_graph->InsertNode(code_from);
279 }
280 if (type == SQLITE_BLOB)
281 from_blob = true;
282 // the NodeTo type
283 type = sqlite3_column_type(stmt, 1);
284 if (type == SQLITE_NULL)
285 to_null = true;
286 if (type == SQLITE_INTEGER)
287 {
288 to_int = true;
289 id_to = sqlite3_column_int(stmt, 1);
290 p_graph->InsertNode(id_to);
291 }
292 if (type == SQLITE_FLOAT)
293 to_double = true;
294 if (type == SQLITE_TEXT)
295 {
296 to_text = true;
297 strcpy(code_to, (char *) sqlite3_column_text(stmt, 1));
298 p_graph->InsertNode(code_to);
299 }
300 if (type == SQLITE_BLOB)
301 to_blob = true;
302 // the Geometry type
303 type = sqlite3_column_type(stmt, 2);
304 if (type == SQLITE_NULL)
305 geom_null = true;
306 else if (strcmp("LINESTRING", (char *) sqlite3_column_text(stmt, 2))
307 != 0)
308 geom_not_linestring = true;
309 col_n = 3;
310 if (cost_length == false)
311 {
312 // the Cost type
313 type = sqlite3_column_type(stmt, col_n);
314 col_n++;
315 if (type == SQLITE_NULL)
316 cost_null = true;
317 if (type == SQLITE_TEXT)
318 cost_text = true;
319 if (type == SQLITE_BLOB)
320 cost_blob = true;
321 }
322 if (one_way == true)
323 {
324 // the FromTo type
325 type = sqlite3_column_type(stmt, col_n);
326 col_n++;
327 if (type == SQLITE_NULL)
328 fromto_null = true;
329 if (type == SQLITE_FLOAT)
330 fromto_double = true;
331 if (type == SQLITE_TEXT)
332 fromto_text = true;
333 if (type == SQLITE_BLOB)
334 fromto_blob = true;
335 // the ToFrom type
336 type = sqlite3_column_type(stmt, col_n);
337 col_n++;
338 if (type == SQLITE_NULL)
339 tofrom_null = true;
340 if (type == SQLITE_FLOAT)
341 tofrom_double = true;
342 if (type == SQLITE_TEXT)
343 tofrom_text = true;
344 if (type == SQLITE_BLOB)
345 tofrom_blob = true;
346 }
347 } else
348 {
349 wxString err = wxString::FromUTF8(sqlite3_errmsg(SqliteHandle));
350 wxMessageBox(wxT("sqlite3_step error: ") + err, wxT("spatialite_gui"),
351 wxOK | wxICON_ERROR, this);
352 sqlite3_finalize(stmt);
353 goto abort;
354 }
355 }
356 sqlite3_finalize(stmt);
357 ret = 1;
358 if (from_null == true)
359 ret = 0;
360 if (from_blob == true)
361 ret = 0;
362 if (from_double == true)
363 ret = 0;
364 if (to_null == true)
365 ret = 0;
366 if (to_blob == true)
367 ret = 0;
368 if (to_double == true)
369 ret = 0;
370 if (geom_null == true)
371 ret = 0;
372 if (geom_not_linestring == true)
373 ret = 0;
374 if (cost_length == false)
375 {
376 if (cost_null == true)
377 ret = 0;
378 if (cost_blob == true)
379 ret = 0;
380 if (cost_text == true)
381 ret = 0;
382 }
383 if (one_way == true)
384 {
385 if (fromto_null == true)
386 ret = 0;
387 if (fromto_blob == true)
388 ret = 0;
389 if (fromto_text == true)
390 ret = 0;
391 if (fromto_double == true)
392 ret = 0;
393 if (tofrom_null == true)
394 ret = 0;
395 if (tofrom_blob == true)
396 ret = 0;
397 if (tofrom_text == true)
398 ret = 0;
399 if (tofrom_double == true)
400 ret = 0;
401 }
402 if (!ret)
403 goto abort;
404 if (from_int == true && to_int == true)
405 {
406 // each node is identified by an INTEGER id
407 p_graph->SetNodeCode(false);
408 } else if (from_text == true && to_text == true)
409 {
410 // each node is identified by a TEXT code
411 p_graph->SetNodeCode(true);
412 } else
413 goto abort;
414 p_graph->InitNodes();
415 // checking topologic consistency
416 strcpy(xname, from.ToUTF8());
417 DoubleQuotedSql(xname);
418 sql = wxT("SELECT ROWID, ") + wxString::FromUTF8(xname);
419 strcpy(xname, to.ToUTF8());
420 DoubleQuotedSql(xname);
421 sql += wxT(", ") + wxString::FromUTF8(xname) + wxT(", ");
422 strcpy(xname, geometry.ToUTF8());
423 DoubleQuotedSql(xname);
424 sql +=
425 wxT("X(StartPoint(") + wxString::FromUTF8(xname) + wxT(")), Y(StartPoint(");
426 sql += wxString::FromUTF8(xname) + wxT(")), ");
427 sql +=
428 wxT("X(EndPoint(") + wxString::FromUTF8(xname) + wxT(")), Y(EndPoint(");
429 sql += wxString::FromUTF8(xname) + wxT("))");
430 if (aStarSupported == true)
431 {
432 // supporting A* algorithm
433 if (cost_length == false)
434 {
435 strcpy(xname, cost.ToUTF8());
436 DoubleQuotedSql(xname);
437 sql += wxT(", ") + wxString::FromUTF8(xname);
438 strcpy(xname, geometry.ToUTF8());
439 DoubleQuotedSql(xname);
440 sql += wxT(", GLength(") + wxString::FromUTF8(xname) + wxT(")");
441 col_n = 9;
442 aStarLength = true;
443 } else
444 {
445 strcpy(xname, geometry.ToUTF8());
446 DoubleQuotedSql(xname);
447 sql += wxT(", GLength(") + wxString::FromUTF8(xname) + wxT(")");
448 col_n = 8;
449 aStarLength = false;
450 min_a_star_coeff = 1.0;
451 }
452 } else
453 {
454 // A* algorithm unsupported
455 if (cost_length == false)
456 {
457 strcpy(xname, cost.ToUTF8());
458 DoubleQuotedSql(xname);
459 sql += wxT(", ") + wxString::FromUTF8(xname);
460 } else
461 {
462 strcpy(xname, geometry.ToUTF8());
463 DoubleQuotedSql(xname);
464 sql += wxT(", GLength(") + wxString::FromUTF8(xname) + wxT(")");
465 }
466 col_n = 8;
467 aStarLength = false;
468 }
469 if (one_way == true)
470 {
471 strcpy(xname, one_way_to_from.ToUTF8());
472 DoubleQuotedSql(xname);
473 sql += wxT(", ") + wxString::FromUTF8(xname);
474 tofrom_n = col_n;
475 col_n++;
476 strcpy(xname, one_way_from_to.ToUTF8());
477 DoubleQuotedSql(xname);
478 sql += wxT(", ") + wxString::FromUTF8(xname);
479 fromto_n = col_n;
480 col_n++;
481 }
482 strcpy(xname, table.ToUTF8());
483 DoubleQuotedSql(xname);
484 sql += wxT(" FROM ") + wxString::FromUTF8(xname);
485 strcpy(xsql, sql.ToUTF8());
486 ret = sqlite3_prepare_v2(SqliteHandle, xsql, strlen(xsql), &stmt, NULL);
487 if (ret != SQLITE_OK)
488 {
489 wxString err = wxString::FromUTF8(sqlite3_errmsg(SqliteHandle));
490 wxMessageBox(wxT("SQL error: ") + err, wxT("spatialite_gui"),
491 wxOK | wxICON_ERROR, this);
492 goto abort;
493 }
494 n_columns = sqlite3_column_count(stmt);
495 while (1)
496 {
497 ret = sqlite3_step(stmt);
498 if (ret == SQLITE_DONE)
499 break;
500 if (ret == SQLITE_ROW)
501 {
502 fromto = true;
503 tofrom = true;
504 if (p_graph->IsNodeCode() == true)
505 {
506 id_from = -1;
507 id_to = -1;
508 } else
509 {
510 *code_from = '\0';
511 *code_to = '\0';
512 }
513 // fetching the ROWID
514 rowid = sqlite3_column_int64(stmt, 0);
515 // fetching the NodeFrom value
516 if (p_graph->IsNodeCode() == true)
517 strcpy(code_from, (char *) sqlite3_column_text(stmt, 1));
518 else
519 id_from = sqlite3_column_int64(stmt, 1);
520 // fetching the NodeTo value
521 if (p_graph->IsNodeCode() == true)
522 strcpy(code_to, (char *) sqlite3_column_text(stmt, 2));
523 else
524 id_to = sqlite3_column_int64(stmt, 2);
525 // fetching the NodeFromX value
526 node_from_x = sqlite3_column_double(stmt, 3);
527 // fetching the NodeFromY value
528 node_from_y = sqlite3_column_double(stmt, 4);
529 // fetching the NodeFromX value
530 node_to_x = sqlite3_column_double(stmt, 5);
531 // fetching the NodeFromY value
532 node_to_y = sqlite3_column_double(stmt, 6);
533 // fetching the Cost value
534 cost_val = sqlite3_column_double(stmt, 7);
535 if (one_way == true)
536 {
537 // fetching the OneWay-FromTo value
538 fromto = sqlite3_column_int(stmt, fromto_n);
539 // fetching the OneWay-ToFrom value
540 tofrom = sqlite3_column_int(stmt, tofrom_n);
541 }
542 if (cost_val <= 0.0)
543 p_graph->SetError();
544 if (aStarLength == true)
545 {
546 // supporting A* - fetching the arc length
547 a_star_length = sqlite3_column_double(stmt, 8);
548 a_star_coeff = cost_val / a_star_length;
549 if (a_star_coeff < min_a_star_coeff)
550 min_a_star_coeff = a_star_coeff;
551 }
552 if (one_way == true)
553 {
554 // fetching the OneWay-FromTo value
555 fromto = sqlite3_column_int(stmt, fromto_n);
556 // fetching the OneWay-ToFrom value
557 tofrom = sqlite3_column_int(stmt, tofrom_n);
558 }
559 if (bidirectional == true)
560 {
561 if (fromto)
562 {
563 if (p_graph->IsNodeCode() == true)
564 p_graph->AddArc(rowid, code_from, code_to, node_from_x,
565 node_from_y, node_to_x, node_to_y,
566 cost_val);
567 else
568 p_graph->AddArc(rowid, id_from, id_to, node_from_x,
569 node_from_y, node_to_x, node_to_y,
570 cost_val);
571 }
572 if (tofrom)
573 {
574 if (p_graph->IsNodeCode() == true)
575 p_graph->AddArc(rowid, code_to, code_from, node_to_x,
576 node_to_y, node_from_x, node_from_y,
577 cost_val);
578 else
579 p_graph->AddArc(rowid, id_to, id_from, node_to_x, node_to_y,
580 node_from_x, node_from_y, cost_val);
581 }
582 } else
583 {
584 if (p_graph->IsNodeCode() == true)
585 p_graph->AddArc(rowid, code_from, code_to, node_from_x,
586 node_from_y, node_to_x, node_to_y, cost_val);
587 else
588 p_graph->AddArc(rowid, id_from, id_to, node_from_x, node_from_y,
589 node_to_x, node_to_y, cost_val);
590 }
591 if (p_graph->IsError() == true)
592 {
593 sqlite3_finalize(stmt);
594 goto abort;
595 }
596 } else
597 {
598 wxString err = wxString::FromUTF8(sqlite3_errmsg(SqliteHandle));
599 wxMessageBox(wxT("sqlite3_step error: ") + err, wxT("spatialite_gui"),
600 wxOK | wxICON_ERROR, this);
601 sqlite3_finalize(stmt);
602 goto abort;
603 }
604 }
605 sqlite3_finalize(stmt);
606 ::wxEndBusyCursor();
607 wr =
608 CreateNetwork(p_graph, table, from, to, geometry, name, aStarSupported,
609 min_a_star_coeff);
610 if (wr == true)
611 {
612 endMsg =
613 wxT("OK: VirtualNetwork table '") + table +
614 wxT("_net' successfully created");
615 wxMessageBox(endMsg, wxT("spatialite_gui"), wxOK | wxICON_INFORMATION,
616 this);
617 } else
618 {
619 endMsg =
620 wxT("DB ERROR: VirtualNetwork table '") + table +
621 wxT("_net' was not created");
622 wxMessageBox(endMsg, wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
623 }
624 if (p_graph)
625 delete p_graph;
626 InitTableTree();
627 return;
628 abort:
629 ::wxEndBusyCursor();
630 msg =
631 wxT
632 ("It's impossible to build a Network using the given configuration;\nsome fatal error occurred\n\n");
633 msg += wxT("please note: using the 'spatialite_network' command-line tool\n");
634 msg +=
635 wxT
636 ("you can obtain a full detailed report explaining causes for this failure");
637 wxMessageBox(msg, wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
638 if (p_graph)
639 delete p_graph;
640 }
641
642 void
OutputNetNode(unsigned char * auxbuf,int * size,int ind,bool node_code,int max_node_length,NetNode * pN,int endian_arch,bool aStarSupported)643 MyFrame::OutputNetNode(unsigned char *auxbuf, int *size, int ind,
644 bool node_code, int max_node_length, NetNode * pN,
645 int endian_arch, bool aStarSupported)
646 {
647 //
648 // exporting a Node into NETWORK-DATA
649 //
650 int n_star;
651 int i;
652 NetArc **arc_array;
653 NetArc *pA;
654 unsigned char *out = auxbuf;
655 *out++ = GAIA_NET_NODE;
656 gaiaExport32(out, ind, 1, endian_arch); // the Node internal index
657 out += 4;
658 if (node_code)
659 {
660 // Nodes are identified by a TEXT Code
661 memset(out, '\0', max_node_length);
662 strcpy((char *) out, pN->GetCode().ToUTF8());
663 out += max_node_length;
664 } else
665 {
666 // Nodes are identified by an INTEGER Id
667 gaiaExportI64(out, pN->GetId(), 1, endian_arch);
668 out += 8;
669 }
670 if (aStarSupported)
671 {
672 // in order to support the A* algorithm [X,Y] are required for each node
673 gaiaExport64(out, pN->GetX(), 1, endian_arch);
674 out += 8;
675 gaiaExport64(out, pN->GetY(), 1, endian_arch);
676 out += 8;
677 }
678 arc_array = pN->PrepareOutcomings(&n_star);
679 gaiaExport16(out, n_star, 1, endian_arch); // # of outcoming arcs
680 out += 2;
681 for (i = 0; i < n_star; i++)
682 {
683 // exporting the outcoming arcs
684 pA = *(arc_array + i);
685 *out++ = GAIA_NET_ARC;
686 gaiaExportI64(out, pA->GetRowId(), 1, endian_arch); // the Arc rowid
687 out += 8;
688 gaiaExport32(out, pA->GetTo()->GetInternalIndex(), 1, endian_arch); // the ToNode internal index
689 out += 4;
690 gaiaExport64(out, pA->GetCost(), 1, endian_arch); // the Arc Cost
691 out += 8;
692 *out++ = GAIA_NET_END;
693 }
694 if (arc_array)
695 delete[]arc_array;
696 *out++ = GAIA_NET_END;
697 *size = out - auxbuf;
698 }
699
CreateNetwork(Network * p_graph,wxString & table,wxString & from,wxString & to,wxString & geometry,wxString & name,bool aStarSupported,double aStarCoeff)700 bool MyFrame::CreateNetwork(Network * p_graph, wxString & table,
701 wxString & from, wxString & to, wxString & geometry,
702 wxString & name, bool aStarSupported,
703 double aStarCoeff)
704 {
705 //
706 // creates the NETWORK-DATA table
707 //
708 int ret;
709 wxString sql;
710 char xsql[1024];
711 char *errMsg = NULL;
712 unsigned char *auxbuf = new unsigned char[MAX_BLOCK];
713 unsigned char *buf = new unsigned char[MAX_BLOCK];
714 unsigned char *out;
715 sqlite3_stmt *stmt;
716 int i;
717 int size;
718 int endian_arch = gaiaEndianArch();
719 NetNode *pN;
720 int pk = 0;
721 int nodes_cnt = 0;
722 int len;
723 bool net_data_exists = false;
724 bool net_exists = false;
725 bool delete_existing = false;
726 char xname[1024];
727 wxString data_table = table + wxT("_net_data");
728 wxString net_table = table + wxT("_net");
729 net_data_exists = TableAlreadyExists(data_table);
730 net_exists = TableAlreadyExists(net_table);
731 if (net_data_exists == true || net_exists == true)
732 {
733 // asking permission to overwrite existing tables
734 wxString msg;
735 if (net_data_exists == true)
736 msg += wxT("A table named '") + data_table + wxT("' already exists\n");
737 if (net_exists == true)
738 msg += wxT("A table named '") + net_table + wxT("' already exists\n");
739 msg += wxT("\nDo you allow DROPping existing table(s) ?");
740 wxMessageDialog confirm(this, msg, wxT("Confirm overwrite"),
741 wxYES_NO | wxICON_QUESTION);
742 ret = confirm.ShowModal();
743 if (ret == wxID_YES)
744 delete_existing = true;
745 }
746 ::wxBeginBusyCursor();
747 for (i = 0; i < p_graph->GetNumNodes(); i++)
748 {
749 // setting the internal index to each Node
750 pN = p_graph->GetSortedNode(i);
751 pN->SetInternalIndex(i);
752 }
753 // starts a transaction
754 ret = sqlite3_exec(SqliteHandle, "BEGIN", NULL, NULL, &errMsg);
755 if (ret != SQLITE_OK)
756 {
757 wxMessageBox(wxT("BEGIN error: ") + wxString::FromUTF8(errMsg),
758 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
759 sqlite3_free(errMsg);
760 goto abort;
761 }
762 if (delete_existing == true)
763 {
764 strcpy(xname, net_table.ToUTF8());
765 DoubleQuotedSql(xname);
766 sql = wxT("DROP TABLE IF EXISTS ") + wxString::FromUTF8(xname);
767 strcpy(xsql, sql.ToUTF8());
768 ret = sqlite3_exec(SqliteHandle, xsql, NULL, NULL, &errMsg);
769 if (ret != SQLITE_OK)
770 {
771 wxMessageBox(wxT("DROP TABLE error: ") + wxString::FromUTF8(errMsg),
772 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
773 sqlite3_free(errMsg);
774 goto abort;
775 }
776 strcpy(xname, data_table.ToUTF8());
777 DoubleQuotedSql(xname);
778 sql = wxT("DROP TABLE IF EXISTS ") + wxString::FromUTF8(xname);
779 strcpy(xsql, sql.ToUTF8());
780 ret = sqlite3_exec(SqliteHandle, xsql, NULL, NULL, &errMsg);
781 if (ret != SQLITE_OK)
782 {
783 wxMessageBox(wxT("DROP TABLE error: ") + wxString::FromUTF8(errMsg),
784 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
785 sqlite3_free(errMsg);
786 goto abort;
787 }
788 }
789 // creating the NETWORK-DATA table
790 strcpy(xname, data_table.ToUTF8());
791 DoubleQuotedSql(xname);
792 sql = wxT("CREATE TABLE ") + wxString::FromUTF8(xname);
793 sql += wxT(" (Id INTEGER PRIMARY KEY, NetworkData BLOB NOT NULL)");
794 strcpy(xsql, sql.ToUTF8());
795 ret = sqlite3_exec(SqliteHandle, xsql, NULL, NULL, &errMsg);
796 if (ret != SQLITE_OK)
797 {
798 wxMessageBox(wxT("CREATE TABLE error: ") + wxString::FromUTF8(errMsg),
799 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
800 sqlite3_free(errMsg);
801 goto abort;
802 }
803 // preparing the SQL statement
804 strcpy(xname, data_table.ToUTF8());
805 DoubleQuotedSql(xname);
806 sql =
807 wxT("INSERT INTO ") + wxString::FromUTF8(xname) +
808 wxT(" (Id, NetworkData) VALUES (?, ?)");
809 strcpy(xsql, sql.ToUTF8());
810 ret = sqlite3_prepare_v2(SqliteHandle, xsql, strlen(xsql), &stmt, NULL);
811 if (ret != SQLITE_OK)
812 {
813 wxString err = wxString::FromUTF8(sqlite3_errmsg(SqliteHandle));
814 wxMessageBox(wxT("INSERT error: ") + err, wxT("spatialite_gui"),
815 wxOK | wxICON_ERROR, this);
816 goto abort;
817 }
818 if (pk == 0)
819 {
820 // preparing the HEADER block
821 out = buf;
822 if (aStarSupported)
823 *out++ = GAIA_NET64_A_STAR_START;
824 else
825 *out++ = GAIA_NET64_START;
826 *out++ = GAIA_NET_HEADER;
827 gaiaExport32(out, p_graph->GetNumNodes(), 1, endian_arch); // how many Nodes are there
828 out += 4;
829 if (p_graph->IsNodeCode() == true)
830 *out++ = GAIA_NET_CODE; // Nodes are identified by a TEXT code
831 else
832 *out++ = GAIA_NET_ID; // Nodes are identified by an INTEGER id
833 if (p_graph->IsNodeCode() == true)
834 *out++ = p_graph->GetMaxCodeLength(); // max TEXT code length
835 else
836 *out++ = 0x00;
837 // inserting the main Table name
838 *out++ = GAIA_NET_TABLE;
839 len = table.Len() + 1;
840 gaiaExport16(out, len, 1, endian_arch); // the Table Name length, including last '\0'
841 out += 2;
842 memset(out, '\0', len);
843 strcpy((char *) out, table.ToUTF8());
844 out += len;
845 // inserting the NodeFrom column name
846 *out++ = GAIA_NET_FROM;
847 len = from.Len() + 1;
848 gaiaExport16(out, len, 1, endian_arch); // the NodeFrom column Name length, including last '\0'
849 out += 2;
850 memset(out, '\0', len);
851 strcpy((char *) out, from.ToUTF8());
852 out += len;
853 // inserting the NodeTo column name
854 *out++ = GAIA_NET_TO;
855 len = to.Len() + 1;
856 gaiaExport16(out, len, 1, endian_arch); // the NodeTo column Name length, including last '\0'
857 out += 2;
858 memset(out, '\0', len);
859 strcpy((char *) out, to.ToUTF8());
860 out += len;
861 // inserting the Geometry column name
862 *out++ = GAIA_NET_GEOM;
863 len = geometry.Len() + 1;
864 gaiaExport16(out, len, 1, endian_arch); // the Geometry column Name length, including last '\0'
865 out += 2;
866 memset(out, '\0', len);
867 strcpy((char *) out, geometry.ToUTF8());
868 out += len;
869 // inserting the Name column name - may be empty
870 *out++ = GAIA_NET_NAME;
871 if (name.Len() == 0)
872 len = 1;
873 else
874 len = name.Len() + 1;
875 gaiaExport16(out, len, 1, endian_arch); // the Name column Name length, including last '\0'
876 out += 2;
877 memset(out, '\0', len);
878 if (name.Len() > 0)
879 strcpy((char *) out, name.ToUTF8());
880 out += len;
881 if (aStarSupported)
882 {
883 // inserting the A* Heuristic Coeff
884 *out++ = GAIA_NET_A_STAR_COEFF;
885 gaiaExport64(out, aStarCoeff, 1, endian_arch);
886 out += 8;
887 }
888 *out++ = GAIA_NET_END;
889 // INSERTing the Header block
890 sqlite3_reset(stmt);
891 sqlite3_clear_bindings(stmt);
892 sqlite3_bind_int64(stmt, 1, pk);
893 sqlite3_bind_blob(stmt, 2, buf, out - buf, SQLITE_STATIC);
894 ret = sqlite3_step(stmt);
895 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
896 ;
897 else
898 {
899 wxString err = wxString::FromUTF8(sqlite3_errmsg(SqliteHandle));
900 wxMessageBox(wxT("sqlite3_step error: ") + err, wxT("spatialite_gui"),
901 wxOK | wxICON_ERROR, this);
902 sqlite3_finalize(stmt);
903 goto abort;
904 }
905 pk++;
906 // preparing a new block
907 out = buf;
908 *out++ = GAIA_NET_BLOCK;
909 gaiaExport16(out, 0, 1, endian_arch); // how many Nodes are into this block
910 out += 2;
911 nodes_cnt = 0;
912 }
913 for (i = 0; i < p_graph->GetNumNodes(); i++)
914 {
915 // looping on each Node
916 pN = p_graph->GetSortedNode(i);
917 OutputNetNode(auxbuf, &size, i, p_graph->IsNodeCode(),
918 p_graph->GetMaxCodeLength(), pN, endian_arch,
919 aStarSupported);
920 if (size >= (MAX_BLOCK - (out - buf)))
921 {
922 // inserting the last block
923 gaiaExport16(buf + 1, nodes_cnt, 1, endian_arch); // how many Nodes are into this block
924 sqlite3_reset(stmt);
925 sqlite3_clear_bindings(stmt);
926 sqlite3_bind_int64(stmt, 1, pk);
927 sqlite3_bind_blob(stmt, 2, buf, out - buf, SQLITE_STATIC);
928 ret = sqlite3_step(stmt);
929 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
930 ;
931 else
932 {
933 wxString err = wxString::FromUTF8(sqlite3_errmsg(SqliteHandle));
934 wxMessageBox(wxT("sqlite3_step error: ") + err,
935 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
936 sqlite3_finalize(stmt);
937 goto abort;
938 }
939 pk++;
940 // preparing a new block
941 out = buf;
942 *out++ = GAIA_NET_BLOCK;
943 gaiaExport16(out, 0, 1, endian_arch); // how many Nodes are into this block
944 out += 2;
945 nodes_cnt = 0;
946 }
947 // inserting the current Node into the block
948 nodes_cnt++;
949 memcpy(out, auxbuf, size);
950 out += size;
951 }
952 if (nodes_cnt)
953 {
954 // inserting the last block
955 gaiaExport16(buf + 1, nodes_cnt, 1, endian_arch); // how many Nodes are into this block
956 sqlite3_reset(stmt);
957 sqlite3_clear_bindings(stmt);
958 sqlite3_bind_int64(stmt, 1, pk);
959 sqlite3_bind_blob(stmt, 2, buf, out - buf, SQLITE_STATIC);
960 ret = sqlite3_step(stmt);
961 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
962 ;
963 else
964 {
965 wxString err = wxString::FromUTF8(sqlite3_errmsg(SqliteHandle));
966 wxMessageBox(wxT("sqlite3_step error: ") + err, wxT("spatialite_gui"),
967 wxOK | wxICON_ERROR, this);
968 sqlite3_finalize(stmt);
969 goto abort;
970 }
971 }
972 sqlite3_finalize(stmt);
973 // creating the VirtualNetwork NET-table
974 strcpy(xname, net_table.ToUTF8());
975 DoubleQuotedSql(xname);
976 sql = wxT("CREATE VIRTUAL TABLE ") + wxString::FromUTF8(xname);
977 sql += wxT(" USING VirtualNetwork(");
978 strcpy(xname, data_table.ToUTF8());
979 DoubleQuotedSql(xname);
980 sql += wxString::FromUTF8(xname) + wxT(")");
981 strcpy(xsql, sql.ToUTF8());
982 ret = sqlite3_exec(SqliteHandle, xsql, NULL, NULL, &errMsg);
983 if (ret != SQLITE_OK)
984 {
985 wxMessageBox(wxT("CREATE VIRTUAL TABLE error: ") +
986 wxString::FromUTF8(errMsg), wxT("spatialite_gui"),
987 wxOK | wxICON_ERROR, this);
988 sqlite3_free(errMsg);
989 goto abort;
990 }
991 // commits the transaction
992 ret = sqlite3_exec(SqliteHandle, "COMMIT", NULL, NULL, &errMsg);
993 if (ret != SQLITE_OK)
994 {
995 wxMessageBox(wxT("COMMIT error: ") + wxString::FromUTF8(errMsg),
996 wxT("spatialite_gui"), wxOK | wxICON_ERROR, this);
997 sqlite3_free(errMsg);
998 goto abort;
999 }
1000 if (buf)
1001 delete[]buf;
1002 if (auxbuf)
1003 delete[]auxbuf;
1004 ::wxEndBusyCursor();
1005 return true;
1006 abort:
1007 ::wxEndBusyCursor();
1008 if (buf)
1009 delete[]buf;
1010 if (auxbuf)
1011 delete[]auxbuf;
1012 return true;
1013 return false;
1014 }
1015
cmp_prenodes_code(const void * p1,const void * p2)1016 int cmp_prenodes_code(const void *p1, const void *p2)
1017 {
1018 //
1019 // compares two preliminary nodes by CODE [for QSORT]
1020 //
1021 NetNodePre *pP1 = *((NetNodePre **) p1);
1022 NetNodePre *pP2 = *((NetNodePre **) p2);
1023 return pP1->GetCode().Cmp(pP2->GetCode());
1024 }
1025
cmp_prenodes_id(const void * p1,const void * p2)1026 int cmp_prenodes_id(const void *p1, const void *p2)
1027 {
1028 //
1029 // compares two preliminary nodes by ID [for QSORT]
1030 //
1031 NetNodePre *pP1 = *((NetNodePre **) p1);
1032 NetNodePre *pP2 = *((NetNodePre **) p2);
1033 if (pP1->GetId() == pP2->GetId())
1034 return 0;
1035 if (pP1->GetId() > pP2->GetId())
1036 return 1;
1037 return -1;
1038 }
1039
cmp_nodes2_code(const void * p1,const void * p2)1040 int cmp_nodes2_code(const void *p1, const void *p2)
1041 {
1042 //
1043 // compares two nodes by CODE [for BSEARCH]
1044 //
1045 NetNode *pN1 = (NetNode *) p1;
1046 NetNode *pN2 = *((NetNode **) p2);
1047 return pN1->GetCode().Cmp(pN2->GetCode());
1048 }
1049
cmp_nodes2_id(const void * p1,const void * p2)1050 int cmp_nodes2_id(const void *p1, const void *p2)
1051 {
1052 //
1053 // compares two nodes by ID [for BSEARCH]
1054 //
1055 NetNode *pN1 = (NetNode *) p1;
1056 NetNode *pN2 = *((NetNode **) p2);
1057 if (pN1->GetId() == pN2->GetId())
1058 return 0;
1059 if (pN1->GetId() > pN2->GetId())
1060 return 1;
1061 return -1;
1062 }
1063
cmp_nodes1_code(const void * p1,const void * p2)1064 int cmp_nodes1_code(const void *p1, const void *p2)
1065 {
1066 //
1067 // compares two nodes by CODE [for QSORT]
1068 //
1069 NetNode *pN1 = *((NetNode **) p1);
1070 NetNode *pN2 = *((NetNode **) p2);
1071 return pN1->GetCode().Cmp(pN2->GetCode());
1072 }
1073
cmp_nodes1_id(const void * p1,const void * p2)1074 int cmp_nodes1_id(const void *p1, const void *p2)
1075 {
1076 //
1077 // compares two nodes by ID [for QSORT ]
1078 //
1079 NetNode *pN1 = *((NetNode **) p1);
1080 NetNode *pN2 = *((NetNode **) p2);
1081 if (pN1->GetId() == pN2->GetId())
1082 return 0;
1083 if (pN1->GetId() > pN2->GetId())
1084 return 1;
1085 return -1;
1086 }
1087
NetNodePre(sqlite3_int64 id)1088 NetNodePre::NetNodePre(sqlite3_int64 id)
1089 {
1090 //
1091 // Network Node [preliminary] constructor
1092 //
1093 Id = id;
1094 Code = wxT("");
1095 Next = NULL;
1096 }
1097
NetNodePre(const char * code)1098 NetNodePre::NetNodePre(const char *code)
1099 {
1100 //
1101 // Network Node [preliminary] constructor
1102 //
1103 Id = -1;
1104 Code = wxString::FromUTF8(code);
1105 Code.Truncate(30);
1106 Next = NULL;
1107 }
1108
NetNode(sqlite3_int64 id)1109 NetNode::NetNode(sqlite3_int64 id)
1110 {
1111 //
1112 // Network Node [final] constructor
1113 //
1114 InternalIndex = -1;
1115 Id = id;
1116 Code = wxT("");
1117 X = DBL_MAX;
1118 Y = DBL_MAX;
1119 First = NULL;
1120 Last = NULL;
1121 Next = NULL;
1122 }
1123
NetNode(wxString & code)1124 NetNode::NetNode(wxString & code)
1125 {
1126 //
1127 // Network Node [final] constructor
1128 //
1129 InternalIndex = -1;
1130 Id = -1;
1131 Code = code;
1132 X = DBL_MAX;
1133 Y = DBL_MAX;
1134 First = NULL;
1135 Last = NULL;
1136 Next = NULL;
1137 }
1138
~NetNode()1139 NetNode::~NetNode()
1140 {
1141 // Network Node [final] destructor
1142 NetArcRef *pAR;
1143 NetArcRef *pARn;
1144 pAR = First;
1145 while (pAR)
1146 {
1147 pARn = pAR->GetNext();
1148 delete pAR;
1149 pAR = pARn;
1150 }
1151 }
1152
AddOutcoming(NetArc * pA)1153 void NetNode::AddOutcoming(NetArc * pA)
1154 {
1155 //
1156 // adds an outcoming Arc to a Node
1157 //
1158 NetArcRef *pAR = new NetArcRef(pA);
1159 if (!First)
1160 First = pAR;
1161 if (Last)
1162 Last->SetNext(pAR);
1163 Last = pAR;
1164 }
1165
PrepareOutcomings(int * count)1166 NetArc **NetNode::PrepareOutcomings(int *count)
1167 {
1168 //
1169 // preparing the outcoming arc array
1170 //
1171 NetArc **arc_array;
1172 int n = 0;
1173 int i;
1174 bool ok;
1175 NetArcRef *pAR;
1176 NetArc *pA0;
1177 NetArc *pA1;
1178 pAR = First;
1179 while (pAR)
1180 {
1181 // counting how many outcoming arcs are there
1182 n++;
1183 pAR = pAR->GetNext();
1184 }
1185 if (!n)
1186 {
1187 *count = 0;
1188 return NULL;
1189 }
1190 arc_array = new NetArc *[n];
1191 i = 0;
1192 pAR = First;
1193 while (pAR)
1194 {
1195 // populating the arcs array
1196 *(arc_array + i++) = pAR->GetReference();
1197 pAR = pAR->GetNext();
1198 }
1199 ok = true;
1200 while (ok == true)
1201 {
1202 // bubble sorting the arcs by Cost
1203 ok = false;
1204 for (i = 1; i < n; i++)
1205 {
1206 pA0 = *(arc_array + i - 1);
1207 pA1 = *(arc_array + i);
1208 if (pA0->GetCost() > pA1->GetCost())
1209 {
1210 // swapping the arcs
1211 *(arc_array + i - 1) = pA1;
1212 *(arc_array + i) = pA0;
1213 ok = true;
1214 }
1215 }
1216 }
1217 *count = n;
1218 return arc_array;
1219 }
1220
NetArc(sqlite3_int64 rowid,NetNode * from,NetNode * to,double cost)1221 NetArc::NetArc(sqlite3_int64 rowid, NetNode * from, NetNode * to, double cost)
1222 {
1223 //
1224 // Network Arc constructor
1225 //
1226 RowId = rowid;
1227 From = from;
1228 To = to;
1229 Cost = cost;
1230 Next = NULL;
1231 }
1232
Network()1233 Network::Network()
1234 {
1235 //
1236 // Network constructor
1237 //
1238 FirstPre = NULL;
1239 LastPre = NULL;
1240 NumPreNodes = 0;
1241 SortedPreNodes = NULL;
1242 NumPreNodes = 0;
1243 SortedPreNodes = NULL;
1244 FirstArc = NULL;
1245 LastArc = NULL;
1246 FirstNode = NULL;
1247 LastNode = NULL;
1248 NumNodes = 0;
1249 SortedNodes = NULL;
1250 Error = false;
1251 NodeCode = false;
1252 MaxCodeLength = 0;
1253 }
1254
~Network()1255 Network::~Network()
1256 {
1257 //
1258 // Network destructor
1259 //
1260 NetArc *pA;
1261 NetArc *pAn;
1262 NetNode *pN;
1263 NetNode *pNn;
1264 CleanPreNodes();
1265 pA = FirstArc;
1266 while (pA)
1267 {
1268 pAn = pA->GetNext();
1269 delete pA;
1270 pA = pAn;
1271 }
1272 pN = FirstNode;
1273 while (pN)
1274 {
1275 pNn = pN->GetNext();
1276 delete pN;
1277 pN = pNn;
1278 }
1279 if (SortedNodes)
1280 delete[]SortedNodes;
1281 }
1282
CleanPreNodes()1283 void Network::CleanPreNodes()
1284 {
1285 //
1286 // cleaning up the preliminary Nodes list
1287 //
1288 NetNodePre *pP;
1289 NetNodePre *pPn;
1290 pP = FirstPre;
1291 while (pP)
1292 {
1293 pPn = pP->GetNext();
1294 delete pP;
1295 pP = pPn;
1296 }
1297 FirstPre = NULL;
1298 LastPre = NULL;
1299 NumPreNodes = 0;
1300 if (SortedPreNodes)
1301 delete[]SortedPreNodes;
1302 SortedPreNodes = NULL;
1303 }
1304
InsertNode(sqlite3_int64 id)1305 void Network::InsertNode(sqlite3_int64 id)
1306 {
1307 //
1308 // inserts a Node into the preliminary list
1309 //
1310 NetNodePre *pP = new NetNodePre(id);
1311 if (!FirstPre)
1312 FirstPre = pP;
1313 if (LastPre)
1314 LastPre->SetNext(pP);
1315 LastPre = pP;
1316 }
1317
InsertNode(const char * code)1318 void Network::InsertNode(const char *code)
1319 {
1320 //
1321 // inserts a Node into the preliminary list
1322 //
1323 NetNodePre *pP = new NetNodePre(code);
1324 if (!FirstPre)
1325 FirstPre = pP;
1326 if (LastPre)
1327 LastPre->SetNext(pP);
1328 LastPre = pP;
1329 }
1330
AddNode(sqlite3_int64 id)1331 void Network::AddNode(sqlite3_int64 id)
1332 {
1333 //
1334 // inserts a Node into the final list
1335 //
1336 NetNode *pN = new NetNode(id);
1337 if (!FirstNode)
1338 FirstNode = pN;
1339 if (LastNode)
1340 LastNode->SetNext(pN);
1341 LastNode = pN;
1342 }
1343
AddNode(wxString & code)1344 void Network::AddNode(wxString & code)
1345 {
1346 //
1347 // inserts a Node into the final list
1348 //
1349 int len;
1350 NetNode *pN = new NetNode(code);
1351 len = pN->GetCode().Len() + 1;
1352 if (len > MaxCodeLength)
1353 MaxCodeLength = len;
1354 if (!FirstNode)
1355 FirstNode = pN;
1356 if (LastNode)
1357 LastNode->SetNext(pN);
1358 LastNode = pN;
1359 }
1360
ProcessNode(sqlite3_int64 id,double x,double y,NetNode ** pOther)1361 NetNode *Network::ProcessNode(sqlite3_int64 id, double x, double y,
1362 NetNode ** pOther)
1363 {
1364 //
1365 // inserts a new node or retrieves an already defined one
1366 //
1367 NetNode *pN = Find(id);
1368 *pOther = NULL;
1369 if (pN)
1370 {
1371 // this Node already exists into the sorted list
1372 if (pN->GetX() == DBL_MAX && pN->GetY() == DBL_MAX)
1373 {
1374 pN->SetX(x);
1375 pN->SetY(y);
1376 } else
1377 {
1378 if (pN->GetX() == x && pN->GetY() == y)
1379 ;
1380 else
1381 *pOther = pN;
1382 }
1383 return pN;
1384 }
1385 // unexpected error; undefined Node
1386 return NULL;
1387 }
1388
ProcessNode(wxString & code,double x,double y,NetNode ** pOther)1389 NetNode *Network::ProcessNode(wxString & code, double x, double y,
1390 NetNode ** pOther)
1391 {
1392 //
1393 // inserts a new node or retrieves an already defined one
1394 //
1395 NetNode *pN = Find(code);
1396 *pOther = NULL;
1397 if (pN)
1398 {
1399 // this Node already exists into the sorted list
1400 if (pN->GetX() == DBL_MAX && pN->GetY() == DBL_MAX)
1401 {
1402 pN->SetX(x);
1403 pN->SetY(y);
1404 } else
1405 {
1406 if (pN->GetX() == x && pN->GetY() == y)
1407 ;
1408 else
1409 *pOther = pN;
1410 }
1411 return pN;
1412 }
1413 // unexpected error; undefined Node
1414 return NULL;
1415 }
1416
1417 void
AddArc(sqlite3_int64 rowid,sqlite3_int64 id_from,sqlite3_int64 id_to,double node_from_x,double node_from_y,double node_to_x,double node_to_y,double cost)1418 Network::AddArc(sqlite3_int64 rowid, sqlite3_int64 id_from,
1419 sqlite3_int64 id_to, double node_from_x, double node_from_y,
1420 double node_to_x, double node_to_y, double cost)
1421 {
1422 //
1423 // inserting an arc into the memory structures
1424 //
1425 NetNode *pFrom;
1426 NetNode *pTo;
1427 NetNode *pN2;
1428 NetArc *pA;
1429 pFrom = ProcessNode(id_from, node_from_x, node_from_y, &pN2);
1430 if (pN2)
1431 Error = true;
1432 pTo = ProcessNode(id_to, node_to_x, node_to_y, &pN2);
1433 if (pN2)
1434 Error = true;
1435 if (!pFrom)
1436 Error = true;
1437 if (!pTo)
1438 Error = true;
1439 if (pFrom == pTo)
1440 Error = true;
1441 if (Error == true)
1442 return;
1443 pA = new NetArc(rowid, pFrom, pTo, cost);
1444 if (!FirstArc)
1445 FirstArc = pA;
1446 if (LastArc)
1447 LastArc->SetNext(pA);
1448 LastArc = pA;
1449 // updating Node connections
1450 pFrom->AddOutcoming(pA);
1451 }
1452
1453 void
AddArc(sqlite3_int64 rowid,const char * code_from,const char * code_to,double node_from_x,double node_from_y,double node_to_x,double node_to_y,double cost)1454 Network::AddArc(sqlite3_int64 rowid, const char *code_from,
1455 const char *code_to, double node_from_x, double node_from_y,
1456 double node_to_x, double node_to_y, double cost)
1457 {
1458 //
1459 // inserting an arc into the memory structures
1460 //
1461 NetNode *pFrom;
1462 NetNode *pTo;
1463 NetNode *pN2;
1464 NetArc *pA;
1465 wxString stCode = wxString::FromUTF8(code_from);
1466 pFrom = ProcessNode(stCode, node_from_x, node_from_y, &pN2);
1467 if (pN2)
1468 Error = true;
1469 stCode = wxString::FromUTF8(code_to);
1470 pTo = ProcessNode(stCode, node_to_x, node_to_y, &pN2);
1471 if (pN2)
1472 Error = true;
1473 if (!pFrom)
1474 Error = true;
1475 if (!pTo)
1476 Error = true;
1477 if (pFrom == pTo)
1478 Error = true;
1479 if (Error == true)
1480 return;
1481 pA = new NetArc(rowid, pFrom, pTo, cost);
1482 if (!FirstArc)
1483 FirstArc = pA;
1484 if (LastArc)
1485 LastArc->SetNext(pA);
1486 LastArc = pA;
1487 // updating Node connections
1488 pFrom->AddOutcoming(pA);
1489 }
1490
Sort()1491 void Network::Sort()
1492 {
1493 //
1494 // updating the Nodes sorted list
1495 //
1496 int i;
1497 NetNode *pN;
1498 NumNodes = 0;
1499 if (SortedNodes)
1500 {
1501 // we must free the already existent sorted list
1502 delete[]SortedNodes;
1503 }
1504 SortedNodes = NULL;
1505 pN = FirstNode;
1506 while (pN)
1507 {
1508 NumNodes++;
1509 pN = pN->GetNext();
1510 }
1511 if (!NumNodes)
1512 return;
1513 SortedNodes = new NetNode *[NumNodes];
1514 i = 0;
1515 pN = FirstNode;
1516 while (pN)
1517 {
1518 *(SortedNodes + i++) = pN;
1519 pN = pN->GetNext();
1520 }
1521 if (NodeCode == true)
1522 {
1523 // Nodes are identified by a TEXT code
1524 qsort(SortedNodes, NumNodes, sizeof(NetNode *), cmp_nodes1_code);
1525 } else
1526 {
1527 // Nodes are identified by an INTEGER id
1528 qsort(SortedNodes, NumNodes, sizeof(NetNode *), cmp_nodes1_id);
1529 }
1530 }
1531
GetSortedNode(sqlite3_int64 x)1532 NetNode *Network::GetSortedNode(sqlite3_int64 x)
1533 {
1534 //
1535 // return a sorted Node [by position]
1536 //
1537 if (x >= 0 && x < NumNodes)
1538 return *(SortedNodes + x);
1539 return NULL;
1540 }
1541
Find(sqlite3_int64 id)1542 NetNode *Network::Find(sqlite3_int64 id)
1543 {
1544 //
1545 // searching a Node into the sorted list
1546 //
1547 NetNode **ret;
1548 NetNode pN(id);
1549 if (!SortedNodes)
1550 return NULL;
1551 // Nodes are identified by an INTEGER id
1552 ret =
1553 (NetNode **) bsearch(&pN, SortedNodes, NumNodes, sizeof(NetNode *),
1554 cmp_nodes2_id);
1555 if (!ret)
1556 return NULL;
1557 return *ret;
1558 }
1559
Find(wxString & code)1560 NetNode *Network::Find(wxString & code)
1561 {
1562 //
1563 // searching a Node into the sorted list
1564 //
1565 NetNode **ret;
1566 NetNode pN(code);
1567 if (!SortedNodes)
1568 return NULL;
1569 // Nodes are identified by a TEXT code
1570 ret =
1571 (NetNode **) bsearch(&pN, SortedNodes, NumNodes, sizeof(NetNode *),
1572 cmp_nodes2_code);
1573 if (!ret)
1574 return NULL;
1575 return *ret;
1576 }
1577
InitNodes()1578 void Network::InitNodes()
1579 {
1580 //
1581 // prepares the final Nodes list
1582 //
1583 sqlite3_int64 last_id;
1584 wxString last_code;
1585 int i;
1586 NetNodePre *pP;
1587 NumPreNodes = 0;
1588 // sorting preliminary nodes
1589 if (SortedPreNodes)
1590 {
1591 // we must free the already existent sorted list
1592 delete[]SortedPreNodes;
1593 }
1594 SortedPreNodes = NULL;
1595 pP = FirstPre;
1596 while (pP)
1597 {
1598 NumPreNodes++;
1599 pP = pP->GetNext();
1600 }
1601 if (!NumPreNodes)
1602 return;
1603 SortedPreNodes = new NetNodePre *[NumPreNodes];
1604 i = 0;
1605 pP = FirstPre;
1606 while (pP)
1607 {
1608 *(SortedPreNodes + i++) = pP;
1609 pP = pP->GetNext();
1610 }
1611 if (NodeCode == true)
1612 {
1613 // Nodes are identified by a TEXT code
1614 qsort(SortedPreNodes, NumPreNodes, sizeof(NetNodePre *),
1615 cmp_prenodes_code);
1616 } else
1617 {
1618 // Nodes are identified by an INTEGER id
1619 qsort(SortedPreNodes, NumPreNodes, sizeof(NetNodePre *), cmp_prenodes_id);
1620 }
1621 // creating the final Nodes linked list
1622 last_id = -1;
1623 last_code = wxT("");
1624 for (i = 0; i < NumPreNodes; i++)
1625 {
1626 pP = *(SortedPreNodes + i);
1627 if (NodeCode == true)
1628 {
1629 // Nodes are identified by a TEXT code
1630 if (pP->GetCode().Cmp(last_code) != 0)
1631 AddNode(pP->GetCode());
1632 } else
1633 {
1634 // Nodes are identified by an INTEGER id
1635 if (pP->GetId() != last_id)
1636 AddNode(pP->GetId());
1637 }
1638 last_id = pP->GetId();
1639 last_code = pP->GetCode();
1640 }
1641 // sorting the final Nodes list
1642 Sort();
1643 // cleaning up the preliminary Nodes structs
1644 CleanPreNodes();
1645 }
1646