@@ -23,6 +23,7 @@ OGRLayer* ShapeEditor::shapefile_reader(const std::string path) {
23
23
poDataset = (GDALDataset *) GDALOpenEx (path.c_str (), GDAL_OF_ALL | GDAL_OF_UPDATE, NULL , NULL , NULL );
24
24
OGRLayer *layer {poDataset->GetLayer (0 )};
25
25
26
+
26
27
return layer;
27
28
}
28
29
@@ -39,78 +40,126 @@ OGRLayer* ShapeEditor::create_demand_point_fields(OGRLayer *dp_layer) {
39
40
return dp_layer;
40
41
}
41
42
42
- void ShapeEditor::process_demand_points (const std::string name_to_change, OGRLayer *in_layer) {
43
+ void ShapeEditor::process_demand_points (OGRLayer *in_layer) {
43
44
/*
44
45
* Process demand points
45
46
* @param name_to_change: The attribute name to change to all caps
46
47
* @param in_layer: An OGRLayer that contains the attribute name to change
47
48
*/
49
+
50
+ /*
51
+ * All field searches assume that CGIS provides attribute names in lowercase, which has
52
+ * been the case so far. If they begin also providing them in uppercase, we'll need to
53
+ * add nested if/else statements to try to determine if the field exists in whichever
54
+ * case.
55
+ */
56
+
48
57
ErrorWindow er;
49
58
const std::string input_streetname_field_name {" street_nam" };
50
- int include_field_idx {find_field_index (" include" , in_layer)}; // Find include field. Returns -1 if "include" isn't present
59
+ const int include_field_idx {find_field_index (" include" , in_layer)}; // Find include field. Returns -1 if "include" isn't present
60
+ int pon_homes_field_idx {-1 };
51
61
bool all_pon_homes_zero {true };
52
62
bool override_pon_homes {false };
53
63
54
64
if (include_field_idx == -1 ) {
55
- er.set_error_message (" Error: could not find " + name_to_change + " in demand points layer. Defaulting to True." );
65
+ er.set_error_message (" Error: could not find include field in demand points layer. Defaulting to True." );
56
66
er.exec ();
57
67
}
58
68
59
69
// Create tmp field to store original include field and populate it with original include values
60
70
// This is done to switch from the lowercase "include" field to uppercase "INCLUDE"
71
+ create_tmp_include_field (include_field_idx, in_layer);
72
+
73
+ // Create tmp field to store original pon_homes values, just as we did for the inlude field
74
+ create_tmp_pon_homes_field (in_layer, pon_homes_field_idx, all_pon_homes_zero);
75
+
76
+ // Prompt user if they want to set PON_HOMES to 1 if CGIS has set them all to 0.
77
+ if (all_pon_homes_zero && pon_homes_field_idx != -1 ) {
78
+ OverridePonHomes override = OverridePonHomes ();
79
+ override .setModal (true );
80
+ if (override .exec () == QDialog::Accepted) {
81
+ override_pon_homes = true ;
82
+ }
83
+ }
84
+
85
+ int streetname_idx {find_street_name_field (in_layer)};
86
+ add_dp_fields (in_layer, include_field_idx, override_pon_homes, pon_homes_field_idx, streetname_idx);
87
+
88
+ delete_tmp_dp_fields (in_layer, include_field_idx, pon_homes_field_idx);
89
+ }
90
+
91
+ void ShapeEditor::create_tmp_include_field (const int include_field_idx, OGRLayer *in_layer) {
92
+ /*
93
+ * Create tmp field to store original include field and populate it with original include values
94
+ * This is done to switch from the lowercase "include" field to uppercase "INCLUDE"
95
+ */
96
+
61
97
if (include_field_idx != -1 ) {
62
98
OGRFieldDefn tmp_include_field_def (" tmp_inc" , OFTString);
63
99
in_layer->CreateField (&tmp_include_field_def);
64
100
65
101
for (OGRFeatureUniquePtr &feature : in_layer) {
66
- std::string include_attr {feature->GetFieldAsString (include_field_idx)};
102
+ const std::string include_attr {feature->GetFieldAsString (include_field_idx)};
67
103
std::cout << " Include attr: " << include_attr << std::endl;
68
104
feature->SetField (" tmp_inc" , include_attr.c_str ());
69
105
in_layer->SetFeature (feature.release ());
70
106
}
71
107
std::cout << " Deleting include field at index " << include_field_idx << std::endl;
72
108
in_layer->DeleteField (include_field_idx); // Delete original include field
73
109
}
110
+ }
74
111
75
- // Create tmp field to store original pon_homes values, just as we did for the inlude field
76
- int pon_homes_field_idx {find_field_index (" pon_homes" , in_layer)}; // Find pon_homes field
77
- if (pon_homes_field_idx != -1 ) {
112
+ void ShapeEditor::create_tmp_pon_homes_field (OGRLayer *in_layer, int &pon_homes_idx, bool &all_zero) {
113
+ /* Create tmp pon_homes field and set pon_homes idx and all_zero
114
+ * @param in_layer: The layer to modify (create tmp pon homes field in)
115
+ * @param pon_homes_idx: The column number of the pon_homes attribute
116
+ * @param all_zero: a bool denoting whether all pon_home values are 0
117
+ */
118
+
119
+ pon_homes_idx = find_field_index (" pon_homes" , in_layer); // Find pon_homes field
120
+
121
+ if (pon_homes_idx != -1 ) {
78
122
OGRFieldDefn tmp_pon_homes_field_defn (" tmp_ph" , OFTInteger);
79
123
in_layer->CreateField (&tmp_pon_homes_field_defn);
80
124
81
125
for (OGRFeatureUniquePtr &feature : in_layer) {
82
- int ph_attr {feature->GetFieldAsInteger (pon_homes_field_idx )};
126
+ const int ph_attr {feature->GetFieldAsInteger (pon_homes_idx )};
83
127
if (ph_attr == 1 ) {
84
- all_pon_homes_zero = false ;
128
+ all_zero = false ;
85
129
}
86
130
87
131
feature->SetField (" tmp_ph" , ph_attr);
88
132
in_layer->SetFeature (feature.release ());
89
133
}
90
- std::cout << " Deleting pon_homes field at index " << pon_homes_field_idx << std::endl;
91
- in_layer->DeleteField (pon_homes_field_idx );
134
+ std::cout << " Deleting pon_homes field at index " << pon_homes_idx << std::endl;
135
+ in_layer->DeleteField (pon_homes_idx );
92
136
}
93
137
94
- // Prompt user if they want to set PON_HOMES to 1 if CGIS has set them all to 0.
95
- if (all_pon_homes_zero && pon_homes_field_idx != -1 ) {
96
- OverridePonHomes override = OverridePonHomes ();
97
- override .setModal (true );
98
- if (override .exec () == QDialog::Accepted) {
99
- override_pon_homes = true ;
100
- }
101
- }
138
+ }
102
139
103
- // Find street name field
104
- int streetname_idx {find_field_index (" street_nam" , in_layer)};
105
- if (streetname_idx == -1 ) {
106
- streetname_idx = find_field_index (" street" , in_layer);
140
+ int ShapeEditor::find_street_name_field (OGRLayer *in_layer) {
141
+ /*
142
+ * Find the streetname field
143
+ * @param in_layer: The layer to search
144
+ */
145
+
146
+ std::array<std::string, 2 > streetname_attr_names {" street_nam" , " street" };
147
+ int streetname_idx {-1 };
148
+ for (std::string attr_name : streetname_attr_names) {
107
149
if (streetname_idx == -1 ) {
108
- er.set_error_message (" Warning: could not find streetname field" );
109
- er.exec ();
150
+ streetname_idx = find_field_index (attr_name, in_layer);
110
151
}
111
152
}
112
153
113
- // Add the new fields
154
+ return streetname_idx;
155
+ }
156
+
157
+ void ShapeEditor::add_dp_fields (OGRLayer *in_layer, const int include_field_idx, const bool override_pon_homes, const int pon_homes_field_idx, const int streetname_idx) {
158
+ /*
159
+ * Add new fields to demand points layer
160
+ * @param in_layer: The layer to add fields to
161
+ */
162
+
114
163
OGRFieldDefn new_include_Field (" INCLUDE" , OFTString);
115
164
OGRFieldDefn new_pon_homes_field (" PON_HOMES" , OFTString);
116
165
OGRFieldDefn streetname_field (" STREETNAME" , OFTString);
@@ -121,11 +170,6 @@ void ShapeEditor::process_demand_points(const std::string name_to_change, OGRLay
121
170
122
171
in_layer->ResetReading (); // Restart reading layer at beginning
123
172
124
- // Ask user if they want to override the pon_homes attribute if CGIS has them all set to 0
125
- if (all_pon_homes_zero) {
126
- // Raise ask pon homes ui
127
- }
128
-
129
173
// Populate new field
130
174
for (OGRFeatureUniquePtr &feature : in_layer) {
131
175
std::string tmp_include_value {};
@@ -150,25 +194,38 @@ void ShapeEditor::process_demand_points(const std::string name_to_change, OGRLay
150
194
}
151
195
feature->SetField (" PON_HOMES" , tmp_ph_value);
152
196
197
+ // Here, we convert streetnames to uppercase, or set the field to UNKNOWN if
198
+ // the CGIS streetname attribute doesn't exist.
153
199
std::string streetname {};
154
200
if (streetname_idx != -1 ) {
155
- streetname = uppercase_string (feature->GetFieldAsString (streetname_idx));
201
+ streetname = feature->GetFieldAsString (streetname_idx);
202
+ std::transform (streetname.begin (), streetname.end (), streetname.begin (), [] (unsigned char c) {return std::toupper (c);});
156
203
} else {
157
204
streetname = " UNKNOWN" ;
158
205
}
159
206
160
207
feature->SetField (" STREETNAME" , streetname.c_str ());
161
208
in_layer->SetFeature (feature.release ());
162
209
}
210
+ }
163
211
212
+ void ShapeEditor::delete_tmp_dp_fields (OGRLayer *in_layer, int include_field_idx, int pon_homes_field_idx) {
213
+ /*
214
+ * Delete temporary demand point fields.
215
+ * @param in_layer: The layer to delete from
216
+ */
217
+
218
+ // Find & delete tmp include field.
164
219
if (include_field_idx != -1 ) {
165
- int tmp_index {find_field_index (" tmp_inc" , in_layer)};
220
+ const int tmp_index {find_field_index (" tmp_inc" , in_layer)};
166
221
if (tmp_index != -1 ) { // Just in case we can't find the tmp_include attribute
167
222
in_layer->DeleteField (find_field_index (" tmp_inc" , in_layer));
168
223
}
169
224
}
225
+
226
+ // Find & delete tmp pon_homes field.
170
227
if (pon_homes_field_idx != -1 ) {
171
- int tmp_index {find_field_index (" tmp_ph" , in_layer)};
228
+ const int tmp_index {find_field_index (" tmp_ph" , in_layer)};
172
229
if (tmp_index != -1 ) {
173
230
in_layer->DeleteField (tmp_index);
174
231
}
@@ -184,21 +241,21 @@ void ShapeEditor::process_access_points(OGRLayer *in_layer) {
184
241
OGRFieldDefn type_defn (" TYPE" , OFTString);
185
242
type_defn.SetWidth (254 );
186
243
in_layer->CreateField (&type_defn);
187
- int structur2_idx {find_field_index (" structur_2" , in_layer)};
244
+ const int structur2_idx {find_field_index (" structur_2" , in_layer)};
188
245
189
246
if (find_field_index (" structur_1" , in_layer) == -1 ) {
190
247
er.set_error_message (" Error: Could not find structur_1 attribute in access_points layer." );
191
248
er.exec ();
192
249
return ;
193
250
}
194
251
195
-
252
+ // Loop through AP features and add the TYPE attribute.
196
253
for (OGRFeatureUniquePtr &feature : in_layer) {
197
254
std::string size {};
198
255
std::string new_type {};
199
256
const std::string type {feature->GetFieldAsString (" structur_1" )}; // TODO: Handle different attribute names
200
257
if (structur2_idx != -1 ) {
201
- size = feature->GetFieldAsString (structur2_idx);
258
+ size = feature->GetFieldAsString (structur2_idx); // Get size value from structur2 field.
202
259
}
203
260
204
261
if (!size.empty ()) {
@@ -295,18 +352,18 @@ void ShapeEditor::process_fdt_boundaries(OGRLayer *in_layer) {
295
352
296
353
int ShapeEditor::find_field_index (const std::string field_name, OGRLayer *in_layer) {
297
354
/*
298
- * Find the index of field
355
+ * Find the index of field. Returns -1 if field could not be found.
299
356
* @param in_layer: The layer to search
300
357
* @param field_name: Field to search for
301
358
*/
302
359
int field_idx {NULL };
303
360
bool field_found {false };
304
361
OGRFeatureDefn *lyr_def {in_layer->GetLayerDefn ()};
305
- int field_count {lyr_def->GetFieldCount ()};
362
+ const int field_count {lyr_def->GetFieldCount ()};
306
363
std::cout << " Field count: " << field_count << std::endl;
307
364
for (int idx {0 }; idx < field_count; idx ++) {
308
365
OGRFieldDefn field_def {lyr_def->GetFieldDefn (idx)};
309
- std::string shp_name {field_def.GetNameRef ()};
366
+ const std::string shp_name {field_def.GetNameRef ()};
310
367
if (shp_name == field_name) {
311
368
field_idx = idx; // This is the field index that will be changed
312
369
field_found = true ;
@@ -319,21 +376,7 @@ int ShapeEditor::find_field_index(const std::string field_name, OGRLayer *in_lay
319
376
return field_idx;
320
377
}
321
378
322
- std::string ShapeEditor::uppercase_string (std::string input_string) {
323
- /*
324
- * Convert string to an uppercase string
325
- * @param input_string: Input string
326
- * @return string: Input string as all uppercase
327
- */
328
-
329
- std::string uppercase_string {input_string};
330
- for (int i {0 }; i < uppercase_string.size (); i++) {
331
- uppercase_string[i] = std::toupper (uppercase_string[i]);
332
- }
333
- return uppercase_string;
334
- }
335
-
336
- void ShapeEditor::reproject (OGRLayer *in_layer, int utm_zone, std::string path) {
379
+ void ShapeEditor::reproject (OGRLayer *in_layer, const int utm_zone, const std::string &path) {
337
380
/*
338
381
* Reproject the layer.
339
382
* @param in_layer: The layer to reproject
@@ -346,15 +389,15 @@ void ShapeEditor::reproject(OGRLayer *in_layer, int utm_zone, std::string path)
346
389
poDriver = GetGDALDriverManager ()->GetDriverByName (pszDriverName);
347
390
348
391
// Convert UTM zone integer into the EPSG code. This map will be updated
349
- // as new areas become active. the N specifier, e.g. 10N, is taken for
350
- // granted.
392
+ // as new areas become active. the N specifier, e.g. 10N, is assumed.
351
393
352
394
// Proj library path
353
395
const std::string ppath {std::filesystem::current_path ().string ()};
354
396
const char * proj_path[] {ppath.c_str (), nullptr };
355
397
std::cout << " Searching for proj.db in " << ppath << std::endl;
356
398
OSRSetPROJSearchPaths (proj_path);
357
399
400
+ // Convert UTM zone string into CRS integer for GDAL
358
401
int crs {};
359
402
for (auto it {utm_zones.begin ()}; it != utm_zones.end (); it++) {
360
403
if (it->first == utm_zone) {
@@ -364,8 +407,7 @@ void ShapeEditor::reproject(OGRLayer *in_layer, int utm_zone, std::string path)
364
407
365
408
// Get projection data
366
409
OGRSpatialReference *srFrom {in_layer->GetSpatialRef ()};
367
- // OGRSpatialReference *srTo = new OGRSpatialReference;
368
- auto srTo = std::make_unique<OGRSpatialReference>();
410
+ auto srTo {std::make_unique<OGRSpatialReference>()};
369
411
370
412
std::cout << " Converting to EPSG: " << crs << std::endl;
371
413
srTo->importFromEPSG (crs);
@@ -392,7 +434,7 @@ void ShapeEditor::reproject(OGRLayer *in_layer, int utm_zone, std::string path)
392
434
poLayer->SetFeature (feature.release ());
393
435
}
394
436
// Cleanup
437
+ delete coordTrans;
395
438
poLayer->SyncToDisk ();
396
439
GDALClose (poDS);
397
- // delete srTo;
398
440
}
0 commit comments