129 lines
3.1 KiB
PHP
129 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
class Position extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'device_id',
|
|
'traccar_position_id',
|
|
'protocol',
|
|
'device_time',
|
|
'fix_time',
|
|
'server_time',
|
|
'outdated',
|
|
'valid',
|
|
'latitude',
|
|
'longitude',
|
|
'altitude',
|
|
'speed',
|
|
'course',
|
|
'address',
|
|
'accuracy',
|
|
'network',
|
|
'attributes',
|
|
];
|
|
|
|
protected $casts = [
|
|
'device_time' => 'datetime',
|
|
'fix_time' => 'datetime',
|
|
'server_time' => 'datetime',
|
|
'outdated' => 'boolean',
|
|
'valid' => 'boolean',
|
|
'latitude' => 'decimal:8',
|
|
'longitude' => 'decimal:8',
|
|
'altitude' => 'decimal:2',
|
|
'speed' => 'decimal:2',
|
|
'course' => 'decimal:2',
|
|
'accuracy' => 'decimal:2',
|
|
'attributes' => 'array',
|
|
];
|
|
|
|
/**
|
|
* Get the device that owns this position
|
|
*/
|
|
public function device(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Device::class);
|
|
}
|
|
|
|
/**
|
|
* Scope for recent positions
|
|
*/
|
|
public function scopeRecent($query, $hours = 24)
|
|
{
|
|
return $query->where('device_time', '>=', now()->subHours($hours));
|
|
}
|
|
|
|
/**
|
|
* Scope for valid positions
|
|
*/
|
|
public function scopeValid($query)
|
|
{
|
|
return $query->where('valid', true);
|
|
}
|
|
|
|
/**
|
|
* Get formatted speed with unit
|
|
*/
|
|
public function getFormattedSpeed(): string
|
|
{
|
|
$speedKmh = $this->speed * 1.852; // Convert knots to km/h
|
|
return round($speedKmh, 1) . ' km/h';
|
|
}
|
|
|
|
/**
|
|
* Get formatted coordinates
|
|
*/
|
|
public function getCoordinates(): string
|
|
{
|
|
return number_format($this->latitude, 6) . ', ' . number_format($this->longitude, 6);
|
|
}
|
|
|
|
/**
|
|
* Check if position is in a specific geofence
|
|
*/
|
|
public function isInGeofence(Geofence $geofence): bool
|
|
{
|
|
// Simple point-in-polygon check for circular geofences
|
|
if ($geofence->type === 'circle') {
|
|
$distance = $this->calculateDistance(
|
|
$this->latitude,
|
|
$this->longitude,
|
|
$geofence->latitude,
|
|
$geofence->longitude
|
|
);
|
|
|
|
return $distance <= $geofence->radius;
|
|
}
|
|
|
|
// For polygon geofences, you would implement a point-in-polygon algorithm
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Calculate distance between two points in meters
|
|
*/
|
|
private function calculateDistance($lat1, $lon1, $lat2, $lon2): float
|
|
{
|
|
$earthRadius = 6371000; // Earth's radius in meters
|
|
|
|
$dLat = deg2rad($lat2 - $lat1);
|
|
$dLon = deg2rad($lon2 - $lon1);
|
|
|
|
$a = sin($dLat / 2) * sin($dLat / 2) +
|
|
cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
|
|
sin($dLon / 2) * sin($dLon / 2);
|
|
|
|
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
|
|
|
|
return $earthRadius * $c;
|
|
}
|
|
}
|