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