Skip to content

Commit 6800e44

Browse files
authored
Merge pull request #28 from minorsecond/develop
Release 1.2.2
2 parents 36aff49 + 0fb621f commit 6800e44

File tree

6 files changed

+202
-135
lines changed

6 files changed

+202
-135
lines changed

Diff for: src/job.cpp

-6
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,8 @@ std::string Job::get_location_path() const {
8686
std::string Job::find_gis_path() const {
8787
/*
8888
* Finds path to GIS directory inside documents directory
89-
* @param job_number: The job number to search for
90-
* @return: The path as a string
9189
*/
9290

93-
/*
94-
* Finds zip file in Downloads directory that contains job_number
95-
* @param job_number: Job number to search for
96-
*/
9791
UtilityFunctions ut;
9892
const std::string download_path {ut.get_home_path() + "\\Documents\\Comsof_Jobs"};
9993
for (const auto & entry : std::filesystem::directory_iterator(download_path)) { // Iterate over states

Diff for: src/shapeeditor.cpp

+102-60
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ OGRLayer* ShapeEditor::shapefile_reader(const std::string path) {
2323
poDataset = (GDALDataset *) GDALOpenEx(path.c_str(), GDAL_OF_ALL | GDAL_OF_UPDATE, NULL, NULL, NULL);
2424
OGRLayer *layer {poDataset->GetLayer(0)};
2525

26+
2627
return layer;
2728
}
2829

@@ -39,78 +40,126 @@ OGRLayer* ShapeEditor::create_demand_point_fields(OGRLayer *dp_layer) {
3940
return dp_layer;
4041
}
4142

42-
void ShapeEditor::process_demand_points(const std::string name_to_change, OGRLayer *in_layer) {
43+
void ShapeEditor::process_demand_points(OGRLayer *in_layer) {
4344
/*
4445
* Process demand points
4546
* @param name_to_change: The attribute name to change to all caps
4647
* @param in_layer: An OGRLayer that contains the attribute name to change
4748
*/
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+
4857
ErrorWindow er;
4958
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};
5161
bool all_pon_homes_zero {true};
5262
bool override_pon_homes {false};
5363

5464
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.");
5666
er.exec();
5767
}
5868

5969
// Create tmp field to store original include field and populate it with original include values
6070
// 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+
6197
if (include_field_idx != -1) {
6298
OGRFieldDefn tmp_include_field_def("tmp_inc", OFTString);
6399
in_layer->CreateField(&tmp_include_field_def);
64100

65101
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)};
67103
std::cout << "Include attr: " << include_attr << std::endl;
68104
feature->SetField("tmp_inc", include_attr.c_str());
69105
in_layer->SetFeature(feature.release());
70106
}
71107
std::cout << "Deleting include field at index " << include_field_idx << std::endl;
72108
in_layer->DeleteField(include_field_idx); // Delete original include field
73109
}
110+
}
74111

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) {
78122
OGRFieldDefn tmp_pon_homes_field_defn("tmp_ph", OFTInteger);
79123
in_layer->CreateField(&tmp_pon_homes_field_defn);
80124

81125
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)};
83127
if (ph_attr == 1) {
84-
all_pon_homes_zero = false;
128+
all_zero = false;
85129
}
86130

87131
feature->SetField("tmp_ph", ph_attr);
88132
in_layer->SetFeature(feature.release());
89133
}
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);
92136
}
93137

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+
}
102139

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) {
107149
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);
110151
}
111152
}
112153

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+
114163
OGRFieldDefn new_include_Field("INCLUDE", OFTString);
115164
OGRFieldDefn new_pon_homes_field("PON_HOMES", OFTString);
116165
OGRFieldDefn streetname_field("STREETNAME", OFTString);
@@ -121,11 +170,6 @@ void ShapeEditor::process_demand_points(const std::string name_to_change, OGRLay
121170

122171
in_layer->ResetReading(); // Restart reading layer at beginning
123172

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-
129173
// Populate new field
130174
for (OGRFeatureUniquePtr &feature : in_layer) {
131175
std::string tmp_include_value {};
@@ -150,25 +194,38 @@ void ShapeEditor::process_demand_points(const std::string name_to_change, OGRLay
150194
}
151195
feature->SetField("PON_HOMES", tmp_ph_value);
152196

197+
// Here, we convert streetnames to uppercase, or set the field to UNKNOWN if
198+
// the CGIS streetname attribute doesn't exist.
153199
std::string streetname {};
154200
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);});
156203
} else {
157204
streetname = "UNKNOWN";
158205
}
159206

160207
feature->SetField("STREETNAME", streetname.c_str());
161208
in_layer->SetFeature(feature.release());
162209
}
210+
}
163211

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.
164219
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)};
166221
if (tmp_index != -1) { // Just in case we can't find the tmp_include attribute
167222
in_layer->DeleteField(find_field_index("tmp_inc", in_layer));
168223
}
169224
}
225+
226+
// Find & delete tmp pon_homes field.
170227
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)};
172229
if (tmp_index != -1) {
173230
in_layer->DeleteField(tmp_index);
174231
}
@@ -184,21 +241,21 @@ void ShapeEditor::process_access_points(OGRLayer *in_layer) {
184241
OGRFieldDefn type_defn("TYPE", OFTString);
185242
type_defn.SetWidth(254);
186243
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)};
188245

189246
if (find_field_index("structur_1", in_layer) == -1) {
190247
er.set_error_message("Error: Could not find structur_1 attribute in access_points layer.");
191248
er.exec();
192249
return;
193250
}
194251

