--- title: Geometry & Spatial Filters | Plaza Docs description: Construct geometries and filter PlazaQL results by location using spatial predicates. --- ## Geometry constructors PlazaQL has four geometry constructors. All use `lat, lng` order (how humans say coordinates). ### Points ``` // Keyword args (self-documenting) $home = point(lat: 38.9, lng: -77.0); // Positional args (concise) $work = point(38.85, -77.05); ``` ### Line strings ``` $path = linestring(point(38.9, -77.0), point(38.88, -77.02), point(38.85, -77.05)); ``` ### Polygons Polygons auto-close — you don’t need to repeat the first point: ``` $zone = polygon( point(38.8, -77.1), point(38.8, -76.9), point(39.0, -76.9), point(39.0, -77.1) ); ``` ### Bounding boxes A shortcut for a rectangular polygon: ``` // Keyword: south, west, north, east $area = bbox(south: 40.7, west: -74.0, north: 40.8, east: -73.9); // Positional: s, w, n, e $area = bbox(40.7, -74.0, 40.8, -73.9); ``` For named places, prefer `boundary()` over hardcoded coordinates: ``` $manhattan = boundary(name: "Manhattan"); ``` ### Composing with variables Geometry constructors are composable — use variables to build complex shapes from simple ones: ``` $home = point(38.9, -77.0); $work = point(38.85, -77.05); $commute = linestring($home, $work); search(amenity: "gas_station") .around(distance: 200, geometry: $commute); ``` ## Spatial filters Spatial filters narrow results by location. They come after `search()` (or set operations) in the chain. ### `.around()` — distance from geometry ``` // Within 500m of a point search(amenity: "cafe") .around(distance: 500, geometry: point(48.85, 2.35)); // Within 200m of a route $r = route(origin: point(40.748, -73.993), destination: point(40.755, -73.970), mode: "foot"); search(amenity: "bench") .around(distance: 200, geometry: $r); ``` ### `.within()` — inside a polygon or area ``` $paris = boundary(name: "Paris"); search(tourism: "museum").within(geometry: $paris); // Inline polygon search(building: *) .within(geometry: polygon( point(40.7, -74.0), point(40.7, -73.9), point(40.8, -73.9), point(40.8, -74.0) )); ``` ### `.intersects()` — overlaps with geometry ``` $river = search(way, waterway: "river", name: "Seine"); search(way, bridge: *).intersects(geometry: $river); ``` ### `.bbox()` — bounding box shortcut ``` search(amenity: "pub") .bbox(south: 51.50, west: -0.13, north: 51.53, east: -0.07); ``` ### `.h3()` — H3 cell filter ``` search(amenity: "cafe") .h3(cell: "8a2a1072b59ffff"); ``` ### `.contains()` — feature fully contains geometry ``` $park = point(40.7829, -73.9654); search(way, leisure: "park").contains(geometry: $park); ``` ### `.crosses()` and `.touches()` ``` $highway = search(way, highway: "motorway", ref: "I-95"); search(way, highway: "primary").crosses(geometry: $highway); ``` ### Negated spatial filters Every spatial filter has a negated form: ``` $flood_zone = polygon(...); search(building: "residential") .not_within(geometry: $flood_zone); search(way, landuse: *) .not_intersects(geometry: $protected_area); search(way, building: *) .not_contains(geometry: $exclusion_point); ``` ## Transforms Transforms modify the geometry or properties of results. ### `.buffer()` — expand geometries Add a buffer zone around each feature: ``` // 50-meter buffer around each school search(amenity: "school") .within(geometry: $city) .buffer(50); ``` Turns points into circles, expands polygons outward. Useful for proximity analysis. ### `.simplify()` — reduce geometry detail Simplify complex geometries using Douglas-Peucker tolerance: ``` // Simplify coastlines for overview display search(way, natural: "coastline") .bbox(40.0, -75.0, 42.0, -72.0) .simplify(100); ``` The parameter is tolerance in meters — higher values produce simpler geometries. ### `.centroid()` — replace with center point Replace each feature’s geometry with its centroid: ``` // Get center points of all parks search(way, leisure: "park") .within(geometry: $city) .centroid(); ``` Converts any `GeoSet` to a `PointSet`.