Chapter 3: Geographic Utility Functions#
Welcome back! In Chapter 1: Data Types & Models, we learned about the blueprints (data types) for our project's information, like geographic shapes and user inputs. In Chapter 2: Building Data API Client, we discovered how to fetch building data, including those geographic shapes (GeoJSON coordinates), from an external service.
Now that we have the data β the digital outline of a building or land plot β what do we do with it? We need to perform calculations and manipulations on this geographic information.
Your Geographic Toolkit#
Imagine you are a surveyor or an urban planner on a digital map. You have the boundary lines of a property, but you need to figure out its size, where its exact center is, and then, based on some proposed building plans (like the number of floors and height per floor), calculate the new building's potential area, height, and volume.
This requires specialized tools β digital calculators and measurement tapes that understand latitude, longitude, and shapes on a map.
This is exactly what the Geographic Utility Functions provide in our building-height
project. They are a collection of helper functions designed to perform these kinds of calculations and transformations on geographic data. Think of them as your digital toolkit for working with shapes and coordinates.
What Can Our Toolkit Do?#
Our geographic utility functions help us with tasks like:
- Measuring Areas: Calculate the size (area) of a geographic shape, like the land plot defined by the GeoJSON we fetched.
- Finding Centers: Determine the central point of a polygon. This is useful for positioning things on the map or in a 3D view.
- Calculating Building Metrics: Using the land area and user inputs (like desired floors and floor height), calculate the building's potential footprint area, total height, and volume.
- Handling Map Projections: Sometimes geographic data comes in different "coordinate systems." These functions can help convert coordinates between different systems so everything lines up correctly.
Let's focus on the main use case: taking the building shape data from the API and user inputs, and calculating the building's size metrics.
Calculating Building Metrics from Shape and Input#
The primary utility function for this task is computeGeoMatrics
. This function takes the geographic coordinates of the land plot (which we got using the API client in Chapter 2) and the user's building plan inputs (which follow the UserInputs
blueprint from Chapter 1), and calculates useful metrics.
Let's look at how you would use it:
import { computeGeoMatrics } from "./utils/geo-operations";
// Assume 'buildingCoordinates' came from the API Client (Chapter 2)
// It would look something like the 'coordinates' part of FileContents (Chapter 1)
const buildingCoordinates = [
[
[-0.1278, 51.5074], // Example coordinates for a simple square
[-0.1278, 51.5075],
[-0.1277, 51.5075],
[-0.1277, 51.5074],
[-0.1278, 51.5074], // Close the loop
],
];
// Assume 'userInput' came from the user (Chapter 1)
const userInput = {
lotCoverage: 80, // User wants the building to cover 80% of the land
floorNumber: 10, // User wants 10 floors
floorHeight: 3, // User wants each floor to be 3 meters high
};
// Now, use the utility function to calculate the metrics!
const calculatedMetrics = computeGeoMatrics(
buildingCoordinates,
userInput.floorHeight,
userInput.floorNumber,
userInput.lotCoverage
);
console.log("Calculated Building Metrics:", calculatedMetrics);
When you run this code, the computeGeoMatrics
function will take the coordinate data and the numbers from userInput
, do some calculations, and return an object containing the results.
The output calculatedMetrics
object would look something like this (the exact numbers depend on the coordinates):
// Example output (numbers will vary based on actual coordinates)
{
center: {
type: "Feature",
geometry: { type: "Point", coordinates: [-0.12775, 51.50745] },
properties: {}
},
landArea: 110.5, // Example: Land area in square meters
buildingArea: 88.4, // Example: Building footprint (80% of land area)
volume: 2652, // Example: Volume (buildingArea * floorHeight * floorNumber)
buildingHeight: 30 // Example: Height (floorHeight * floorNumber)
}
This calculatedMetrics
object now contains all the essential information about the building based on the land shape and the user's simple plan. This object follows the structure defined by the Metrics
blueprint from Chapter 1: Data Types & Models.
Under the Hood: Inside computeGeoMatrics
#
Let's peek inside the computeGeoMatrics
function (found in src/utils/geo-operations.ts
) to see how it performs these calculations.
The Process (Non-Code Walkthrough)#
Here's a simple sequence of what happens when computeGeoMatrics
is called:
- Receive Inputs: The function gets the raw geographic coordinates (like the GeoJSON shape data) and the user's numbers (floor height, floor number, lot coverage percentage).
- Understand the Shape: It uses a specialized geographic library (
@turf/turf
) to interpret the raw coordinates as a recognizable shape (a polygon). - Calculate Land Area: It asks the geographic library to calculate the area of that polygon shape.
- Perform Building Calculations: It takes the calculated land area and uses basic arithmetic (multiplication, division) with the user's floor height, floor number, and lot coverage percentage to determine the building's potential footprint area, total height, and total volume.
- Find the Center: It asks the geographic library again to find the geographic center point of the original polygon shape.
- Package Results: It gathers all the calculated values (center, land area, building area, volume, height) into a single, structured object.
- Return Results: It sends the structured object back to whoever called the function.
Here's a simple diagram of this flow:
sequenceDiagram
participant Caller as Code Calling Function
participant Cgm as computeGeoMatrics Function
participant Turf as @turf/turf Library
Caller->>Cgm: Call computeGeoMatrics(coords, fh, fn, lc)
Cgm->>Turf: Convert coords to Polygon
Cgm->>Turf: Calculate Area of Polygon
Turf-->>Cgm: Return Land Area
Cgm->>Cgm: Calculate Building Area, Height, Volume (using Land Area, fh, fn, lc)
Cgm->>Turf: Calculate Center of Polygon
Turf-->>Cgm: Return Center Point
Cgm->>Cgm: Package all results into an object
Cgm-->>Caller: Return Results Object
Code Details#
Let's look at snippets from the src/utils/geo-operations.ts
file that make this happen.
First, we need to import the necessary tools from the @turf/turf
library:
// src/utils/geo-operations.ts
import { polygon, area, centerOfMass } from "@turf/turf";
// ... rest of the file ...
This line brings in specific functions: polygon
(to create a polygon object from coordinates), area
(to calculate the area of a polygon), and centerOfMass
(to find the center).
Next, the start of the computeGeoMatrics
function:
// src/utils/geo-operations.ts
export const computeGeoMatrics = (
coordinates: any, // The shape data (like GeoJSON coords)
floorHeight: number, // User input
floorNumber: number, // User input
lotCoverage: number // User input
) => {
// Create a polygon object from the input coordinates
const areaPolygon = polygon(coordinates);
// Calculate the land area of the polygon
const landArea = area(areaPolygon);
// ... rest of the calculations ...
};
Here, polygon(coordinates)
converts the coordinate data into a format that the @turf/turf
library understands as a shape. Then, area(areaPolygon)
performs the calculation to get the size of that land plot.
Now, the simple math for building metrics:
// src/utils/geo-operations.ts (inside computeGeoMatrics)
// ... area calculation ...
// Basic math using land area and user inputs
const buildingHeight = floorHeight * floorNumber;
const buildingArea = landArea * (lotCoverage / 100); // lotCoverage is a percentage
const volume = landArea * (lotCoverage / 100) * floorHeight * floorNumber;
// This is the same as buildingArea * buildingHeight
// ... center calculation and return ...
};
These lines are straightforward multiplications. We use the calculated landArea
and the user's floorHeight
, floorNumber
, and lotCoverage
percentage to figure out the building's dimensions and volume. Notice the lotCoverage / 100
to convert the percentage into a decimal.
Finally, finding the center and returning the results:
// src/utils/geo-operations.ts (inside computeGeoMatrics)
// ... building metrics calculations ...
// Calculate the center point of the original polygon
const center = centerOfMass(areaPolygon);
// Return an object with all the results
return { center, landArea, buildingArea, volume, buildingHeight };
};
centerOfMass(areaPolygon)
calculates the central point of the shape. The function then packages center
and all the previously calculated metrics (landArea
, buildingArea
, volume
, buildingHeight
) into a single object and returns it.
There's also a small helper function round
in the actual code to keep the numbers tidy, but the core calculations are as shown above.
Other Geographic Helpers#
Besides computeGeoMatrics
, the utils
folder contains other geographic helpers, like those in src/utils/projection.ts
.
Handling Map Projections (src/utils/projection.ts
)#
Geographic data can sometimes be stored in different formats or "coordinate reference systems" (CRS). Think of it like using different types of maps (flat versus globe) or different grid systems. Sometimes, you need to convert coordinates from one system to another so they display or interact correctly.
The src/utils/projection.ts
file uses the @math.gl/proj4
library to handle this.
// src/utils/projection.ts
import { Proj4Projection } from "@math.gl/proj4";
// Set up a projection tool to convert from EPSG:3857 to WGS84
export const positionProjection = new Proj4Projection({
from: "EPSG:3857", // Web Mercator, common for web maps
to: "WGS84", // Latitude/Longitude, common for GPS/GeoJSON
});
// ... function to apply this projection to data ...
This code sets up a tool (positionProjection
) specifically for converting coordinates from one common web map system (EPSG:3857
) to the standard system often used by GPS and GeoJSON (WGS84
).
There's also a function transformLazData
which uses this tool to convert a list of coordinates (like those from a point cloud, often used in 3D data) from one system to another. This is a more advanced use case, but the core idea is using positionProjection
to convert points like positionProjection.project(vertex)
. These projection utilities ensure that map data, no matter its original format, can be correctly placed and used within our application, especially when integrating different data sources or preparing data for display in a map view.
Conclusion#
In this chapter, we explored the Geographic Utility Functions, our digital toolkit for working with map data. We learned how functions like computeGeoMatrics
take geographic shapes (fetched by the API client) and user inputs (defined by our data types) to calculate important building metrics like area, volume, and height, as well as finding the center of a property. We also touched upon how other utilities handle tasks like converting coordinates between different mapping systems using projections.
These utility functions are crucial because they transform raw geographic data into usable information and metrics that the rest of the application can understand and display.
Now that we have the building geometry (from the API client) and the calculated metrics (from the utility functions), we have everything needed to visualize the building. In the next chapter, we'll dive into how the application takes this information and turns it into something you can see on the screen: the 3D building rendering pipeline.
Next Chapter: 3D Building Rendering Pipeline
Generated by AI Codebase Knowledge Builder