diff --git a/app/Models/Tracks.php b/app/Models/Tracks.php index 3f86d9d..828dae2 100755 --- a/app/Models/Tracks.php +++ b/app/Models/Tracks.php @@ -307,11 +307,10 @@ 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"; + $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.ignition,tr.stts_engine"; $query .= " ,tr.pre_milleage,tr.sum_milleage,tr.vhc_milleage,v.sum_milleage AS vhc_sum_milleage_1"; @@ -321,13 +320,11 @@ class Tracks extends Model $query .= " FROM t_vehicles AS v"; $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.id = tr.vhc_id"; $query .= " LEFT JOIN " . self::T_TRACKS_ADDR . " AS addr ON tr.id = addr.master_id"; - $query .= " WHERE v.dlt IS NULL"; - $query .= " AND v.id = ?"; + $query .= " WHERE v.dlt IS NULL AND v.id = ?"; $params[] = $vid; - $query .= " AND tr.latitude IS NOT NULL"; - $query .= " AND tr.longitude IS NOT NULL"; + $query .= " AND tr.latitude IS NOT NULL AND tr.longitude IS NOT NULL"; - if (isset($filter["start_date"]) && isset($filter["end_date"])) { + if (isset($filter["start_date"], $filter["end_date"])) { $query .= " AND tr.crt_d BETWEEN ? AND ?"; $params[] = $filter["start_date"]; $params[] = $filter["end_date"]; @@ -338,39 +335,19 @@ class Tracks extends Model $params[] = $filter["start_at"]; } - // $query .= " GROUP BY tr.crt_d"; $query .= " ORDER BY tr.crt_d DESC"; - - if (!isset($filter["limit"]) || $filter["limit"] < 3000) { - $filter["limit"] = 3000; - } + $limit = isset($filter["limit"]) && $filter["limit"] > 500 ? $filter["limit"] : 3000; $query .= " LIMIT ?"; - $params[] = $filter["limit"]; + $params[] = $limit; $raw = DB::select($query, $params); + $rawAscCleaned = self::removeSpeedSandwich($raw); + $filtered = self::filterJumps($rawAscCleaned); + $combined = $filtered; - usort($raw, function ($a, $b) { - $aTime = strtotime($a->lst_loc_crt ?? "1970-01-01 00:00:00"); - $bTime = strtotime($b->lst_loc_crt ?? "1970-01-01 00:00:00"); - return $aTime <=> $bTime; - }); - - $filtered = self::filterJumps($raw); - - $minData = 500; - if (count($filtered) < $minData) { - $needed = $minData - count($filtered); - $lastRaw = array_slice($raw, -$needed); - $filtered = array_merge($filtered, $lastRaw); - } - - usort($filtered, function ($a, $b) { - $aTime = strtotime($a->lst_loc_crt ?? "1970-01-01 00:00:00"); - $bTime = strtotime($b->lst_loc_crt ?? "1970-01-01 00:00:00"); - return $bTime <=> $aTime; - }); - - return $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) @@ -391,21 +368,45 @@ class Tracks extends Model 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; + } + + return $cleaned; + } + public static function filterJumps( $points, $maxDistance = 150, $maxTimeGap = 20, $maxSpeed = 40, $maxHardJump = 800, - $maxIdleJump = 1000 + $maxIdleJump = 1000, + $maxRealSpeed = 150 ) { + // km/h $filtered = []; $last = null; + $start = null; foreach ($points as $p) { if (!$last) { $filtered[] = $p; $last = $p; + $start = $p; continue; } @@ -416,21 +417,45 @@ class Tracks extends Model $p->longitude ); - $timeGap = $p->lst_loc_crt - $last->lst_loc_crt; + $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; + // Tambahan: jarak terhadap titik awal + $jumpFromStart = self::haversineDistance( + $start->latitude, + $start->longitude, + $p->latitude, + $p->longitude + ); + + // 🚫 Lompatan keras (langsung > 800 m) if ($distance > $maxHardJump) { continue; } - if ($distance > $maxIdleJump && $p->speed == 0) { + + // 🚫 Lompat saat idle (dianggap tidak wajar jika dua titik idle dan lompat jauh) + if ($distance > $maxIdleJump && $p->speed < 5 && $last->speed < 5) { continue; } + + // 🚫 Lompat dalam waktu pendek dan speed terlalu tinggi if ($timeGap <= $maxTimeGap && $speed > $maxSpeed) { continue; } - if ($distance > $maxDistance) { + + // 🚫 Speed tidak masuk akal + if ($realSpeedKmh > $maxRealSpeed) { continue; } + + // 🚫 Lompat dari titik awal terlalu jauh (anomaly GPS loncat) + if ($jumpFromStart > 10000 && $p->speed < 5) { + continue; + } // >10 km dari area awal tapi status idle + $filtered[] = $p; $last = $p; }