This commit is contained in:
meusinfirmary
2025-07-15 03:03:27 +07:00
parent 1ee5cbb1a8
commit 86e9c43cfd
5 changed files with 727 additions and 145 deletions

View File

@ -307,27 +307,40 @@ class Tracks extends Model
public static function lastMoveTracks($vid, $filter = [])
{
$now = time();
$params = [];
$query = "SELECT";
$query .= " v.id as vid,v.device_id,v.nopol1,v.nopol2,v.nopol3";
$query .= " ,tr.id as master_id,tr.latitude,tr.longitude,tr.speed,tr.orientation, tr.crt_d_format";
$query .= " ,tr.crt AS lst_loc_crt,tr.crt_d AS lst_loc_crt_d,tr.crt_s AS lst_loc_crt_s";
$query .= " ,tr.id as master_id,tr.latitude,tr.longitude,tr.speed,tr.orientation";
$query .= "
,(tr.crt + ( 9 * 3600 )) AS lst_loc_crt
,(tr.crt_d + ( 9 * 3600 )) AS lst_loc_crt_d
,tr.crt_s AS lst_loc_crt_s";
$query .= " ,tr.ignition,tr.stts_engine";
$query .= " ,tr.pre_milleage,tr.sum_milleage,tr.vhc_milleage,v.sum_milleage AS vhc_sum_milleage_1";
$query .= " ,addr.master_id AS addr_master_id,addr.crt AS addr_loc_crt";
$query .=
" ,addr.country_text,addr.state_text,addr.city_text,addr.district_text,addr.village_text,addr.postcode,addr.streets,addr.postcode,addr.fulladdress";
$query .= " ,addr.country_text,
addr.state_text,addr.city_text,addr.district_text,addr.village_text,addr.postcode,addr.streets,addr.postcode,
concat(addr.fulladdress,';',tr.id) as fulladdress
";
$query .= " FROM t_vehicles AS v";
$query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.id = tr.vhc_id";
// $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.device_id = tr.device_id"; // cara lama berlaku utk gps tracker saja
$query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.id = tr.vhc_id"; // support gps tracker dan smartphone / apapun yang mempunyai device_id(IMEI)
$query .= " LEFT JOIN " . self::T_TRACKS_ADDR . " AS addr ON tr.id = addr.master_id";
$query .= " WHERE v.dlt IS NULL AND v.id = ?";
$params[] = $vid;
$query .= " AND tr.latitude IS NOT NULL AND tr.longitude IS NOT NULL";
$query .= " WHERE v.dlt is null";
$query .= " AND v.id = ?";
array_push($params, $vid);
$query .= " AND tr.latitude is not null";
$query .= " AND tr.longitude is not null";
$query .= " AND tr.action in ('location')";
if (isset($filter["start_date"], $filter["end_date"])) {
// last move based on date
// $query .= " AND tr.crt BETWEEN ? AND ?";
// array_push($params, strtotime('-24 hours', $now), $now);
if (isset($filter["start_date"]) && isset($filter["end_date"])) {
$query .= " AND tr.crt_d BETWEEN ? AND ?";
$params[] = $filter["start_date"];
$params[] = $filter["end_date"];
array_push($params, $filter["start_date"], $filter["end_date"]);
}
if (isset($filter["start_at"])) {
@ -335,125 +348,29 @@ class Tracks extends Model
$params[] = $filter["start_at"];
}
// last move based on last count data
$query .= " GROUP BY tr.crt_d";
$query .= " ORDER BY tr.crt_d DESC";
$limit = isset($filter["limit"]) && $filter["limit"] > 500 ? $filter["limit"] : 50000;
$query .= " LIMIT ?";
$params[] = $limit;
// $query .= " ORDER BY tr.id DESC";
// array_push($params, strtotime('-24 hours', $now), $now);
$raw = DB::select($query, $params);
$rawAscCleaned = self::removeSpeedSandwich($raw);
$filtered = self::filterJumps($rawAscCleaned);
$combined = $filtered;
// usort($combined, fn($a, $b) => $b->lst_loc_crt_d <=> $a->lst_loc_crt_d);
$final = array_slice($combined, 0, 500);
return $final;
}
public static function haversineDistance($lat1, $lon1, $lat2, $lon2)
{
$earthRadius = 6371000; // meters
$lat1 = deg2rad($lat1);
$lon1 = deg2rad($lon1);
$lat2 = deg2rad($lat2);
$lon2 = deg2rad($lon2);
$dlat = $lat2 - $lat1;
$dlon = $lon2 - $lon1;
$a = sin($dlat / 2) ** 2 + cos($lat1) * cos($lat2) * sin($dlon / 2) ** 2;
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
return $earthRadius * $c;
}
private static function removeSpeedSandwich($data)
{
$cleaned = [];
for ($i = 0; $i < count($data); $i++) {
$next = $data[$i + 1] ?? null; // lebih lama
$curr = $data[$i];
$prev = $data[$i - 1] ?? null; // lebih baru
// Logika dibalik: prev = lebih baru, next = lebih lama
if ($prev && $next && $prev->speed > 5 && $curr->speed < 5 && $next->speed > 5) {
continue;
}
$cleaned[] = $curr;
if (isset($filter["limit"])) {
$query .= " LIMIT ?";
$params[] = $filter["limit"] ?? 500;
}
return $cleaned;
}
$query .= " ;";
public static function filterJumps(
$points,
$maxDistance = 150,
$maxTimeGap = 20,
$maxSpeed = 100,
$maxHardJump = 100,
$maxIdleJump = 100,
$maxRealSpeed = 100
) {
$filtered = [];
$last = null;
$start = null;
// return DB::select($query, $params);
$rawTracks = DB::select($query, $params);
// $cleanTracks = self::filterJumps($rawTracks);
$cleanTracks = $rawTracks;
//dd($cleanTracks);
foreach ($points as $p) {
if (!$last) {
$filtered[] = $p;
$last = $p;
$start = $p;
continue;
}
$distance = self::haversineDistance(
$last->latitude,
$last->longitude,
$p->latitude,
$p->longitude
);
$t1 = strtotime($last->lst_loc_crt);
$t2 = strtotime($p->lst_loc_crt);
$timeGap = $t2 - $t1;
$speed = $timeGap > 0 ? $distance / $timeGap : 0;
$realSpeedKmh = $speed * 3.6;
$jumpFromStart = self::haversineDistance(
$start->latitude,
$start->longitude,
$p->latitude,
$p->longitude
);
if ($distance > $maxHardJump) {
continue;
}
if ($distance > $maxIdleJump && $p->speed < 5 && $last->speed < 5) {
continue;
}
if ($timeGap <= $maxTimeGap && $speed > $maxSpeed) {
continue;
}
if ($realSpeedKmh > $maxRealSpeed) {
continue;
}
if ($jumpFromStart > 500 && $p->speed < 5) {
continue;
} // >10 km dari area awal tapi status idle
$filtered[] = $p;
$last = $p;
}
return $filtered;
// if (isset($filter["limit"])) {
// return array_slice($cleanTracks, 0, $filter["limit"]);
// }
return $cleanTracks;
}
public static function nearestInCircle($lat, $lng, $rad, $filter = [])