133 lines
4.0 KiB
Python
133 lines
4.0 KiB
Python
from pydantic import BaseModel, Field
|
|
from typing import Optional, List, Dict, Any
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
|
|
from .green_space import Coordinates
|
|
|
|
class TreeCategory(str, Enum):
|
|
STREET_TREE = "street_tree"
|
|
PARK_TREE = "park_tree"
|
|
ANLAGEBAUM = "anlagebaum"
|
|
ALLEE_TREE = "allee_tree"
|
|
|
|
class TreeHealthStatus(str, Enum):
|
|
EXCELLENT = "excellent"
|
|
GOOD = "good"
|
|
FAIR = "fair"
|
|
POOR = "poor"
|
|
CRITICAL = "critical"
|
|
UNKNOWN = "unknown"
|
|
|
|
class TreeGenus(str, Enum):
|
|
AHORN = "ahorn"
|
|
LINDE = "linde"
|
|
KASTANIE = "kastanie"
|
|
EICHE = "eiche"
|
|
PLATANE = "platane"
|
|
BIRKE = "birke"
|
|
WEISSDORN = "weissdorn"
|
|
ROSSKASTANIE = "rosskastanie"
|
|
PAPPEL = "pappel"
|
|
ESCHE = "esche"
|
|
OTHER = "other"
|
|
|
|
class StreetTree(BaseModel):
|
|
"""Individual street tree model based on Berlin Baumkataster data."""
|
|
|
|
id: str
|
|
object_id: Optional[int] = None
|
|
tree_id: Optional[str] = None
|
|
location_number: Optional[str] = None
|
|
identifier: Optional[str] = None
|
|
|
|
object_name: Optional[str] = None
|
|
species_german: Optional[str] = None
|
|
species_botanical: Optional[str] = None
|
|
genus_german: Optional[str] = None
|
|
genus_botanical: Optional[str] = None
|
|
genus_category: Optional[TreeGenus] = None
|
|
|
|
coordinates: Coordinates
|
|
district: Optional[str] = None
|
|
owner: Optional[str] = None
|
|
category: Optional[str] = None
|
|
|
|
street: Optional[str] = None
|
|
house_number: Optional[str] = None
|
|
address_addition: Optional[str] = None
|
|
full_address: Optional[str] = None
|
|
|
|
planting_year: Optional[int] = None
|
|
age: Optional[int] = None
|
|
crown_diameter_m: Optional[float] = None
|
|
trunk_circumference_cm: Optional[int] = None
|
|
height_m: Optional[float] = None
|
|
|
|
health_status: TreeHealthStatus = TreeHealthStatus.UNKNOWN
|
|
confidence_score: int = Field(80, ge=0, le=100)
|
|
|
|
last_updated: datetime = Field(default_factory=datetime.now)
|
|
|
|
class TreeDensityMetrics(BaseModel):
|
|
"""Tree density and coverage metrics for an area."""
|
|
|
|
total_trees: int = 0
|
|
trees_per_hectare: float = 0.0
|
|
average_tree_age: Optional[float] = None
|
|
average_height: Optional[float] = None
|
|
average_crown_diameter: Optional[float] = None
|
|
|
|
shade_coverage_percent: float = Field(0.0, ge=0, le=100)
|
|
mature_trees_count: int = 0 # Trees older than 20 years
|
|
young_trees_count: int = 0 # Trees younger than 10 years
|
|
|
|
dominant_species: List[str] = []
|
|
species_diversity_score: int = Field(0, ge=0, le=100)
|
|
|
|
class TreeShadeAnalysis(BaseModel):
|
|
"""Shade analysis for picnic spot evaluation."""
|
|
|
|
has_nearby_trees: bool = False
|
|
trees_within_50m: int = 0
|
|
trees_within_100m: int = 0
|
|
|
|
estimated_shade_coverage: int = Field(0, ge=0, le=100)
|
|
shade_quality_score: int = Field(0, ge=0, le=100)
|
|
|
|
best_shade_times: List[str] = [] # Time periods with best shade
|
|
seasonal_shade_variation: Optional[str] = None
|
|
|
|
nearby_large_trees: List[StreetTree] = []
|
|
canopy_density: Optional[float] = None
|
|
|
|
class TreesSearchFilters(BaseModel):
|
|
"""Filters for searching trees."""
|
|
|
|
species: Optional[List[str]] = None
|
|
genus: Optional[List[TreeGenus]] = None
|
|
min_age: Optional[int] = None
|
|
max_age: Optional[int] = None
|
|
min_height: Optional[float] = None
|
|
max_height: Optional[float] = None
|
|
min_crown_diameter: Optional[float] = None
|
|
district: Optional[str] = None
|
|
category: Optional[str] = None
|
|
|
|
within_radius_m: Optional[int] = None
|
|
center_lat: Optional[float] = None
|
|
center_lng: Optional[float] = None
|
|
|
|
class TreesNearLocationResponse(BaseModel):
|
|
"""Response for trees near a location query."""
|
|
|
|
location: Coordinates
|
|
radius_m: int
|
|
trees: List[StreetTree]
|
|
metrics: TreeDensityMetrics
|
|
shade_analysis: TreeShadeAnalysis
|
|
|
|
total_found: int
|
|
query_time_ms: Optional[int] = None
|
|
data_source: str = "baumkataster"
|
|
last_updated: datetime = Field(default_factory=datetime.now) |