Skip to content

Commit

Permalink
avoid duplicate class features
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielJDufour committed Apr 11, 2022
1 parent 72beee7 commit 62c6bf6
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 12 deletions.
48 changes: 42 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,20 @@ function getArrayKey({ feature, index, geometry, props }) {
}
}

function unarray(arr) {
function unarray (arr) {
return arr.length === 1 ? arr[0] : arr;
}

// https://stackoverflow.com/questions/6122571/simple-non-secure-hash-function-for-javascript
function hash (string) {
let hash = 0;
for (i = 0; i < string.length; i++) {
chr = string.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
}
return hash;
}

// assumptions
// - zones is a GeoJSON with polygons
// - classes are either all polygons/multi-polygons or all points (not mix of polygons and points)
Expand All @@ -68,7 +78,10 @@ function calculate({
class_properties_delimiter = ",",
preserve_features = true,
remove_features_with_no_overlap = false,
debug_level = 0
on_before_each_zone_feature,
on_after_each_zone_feature,
feature_filter,
debug_level = 0,
}) {
if (!classes) throw new Error("[zonal] classes are missing or empty");
if (!zones) throw new Error("[zonal] zones are missing or empty");
Expand Down Expand Up @@ -98,7 +111,6 @@ function calculate({
if ([undefined, null].includes(class_properties)) {
console.warn("[zonal] you didn't pass in class_properties, so defaulting to the class feature index number");
}


// stats keyed by the unique zone+class combo id
// e.g. { '["AK","Hot"]': 10, '["AK","Cold"]': 342 }
Expand All @@ -113,6 +125,7 @@ function calculate({

// group class geometries into dictionary objects
featureEach(classes, (class_feature, class_feature_index) => {

geomEach(class_feature, (class_geometry, class_geometry_index) => {
const class_array = getArrayKey({
feature: class_feature,
Expand All @@ -133,14 +146,29 @@ function calculate({
return;
}

class_to_geometries[class_id] ??= [];
class_to_geometries[class_id].push(class_geometry);
const class_geometry_hash = hash(JSON.stringify(class_geometry.coordinates));

class_to_geometries[class_id] ??= {};
class_to_geometries[class_id][class_geometry_hash] = class_geometry;
});
});

// zones must be one or more features with polygon geometries
// like administrative districts
featureEach(zones, (zone_feature, zone_feature_index) => {

if (feature_filter && feature_filter({ feature: zone_feature, index: zone_feature_index }) === false) {
return;
}

if (typeof on_before_each_zone_feature === "function") {
on_before_each_zone_feature({
feature: zone_feature,
feature_index: zone_feature_index,
stats,
zone_to_area
});
}
geomEach(zone_feature, (zone_geometry, geometry_index) => {
// sometimes the same zone could be split up amonst multiple features
// for example, you could have a country with multiple islands
Expand Down Expand Up @@ -174,7 +202,7 @@ function calculate({
const combo_id = JSON.stringify([zone_id, class_id]);

let remaining_zone_geometry_for_specific_class = zone_geometry;
class_geometries.forEach(class_geometry => {
Object.values(class_geometries).forEach(class_geometry => {
if (class_geometry_type === "Point") {
stats[combo_id] ??= { count: 0 };

Expand Down Expand Up @@ -226,6 +254,14 @@ function calculate({
: 0;
}
});
if (typeof on_after_each_zone_feature === "function") {
on_after_each_zone_feature({
feature: zone_feature,
feature_index: zone_feature_index,
stats,
zone_to_area
});
}
});

// calculate percentages
Expand Down
47 changes: 44 additions & 3 deletions zonal.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ function getArrayKey(_ref) {

function unarray(arr) {
return arr.length === 1 ? arr[0] : arr;
} // https://stackoverflow.com/questions/6122571/simple-non-secure-hash-function-for-javascript


function hash(string) {
var hash = 0;

for (i = 0; i < string.length; i++) {
chr = string.charCodeAt(i);
hash = (hash << 5) - hash + chr;
}

return hash;
} // assumptions
// - zones is a GeoJSON with polygons
// - classes are either all polygons/multi-polygons or all points (not mix of polygons and points)
Expand All @@ -109,6 +121,9 @@ function calculate(_ref2) {
preserve_features = _ref2$preserve_featur === void 0 ? true : _ref2$preserve_featur,
_ref2$remove_features = _ref2.remove_features_with_no_overlap,
remove_features_with_no_overlap = _ref2$remove_features === void 0 ? false : _ref2$remove_features,
on_before_each_zone_feature = _ref2.on_before_each_zone_feature,
on_after_each_zone_feature = _ref2.on_after_each_zone_feature,
feature_filter = _ref2.feature_filter,
_ref2$debug_level = _ref2.debug_level,
debug_level = _ref2$debug_level === void 0 ? 0 : _ref2$debug_level;
if (!classes) throw new Error("[zonal] classes are missing or empty");
Expand Down Expand Up @@ -171,13 +186,30 @@ function calculate(_ref2) {
return;
}

(_class_to_geometries$ = class_to_geometries[class_id]) !== null && _class_to_geometries$ !== void 0 ? _class_to_geometries$ : class_to_geometries[class_id] = [];
class_to_geometries[class_id].push(class_geometry);
var class_geometry_hash = hash(JSON.stringify(class_geometry.coordinates));
(_class_to_geometries$ = class_to_geometries[class_id]) !== null && _class_to_geometries$ !== void 0 ? _class_to_geometries$ : class_to_geometries[class_id] = {};
class_to_geometries[class_id][class_geometry_hash] = class_geometry;
});
}); // zones must be one or more features with polygon geometries
// like administrative districts

featureEach(zones, function (zone_feature, zone_feature_index) {
if (feature_filter && feature_filter({
feature: zone_feature,
index: zone_feature_index
}) === false) {
return;
}

if (typeof on_before_each_zone_feature === "function") {
on_before_each_zone_feature({
feature: zone_feature,
feature_index: zone_feature_index,
stats: stats,
zone_to_area: zone_to_area
});
}

geomEach(zone_feature, function (zone_geometry, geometry_index) {
var _zone_feature$propert, _zone_to_area$zone_id;

Expand Down Expand Up @@ -211,7 +243,7 @@ function calculate(_ref2) {
// there will be a row in the table for each zone + class combo
var combo_id = JSON.stringify([zone_id, class_id]);
var remaining_zone_geometry_for_specific_class = zone_geometry;
class_geometries.forEach(function (class_geometry) {
Object.values(class_geometries).forEach(function (class_geometry) {
if (class_geometry_type === "Point") {
var _stats$combo_id;

Expand Down Expand Up @@ -263,6 +295,15 @@ function calculate(_ref2) {
stats[zone_without_class_id].area += remaining_zone_geometry_for_all_classes ? Math.round(calculateArea(remaining_zone_geometry_for_all_classes)) : 0;
}
});

if (typeof on_after_each_zone_feature === "function") {
on_after_each_zone_feature({
feature: zone_feature,
feature_index: zone_feature_index,
stats: stats,
zone_to_area: zone_to_area
});
}
}); // calculate percentages

entries(stats).forEach(function (_ref5) {
Expand Down
47 changes: 44 additions & 3 deletions zonal.min.js
Original file line number Diff line number Diff line change
Expand Up @@ -5494,6 +5494,18 @@ function getArrayKey(_ref) {

function unarray(arr) {
return arr.length === 1 ? arr[0] : arr;
} // https://stackoverflow.com/questions/6122571/simple-non-secure-hash-function-for-javascript


function hash(string) {
var hash = 0;

for (i = 0; i < string.length; i++) {
chr = string.charCodeAt(i);
hash = (hash << 5) - hash + chr;
}

return hash;
} // assumptions
// - zones is a GeoJSON with polygons
// - classes are either all polygons/multi-polygons or all points (not mix of polygons and points)
Expand All @@ -5517,6 +5529,9 @@ function calculate(_ref2) {
preserve_features = _ref2$preserve_featur === void 0 ? true : _ref2$preserve_featur,
_ref2$remove_features = _ref2.remove_features_with_no_overlap,
remove_features_with_no_overlap = _ref2$remove_features === void 0 ? false : _ref2$remove_features,
on_before_each_zone_feature = _ref2.on_before_each_zone_feature,
on_after_each_zone_feature = _ref2.on_after_each_zone_feature,
feature_filter = _ref2.feature_filter,
_ref2$debug_level = _ref2.debug_level,
debug_level = _ref2$debug_level === void 0 ? 0 : _ref2$debug_level;
if (!classes) throw new Error("[zonal] classes are missing or empty");
Expand Down Expand Up @@ -5579,13 +5594,30 @@ function calculate(_ref2) {
return;
}

(_class_to_geometries$ = class_to_geometries[class_id]) !== null && _class_to_geometries$ !== void 0 ? _class_to_geometries$ : class_to_geometries[class_id] = [];
class_to_geometries[class_id].push(class_geometry);
var class_geometry_hash = hash(JSON.stringify(class_geometry.coordinates));
(_class_to_geometries$ = class_to_geometries[class_id]) !== null && _class_to_geometries$ !== void 0 ? _class_to_geometries$ : class_to_geometries[class_id] = {};
class_to_geometries[class_id][class_geometry_hash] = class_geometry;
});
}); // zones must be one or more features with polygon geometries
// like administrative districts

featureEach(zones, function (zone_feature, zone_feature_index) {
if (feature_filter && feature_filter({
feature: zone_feature,
index: zone_feature_index
}) === false) {
return;
}

if (typeof on_before_each_zone_feature === "function") {
on_before_each_zone_feature({
feature: zone_feature,
feature_index: zone_feature_index,
stats: stats,
zone_to_area: zone_to_area
});
}

geomEach(zone_feature, function (zone_geometry, geometry_index) {
var _zone_feature$propert, _zone_to_area$zone_id;

Expand Down Expand Up @@ -5619,7 +5651,7 @@ function calculate(_ref2) {
// there will be a row in the table for each zone + class combo
var combo_id = JSON.stringify([zone_id, class_id]);
var remaining_zone_geometry_for_specific_class = zone_geometry;
class_geometries.forEach(function (class_geometry) {
Object.values(class_geometries).forEach(function (class_geometry) {
if (class_geometry_type === "Point") {
var _stats$combo_id;

Expand Down Expand Up @@ -5671,6 +5703,15 @@ function calculate(_ref2) {
stats[zone_without_class_id].area += remaining_zone_geometry_for_all_classes ? Math.round(calculateArea(remaining_zone_geometry_for_all_classes)) : 0;
}
});

if (typeof on_after_each_zone_feature === "function") {
on_after_each_zone_feature({
feature: zone_feature,
feature_index: zone_feature_index,
stats: stats,
zone_to_area: zone_to_area
});
}
}); // calculate percentages

entries(stats).forEach(function (_ref5) {
Expand Down

0 comments on commit 62c6bf6

Please sign in to comment.