diff --git a/app/Models/Tracks.php b/app/Models/Tracks.php index 828dae2..7a6731d 100755 --- a/app/Models/Tracks.php +++ b/app/Models/Tracks.php @@ -336,7 +336,7 @@ class Tracks extends Model } $query .= " ORDER BY tr.crt_d DESC"; - $limit = isset($filter["limit"]) && $filter["limit"] > 500 ? $filter["limit"] : 3000; + $limit = isset($filter["limit"]) && $filter["limit"] > 500 ? $filter["limit"] : 50000; $query .= " LIMIT ?"; $params[] = $limit; @@ -345,7 +345,7 @@ class Tracks extends Model $filtered = self::filterJumps($rawAscCleaned); $combined = $filtered; - usort($combined, fn($a, $b) => $b->lst_loc_crt_d <=> $a->lst_loc_crt_d); + // usort($combined, fn($a, $b) => $b->lst_loc_crt_d <=> $a->lst_loc_crt_d); $final = array_slice($combined, 0, 500); return $final; } @@ -392,12 +392,11 @@ class Tracks extends Model $points, $maxDistance = 150, $maxTimeGap = 20, - $maxSpeed = 40, - $maxHardJump = 800, - $maxIdleJump = 1000, - $maxRealSpeed = 150 + $maxSpeed = 100, + $maxHardJump = 100, + $maxIdleJump = 100, + $maxRealSpeed = 100 ) { - // km/h $filtered = []; $last = null; $start = null; @@ -423,7 +422,6 @@ class Tracks extends Model $speed = $timeGap > 0 ? $distance / $timeGap : 0; $realSpeedKmh = $speed * 3.6; - // Tambahan: jarak terhadap titik awal $jumpFromStart = self::haversineDistance( $start->latitude, $start->longitude, @@ -431,28 +429,23 @@ class Tracks extends Model $p->longitude ); - // 🚫 Lompatan keras (langsung > 800 m) if ($distance > $maxHardJump) { continue; } - // 🚫 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; } - // 🚫 Speed tidak masuk akal if ($realSpeedKmh > $maxRealSpeed) { continue; } - // 🚫 Lompat dari titik awal terlalu jauh (anomaly GPS loncat) - if ($jumpFromStart > 10000 && $p->speed < 5) { + if ($jumpFromStart > 500 && $p->speed < 5) { continue; } // >10 km dari area awal tapi status idle diff --git a/app/Models/Tracks_copy.php b/app/Models/Tracks_copy.php index 0a16a32..6da9264 100755 --- a/app/Models/Tracks_copy.php +++ b/app/Models/Tracks_copy.php @@ -307,12 +307,10 @@ class Tracks_copy 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"; @@ -322,12 +320,11 @@ class Tracks_copy 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 AND v.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 .= " 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,84 +335,19 @@ class Tracks_copy extends Model $params[] = $filter["start_at"]; } - // ASC supaya filter berurutan waktu - $query .= " ORDER BY tr.crt DESC"; + $query .= " ORDER BY tr.crt_d DESC"; + $limit = isset($filter["limit"]) && $filter["limit"] > 500 ? $filter["limit"] : 3000; + $query .= " LIMIT ?"; + $params[] = $limit; - if (isset($filter["limit"])) { - $query .= " LIMIT ?"; - $params[] = $filter["limit"] ?? 500; - } + $raw = DB::select($query, $params); + $rawAscCleaned = self::removeSpeedSandwich($raw); + $filtered = self::filterJumps($rawAscCleaned); + $combined = $filtered; - $query .= " ;"; - - // Ambil data - $rawTracks = DB::select($query, $params); - - // Sort manual jika perlu - usort($rawTracks, fn($a, $b) => $a->lst_loc_crt <=> $b->lst_loc_crt); - - // Filter loncatan - $filtered = self::filterJumps($rawTracks, 3000, 5, 300); - - return $filtered; - // return array_reverse($filtered); - } - - public static function filterJumps($points, $maxDistance = 3000, $maxTimeGap = 5, $maxSpeed = 150) - { - $filtered = []; - $last = null; - - // Sort dari terbaru ke terlama (pastikan sesuai kebutuhan) - usort($points, fn($a, $b) => $b->lst_loc_crt <=> $a->lst_loc_crt); - - foreach ($points as $p) { - // 1. Validasi koordinat - if (!is_numeric($p->latitude) || !is_numeric($p->longitude)) { - continue; - } - - if ( - strlen(explode(".", $p->latitude)[1] ?? "") < 6 || - strlen(explode(".", $p->longitude)[1] ?? "") < 6 - ) { - continue; - } - - if (!$last) { - $filtered[] = $p; - $last = $p; - continue; - } - - // 2. Jarak & waktu - $distance = self::haversineDistance( - $last->latitude, - $last->longitude, - $p->latitude, - $p->longitude - ); - $timeGap = $last->lst_loc_crt - $p->lst_loc_crt; - - if ($timeGap <= 0) { - continue; - } - - $speed = ($distance / $timeGap) * 3.6; // m/s to km/h - - // 3. Filter logis - if ($speed <= $maxSpeed || $distance <= $maxDistance) { - $filtered[] = $p; - $last = $p; - } - } - - // 4. Pastikan hasil minimal N - if (count($filtered) < 500 && count($points) > 500) { - return array_slice($points, 0, 500); // fallback ke raw jika terlalu sedikit - } - - 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) @@ -436,6 +368,101 @@ class Tracks_copy 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, + $maxRealSpeed = 150 + ) { + // km/h + $filtered = []; + $last = null; + $start = null; + + 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; + + // 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; + } + + // 🚫 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; + } + + // 🚫 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; + } + + return $filtered; + } + public static function nearestInCircle($lat, $lng, $rad, $filter = []) { $earth_rad = Helper::EARTH_RADIUS_M;