from typing import Optional, Literal from pydantic import BaseModel, Field from uuid import uuid4 # Output to frontend class Landmark(BaseModel) : # Properties of the landmark name : str type: Literal['sightseeing', 'nature', 'shopping', 'start', 'finish'] location : tuple osm_type : str osm_id : int attractiveness : int n_tags : int image_url : Optional[str] = None website_url : Optional[str] = None description : Optional[str] = None # TODO future duration : Optional[int] = 0 name_en : Optional[str] = None # Unique ID of a given landmark uuid: str = Field(default_factory=uuid4) # Additional properties depending on specific tour must_do : Optional[bool] = False must_avoid : Optional[bool] = False is_secondary : Optional[bool] = False # TODO future time_to_reach_next : Optional[int] = 0 next_uuid : Optional[str] = None def __str__(self) -> str: time_to_next_str = f", time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else "" is_secondary_str = f", secondary" if self.is_secondary else "" type_str = '(' + self.type + ')' if self.type in ["start", "finish", "nature", "shopping"] : type_str += '\t ' return f'Landmark{type_str}: [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}{is_secondary_str}]' def distance(self, value: 'Landmark') -> float: return (self.location[0] - value.location[0])**2 + (self.location[1] - value.location[1])**2 def __hash__(self) -> int: return hash(self.name) def __eq__(self, value: 'Landmark') -> bool: # eq and hash must be consistent # in particular, if two objects are equal, their hash must be equal # uuid and osm_id are just shortcuts to avoid comparing all the properties # if they are equal, we know that the name is also equal and in turn the hash is equal return self.uuid == value.uuid or self.osm_id == value.osm_id or (self.name == value.name and self.distance(value) < 0.001)