195-
252+
// Loop through AP features and add the TYPE attribute.
196253
for (OGRFeatureUniquePtr &feature : in_layer) {
197254
std::string size {};
198255
std::string new_type {};
199256
const std::string type {feature->GetFieldAsString("structur_1")}; // TODO: Handle different attribute names
200257
if (structur2_idx != -1) {
201-
size = feature->GetFieldAsString(structur2_idx);
258+
size = feature->GetFieldAsString(structur2_idx); // Get size value from structur2 field.
202259
}
203260

204261
if (!size.empty()) {
@@ -295,18 +352,18 @@ void ShapeEditor::process_fdt_boundaries(OGRLayer *in_layer) {
295352

296353
int ShapeEditor::find_field_index(const std::string field_name, OGRLayer *in_layer) {
297354
/*
298-
* Find the index of field
355+
* Find the index of field. Returns -1 if field could not be found.
299356
* @param in_layer: The layer to search
300357
* @param field_name: Field to search for
301358
*/
302359
int field_idx {NULL};
303360
bool field_found {false};
304361
OGRFeatureDefn *lyr_def {in_layer->GetLayerDefn()};
305-
int field_count {lyr_def->GetFieldCount()};
362+
const int field_count {lyr_def->GetFieldCount()};
306363
std::cout << "Field count: " << field_count << std::endl;
307364
for (int idx {0}; idx < field_count; idx ++) {
308365
OGRFieldDefn field_def {lyr_def->GetFieldDefn(idx)};
309-
std::string shp_name {field_def.GetNameRef()};
366+
const std::string shp_name {field_def.GetNameRef()};
310367
if (shp_name == field_name) {
311368
field_idx = idx; // This is the field index that will be changed
312369
field_found = true;
@@ -319,21 +376,7 @@ int ShapeEditor::find_field_index(const std::string field_name, OGRLayer *in_lay
319376
return field_idx;
320377
}
321378

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) {
337380
/*
338381
* Reproject the layer.
339382
* @param in_layer: The layer to reproject
@@ -346,15 +389,15 @@ void ShapeEditor::reproject(OGRLayer *in_layer, int utm_zone, std::string path)
346389
poDriver = GetGDALDriverManager()->GetDriverByName(pszDriverName);
347390

348391
// 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.
351393

352394
// Proj library path
353395
const std::string ppath {std::filesystem::current_path().string()};
354396
const char * proj_path[] {ppath.c_str(), nullptr};
355397
std::cout << "Searching for proj.db in " << ppath << std::endl;
356398
OSRSetPROJSearchPaths(proj_path);
357399

400+
// Convert UTM zone string into CRS integer for GDAL
358401
int crs {};
359402
for (auto it {utm_zones.begin()}; it != utm_zones.end(); it++) {
360403
if (it->first == utm_zone) {
@@ -364,8 +407,7 @@ void ShapeEditor::reproject(OGRLayer *in_layer, int utm_zone, std::string path)
364407

365408
// Get projection data
366409
OGRSpatialReference *srFrom {in_layer->GetSpatialRef()};
367-
//OGRSpatialReference *srTo = new OGRSpatialReference;
368-
auto srTo = std::make_unique<OGRSpatialReference>();
410+
auto srTo {std::make_unique<OGRSpatialReference>()};
369411

370412
std::cout << "Converting to EPSG: " << crs << std::endl;
371413
srTo->importFromEPSG(crs);
@@ -392,7 +434,7 @@ void ShapeEditor::reproject(OGRLayer *in_layer, int utm_zone, std::string path)
392434
poLayer->SetFeature(feature.release());
393435
}
394436
// Cleanup
437+
delete coordTrans;
395438
poLayer->SyncToDisk();
396439
GDALClose(poDS);
397-
//delete srTo;
398440
}

Diff for: src/shapeeditor.h

+11-5
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,22 @@ class ShapeEditor
2222
public:
2323
GDALDriverH gdaldriver {GDALGetDriverByName("ESRI Shapefile")};
2424
static OGRLayer* shapefile_reader(const std::string path);
25-
static OGRLayer* create_demand_point_fields(OGRLayer *dp_layer);
26-
static void process_demand_points(const std::string name_to_change, OGRLayer *in_layer);
25+
static void process_demand_points(OGRLayer *in_layer);
2726
static void process_access_points(OGRLayer *in_layer);
2827
static void process_poles(OGRLayer *in_layer);
2928
static void process_aerial_connections(OGRLayer *in_layer);
3029
static void process_fdt_boundaries(OGRLayer *in_layer);
31-
static void reproject(OGRLayer *in_layer, int utm_zone, std::string path);
32-
static int find_field_index (const std::string field_name, OGRLayer *in_layer);
33-
static std::string uppercase_string(std::string input_string);
30+
static void reproject(OGRLayer *in_layer, const int utm_zone, const std::string &path);
3431
ShapeEditor();
32+
33+
private:
34+
static OGRLayer* create_demand_point_fields(OGRLayer *dp_layer);
35+
static void create_tmp_include_field(const int include_field_idx, OGRLayer *in_layer);
36+
static void create_tmp_pon_homes_field(OGRLayer *in_layer, int &pon_homes_idx, bool &all_zero);
37+
static int find_street_name_field(OGRLayer *in_layer);
38+
static void 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);
39+
static void delete_tmp_dp_fields(OGRLayer *in_layer, int include_field_idx, int pon_homes_field_idx);
40+
static int find_field_index (const std::string field_name, OGRLayer *in_layer);
3541
};
3642

3743
#endif // SHAPEEDITOR_H

0 commit comments

Comments
 (0)