# OSM Search Plus

A Python package for searching OpenStreetMap data with advanced features and filtering. Find abandoned places, ruins, bunkers, and other interesting locations using OpenStreetMap data.

## Installation

```bash
pip install autobex
```

## Basic Usage

```python
from autobex import OSMSearchPlus

# Initialize searcher
searcher = OSMSearchPlus()

# List all available search tags
print("Available search tags:")
for tag in searcher.list_tags():
    print(f"  - {tag}")

# Search with coordinates and radius
results = searcher.search(
    lat=42.3601,  # Latitude in decimal degrees
    lon=-71.0589, # Longitude in decimal degrees
    radius=5.0    # Search radius in miles
)

# Print results
for group in results:
    print(f"Group: {group.name}")  # Descriptive group name
    for location in group:
        print(f"  - {location}")
```

## Search Options

### Tag Configuration

You can control which tags to search for in several ways:

1. List available tags:
```python
# See what tags are available for searching
for tag in searcher.list_tags():
    print(tag)
```

2. Default tags from `tags.txt`:
```python
# Use only default tags (default behavior)
results = searcher.search(lat, lon, radius)

# Disable default tags
results = searcher.search(lat, lon, radius, use_default_tags=False)
```

3. Custom tags:
```python
# Use custom tags only
results = searcher.search(
    lat, lon, radius,
    use_default_tags=False,
    custom_tags=["building=ruins", "abandoned"]
)

# Use both default and custom tags
results = searcher.search(
    lat, lon, radius,
    custom_tags=["building=ruins"]  # Will combine with default tags
)
```

### Search Area

Search by radius:
```python
results = searcher.search(lat=42.3601, lon=-71.0589, radius=5.0)  # 5 mile radius
```

Search in polygon:
```python
polygon = [
    (42.3601, -71.0589),
    (42.3702, -71.0690),
    (42.3803, -71.0791)
]
results = searcher.search(polygon_coords=polygon)
```

### Coordinate Formats

Supports both decimal degrees and DMS format:

```python
# Decimal degrees
results = searcher.search(lat=42.3601, lon=-71.0589, radius=5.0)

# DMS format
results = searcher.search(
    lat='41°28\'50.4"N',
    lon='71°23\'35.5"W',
    radius=5.0
)
```

### Logging and Debug Information

Enable detailed logging to see search progress:

```python
results = searcher.search(lat, lon, radius, show_logs=True)
```

This will show:
- Tags being searched
- Number of elements found
- Processing progress
- Number of locations added per tag
- Total unique locations found
- Grouping information

## Location Results

Each location contains:

### Core Properties (not from OSM)
- `location.name`: Generated from OSM name or reverse geocoding
- `location.latitude`, `location.longitude`: Coordinates
- `location.distance`: Direct distance from search center in meters
- `location.road_distance`: Distance to nearest road in meters
- `location.elevation`: Elevation in meters
- `location.google_maps_url`: Link to Google Maps (maximum zoom)
- `location.bing_maps_url`: Link to Bing Maps (aerial view)
- `location.osm_url`: Link to OpenStreetMap

### OSM-specific Data
- `location.osm_id`: OpenStreetMap ID
- `location.type`: Type of element (node or way)
- `location.tags`: Dictionary of all OpenStreetMap tags

### Accessing Tag Information

```python
# Check if a tag exists
if "abandoned" in location.tags:
    print("This is an abandoned location")

# Get tag value with fallback
building_type = location.tags.get("building", "unknown")

# Print all tags
print(location.all_tags())
```

## Location Groups

Results are automatically grouped by proximity (within 100 meters). Each group has an intelligent naming system that combines:

1. Status (if common across group):
   - Abandoned
   - Ruins
   - Disused
   - Demolished

2. Type (from most specific to least specific):
   - Amenity
   - Military
   - Building
   - Historic
   - Landuse

3. Location:
   - City name (when available)
   - State/Region
   - Fallback to shortest location name if geocoding fails

4. Group size:
   - Number of locations in the group

Example group names:
- "Abandoned Factory - Boston, Massachusetts (3 locations)"
- "Military Bunker - Portland, Maine"
- "Ruins - Historic Site - Burlington, Vermont (2 locations)"

