Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phpgeo Laravel Package

mjaschen/phpgeo

PHPGeo is a lightweight geospatial library for PHP. Model geographic coordinates (with ellipsoid support) and compute high‑precision distances and related calculations between points. Compatible with modern PHP versions (8.2+ for latest).

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require mjaschen/phpgeo
    

    Ensure your composer.json targets PHP 8.2+ (recommended: ^6.0).

  2. First Use Case: Calculate distance between two coordinates (e.g., Mauna Kea and Haleakala):

    use Location\Coordinate;
    use Location\Distance\Vincenty;
    
    $pointA = new Coordinate(19.820664, -155.468066); // Mauna Kea
    $pointB = new Coordinate(20.709722, -156.253333); // Haleakala
    $distance = (new Vincenty())->getDistance($pointA, $pointB); // 128130.850 meters
    
  3. Key Classes to Explore:

    • Coordinate: Represents latitude/longitude.
    • Vincenty/Haversine: Distance calculators.
    • Polygon: For geofencing (e.g., "Is this point inside my area?").
    • Polyline: For GPS tracks or routes.
  4. Documentation: Start with the official docs for class references and examples.


Implementation Patterns

Core Workflows

1. Distance Calculations

  • Use Case: Shipping costs, proximity searches, or route planning.
  • Pattern:
    $calculator = new Vincenty(); // or Haversine for simpler (but less accurate) results
    $distance = $calculator->getDistance($coord1, $coord2);
    
  • Laravel Integration: Store distances in meters in a database, then convert to km/miles for display:
    $distanceKm = $distance / 1000;
    

2. Geofencing (Polygon Containment)

  • Use Case: Restrict user access to specific regions (e.g., delivery zones).
  • Pattern:
    $geofence = new Polygon();
    $geofence->addPoint(new Coordinate(/* ... */));
    
    if ($geofence->contains($userLocation)) {
        // Allow access
    }
    
  • Laravel Tip: Use a scopeGeofenced() query builder method:
    // app/Models/User.php
    public function scopeGeofenced($query, Polygon $geofence) {
        return $query->where(function($q) use ($geofence) {
            $q->whereRaw("ST_Contains(ST_GeomFromText('POLYGON(...')), ST_Point(longitude, latitude))");
        });
    }
    

3. Polyline Simplification

  • Use Case: Optimize GPS track storage or reduce API payloads.
  • Pattern:
    $polyline = new Polyline();
    $polyline->addPoint(new Coordinate(/* ... */));
    
    $simplified = (new \Location\Simplify($polyline))->simplify(1000); // Tolerance: 1km
    
  • Laravel Tip: Serialize simplified polylines to JSON for caching:
    Cache::remember("user_{$userId}_route", now()->addHours(1), function() use ($polyline) {
        return $polyline->format(new \Location\Formatter\Polyline\GeoJSON());
    });
    

4. Bearing and Destination Points

  • Use Case: Navigation apps or calculating offsets (e.g., "1km north of this point").
  • Pattern:
    $bearing = $coord1->getBearingTo($coord2); // Degrees (0-360)
    $destination = $coord1->getDestinationPoint($bearing, 1000); // 1km away
    

5. Coordinate Formatting

  • Use Case: User-friendly displays (e.g., "18° 54′ 41″ N").
  • Pattern:
    $formatter = (new \Location\Formatter\Coordinate\DMS())
        ->setSeparator(", ")
        ->useCardinalLetters(true);
    echo $coord->format($formatter); // "18° 54' 41" N, 155° 40' 42" W"
    

Integration Tips

Database Storage

  • Store coordinates as decimal(10,8) for latitude/longitude (e.g., latitude DECIMAL(10,8)).
  • Use PostgreSQL’s GEOGRAPHY type for advanced queries:
    // Using Laravel Scout with PostGIS
    use Laravel\Scout\Builder;
    
    class LocationScout extends Builder {
        public function geofenced($polygon) {
            return $this->whereRaw("ST_Intersects(geography, ST_GeomFromText('POLYGON(...)'))");
        }
    }
    

API Responses

  • Return formatted coordinates in responses:
    return response()->json([
        'location' => [
            'decimal' => $coord->format(new \Location\Formatter\Coordinate\DecimalDegrees()),
            'dms' => $coord->format(new \Location\Formatter\Coordinate\DMS()),
        ],
    ]);
    

Caching

  • Cache distance calculations for static pairs (e.g., city centers):
    Cache::remember("distance_{$fromId}_{$toId}", now()->addHours(1), function() use ($from, $to) {
        return (new Vincenty())->getDistance($from, $to);
    });
    

Testing

  • Use Location\Test\Assertions for assertions:
    $this->assertTrue($geofence->contains($point));
    $this->assertAlmostEqual(128130.850, $distance, 0.001);
    

Gotchas and Tips

Pitfalls

  1. Ellipsoid Assumptions:

    • By default, phpgeo uses the WGS-84 ellipsoid (correct for most GPS data). Gotcha: If working with non-Earth data (e.g., Mars), explicitly set the ellipsoid:
      $coord = new Coordinate(..., ..., new \Location\Ellipsoid\Custom(/* ... */));
      
  2. Polygon Edge Cases:

    • Self-intersecting polygons: The contains() method may return false positives.
    • Crossing the 180° meridian: Split the polygon into multiple non-crossing polygons or use a library like JTS for robust handling.
  3. Floating-Point Precision:

    • Distance calculations can suffer from floating-point errors. For critical applications, round coordinates to 6-8 decimal places before calculations:
      $coord = new Coordinate(round($lat, 6), round($lon, 6));
      
  4. Immutable Objects:

    • Line, Polyline, and Polygon are immutable post-construction. To "modify" them, create a new instance:
      // Wrong (throws exception):
      $polyline->addPoint($newPoint);
      
      // Correct:
      $newPolyline = clone $polyline;
      $newPolyline->addPoint($newPoint);
      
  5. Performance:

    • Vincenty vs. Haversine: Vincenty is more accurate but slower (~10x). Use Haversine for non-critical applications (e.g., approximate distances).
    • Large Polylines: Simplify polylines early to avoid memory issues:
      $polyline = (new \Location\Simplify($rawPolyline))->simplify(1000)->getPolyline();
      
  6. GeoJSON Quirks:

    • Coordinate Order: GeoJSON expects [longitude, latitude], but phpgeo uses [latitude, longitude]. Use GeoJSON formatter carefully:
      $geoJson = $coord->format(new \Location\Formatter\Coordinate\GeoJSON());
      // Output: { "type": "point", "coordinates": [ -155.678268, 18.911306 ] }
      

Debugging Tips

  1. Visualize Geometries:

    • Use Leaflet.js or Mapbox GL JS to render geometries for debugging:
      // Dump GeoJSON to a view
      return view('debug', [
          'geojson' => $polygon->format(new \Location\Formatter\Polygon\GeoJSON()),
      ]);
      
  2. Log Coordinates:

    • Add a helper to log coordinates in DMS format:
      if (
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor