A point-in-zone join must handle invalid polygons, shared borders, overlaps and the intended ownership rule.
Spatial joins: polygons, boundaries and duplicate matches
Validate geometry first
A zone polygon may self-intersect, omit a ring or use a different coordinate reference from the points. Check geometry validity and transform both sides into a compatible reference before containment tests. A bounding box is only a quick candidate filter; it can include points outside an irregular polygon. The coordinate contract should determine how transformations are recorded.
Choose a border policy
A pickup point on the shared edge of two zones can match both under an intersects predicate, neither under strict within, or one under a declared tie-break. Specify the rule based on the business decision. Do not let database row order decide ownership. Keep an unresolved state if uncertainty or overlapping zones prevents a defensible unique assignment.
Control duplicate rows
One point joined to three overlapping polygons creates three output rows and can inflate delivery totals. Preserve point ID and count matches before aggregation. For coverage reporting, decide whether overlap means multiple eligible zones or a data-quality defect. Reconciliation should compare unique input event IDs with unique output event IDs.
Use a fixture
Create two square zones sharing one edge, one point in the first zone, one on the common edge and one outside both. Verify the declared border rule for each. Add a self-intersecting polygon and quarantine it. A report should show unmatched and multi-match counts, not silently assign every point to the first returned polygon.
Implementation
def bounding_box_candidates(points, bounds_by_zone):
matches = []
for point in points:
for zone_id, (west, south, east, north) in bounds_by_zone.items():
if west <= point["longitude"] <= east and south <= point["latitude"] <= north:
matches.append((point["point_id"], zone_id))
return matchesPerformance and operating cost
The fixture broad-phase scan costs O(P times Z) time for P points and Z zones, with O(M) output for M candidate pairs. An index can reduce candidate tests; exact polygon predicates must still follow the broad-phase filter.
Common Mistakes
- Do not use a bounding-box candidate as a confirmed polygon match.
- Do not let overlapping polygons multiply event counts silently.
- Do not assign a border point by arbitrary database order.