```python
for group in results:
    # Access the intelligent group name
    print(f"\nGroup: {group.name}")
    
    # Get group statistics
    print(f"Center: {group.center()}")
    print(f"Distance span: {group.distance_span()} miles")
    
    # Filter group by tag
    ruins = group.filter_by_tag("building", "ruins")
    abandoned = group.filter_by_tag("abandoned")
```

## Error Handling

The package includes automatic retry logic for API timeouts and rate limits. It will:
- Retry failed queries up to 3 times
- Use progressive backoff delays
- Handle rate limiting gracefully
- Provide detailed error messages

## Configuration Files

### tags.txt
Contains tags to search for by default. Each line should be either:
- A simple tag (e.g., `abandoned`)
- A key=value pair (e.g., `building=ruins`)
- A name pattern (e.g., `name~Factory`)

You can view all configured tags using `searcher.list_tags()`.

### excluded_tags.txt
Contains tags that will exclude locations from results. Same format as `tags.txt`.
If not found, default exclusions are used (e.g., `demolished=yes`, `highway=bus_stop`, etc.).

## Features

- List and inspect available search tags
- Intelligent group naming based on common properties
- Search by radius or polygon area
- Support for both decimal and DMS coordinates
- Automatic grouping of nearby locations (100m radius)
- Distance calculations (direct and to nearest road)
- Elevation data and reverse geocoding
- Direct links to OpenStreetMap, Google Maps, and Bing Maps
- Tag-based filtering and exclusions
- Increased timeout values for slower connections
- Comprehensive testing tools included

## Testing Tools

The package includes two testing tools to help you explore and verify functionality:

### 1. Test Query Tool (test_query.py)

A simple tool to test searches and view formatted results:

```python
python test_query.py
```

Features:
- Formatted output with distances in both metric and imperial
- Direct links to maps
- Organized tag display
- Elevation in meters and feet
- Group information

Sample output:
```
Found 1 location in 1 group

========================================
Group 1 (1 locations)
========================================

Location 1:
----------------------------------------
Name: Northeastern University Marine Science Center
Type: way
OSM ID: 123456789
Distance: 0.04 miles
Elevation: 15.2m (49.9ft)

Map Links:
  Google Maps: https://www.google.com/maps?q=42.4185,-70.9056&z=21
  Bing Maps: https://www.bing.com/maps?cp=42.4185~-70.9056&style=h&lvl=20

Tags:
  • building = yes
  • historic = ruins
  • name = Northeastern University Marine Science Center
  • abandoned = yes
```

### 2. Feature Test Suite (test_features.py)

A comprehensive test suite that verifies all major features:

```python
python test_features.py
```

Tests include:
- Radius search
- Polygon search
- Large area search
- Location grouping
- Error handling
- Coordinate parsing
- Tag filtering
- Distance calculations

Use this to:
- Verify package functionality
- Test custom configurations
- Debug search issues
- Explore feature behavior

## Dependencies

- Python 3.7+
- geopy (≥2.3.0) - For geocoding and distance calculations
- requests (≥2.25.0) - For API communication
- numpy - For mathematical operations

## Performance Tips

1. Use appropriate search radius (smaller = faster)
2. Use `limit` parameter when possible
3. Keep tag files focused and minimal
4. Use `excluded_tags.txt` to filter noise
5. Enable `show_logs=True` to monitor progress
6. Start with test tools to verify setup

## Tag Matching System

The system supports three types of tag matching:

1. Exact matches (with `=`):
   ```
   building=ruins    -> matches exactly building=ruins
   ```

2. Simple tags (without `=`):
   ```
   abandoned        -> matches:
                      - abandoned=* (any value)
                      - building=abandoned
                      - historic=abandoned
   ```

3. Name patterns (with `~`):
   ```
   name~Factory    -> matches locations with "Factory" in their name
   ```

## Support and Resources

- [GitHub Repository](https://github.com/the-Drunken-coder/Autobex)
- [Issue Tracker](https://github.com/the-Drunken-coder/Autobex/issues)
- [Documentation](https://github.com/the-Drunken-coder/Autobex#readme)

## License

MIT License - see LICENSE file for details.

## Acknowledgments

- OpenStreetMap contributors
- Open-Elevation API
- All package contributors
