update
This commit is contained in:
@ -336,7 +336,7 @@ class Tracks extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
$query .= " ORDER BY tr.crt_d DESC";
|
$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 ?";
|
$query .= " LIMIT ?";
|
||||||
$params[] = $limit;
|
$params[] = $limit;
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ class Tracks extends Model
|
|||||||
$filtered = self::filterJumps($rawAscCleaned);
|
$filtered = self::filterJumps($rawAscCleaned);
|
||||||
$combined = $filtered;
|
$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);
|
$final = array_slice($combined, 0, 500);
|
||||||
return $final;
|
return $final;
|
||||||
}
|
}
|
||||||
@ -392,12 +392,11 @@ class Tracks extends Model
|
|||||||
$points,
|
$points,
|
||||||
$maxDistance = 150,
|
$maxDistance = 150,
|
||||||
$maxTimeGap = 20,
|
$maxTimeGap = 20,
|
||||||
$maxSpeed = 40,
|
$maxSpeed = 100,
|
||||||
$maxHardJump = 800,
|
$maxHardJump = 100,
|
||||||
$maxIdleJump = 1000,
|
$maxIdleJump = 100,
|
||||||
$maxRealSpeed = 150
|
$maxRealSpeed = 100
|
||||||
) {
|
) {
|
||||||
// km/h
|
|
||||||
$filtered = [];
|
$filtered = [];
|
||||||
$last = null;
|
$last = null;
|
||||||
$start = null;
|
$start = null;
|
||||||
@ -423,7 +422,6 @@ class Tracks extends Model
|
|||||||
$speed = $timeGap > 0 ? $distance / $timeGap : 0;
|
$speed = $timeGap > 0 ? $distance / $timeGap : 0;
|
||||||
$realSpeedKmh = $speed * 3.6;
|
$realSpeedKmh = $speed * 3.6;
|
||||||
|
|
||||||
// Tambahan: jarak terhadap titik awal
|
|
||||||
$jumpFromStart = self::haversineDistance(
|
$jumpFromStart = self::haversineDistance(
|
||||||
$start->latitude,
|
$start->latitude,
|
||||||
$start->longitude,
|
$start->longitude,
|
||||||
@ -431,28 +429,23 @@ class Tracks extends Model
|
|||||||
$p->longitude
|
$p->longitude
|
||||||
);
|
);
|
||||||
|
|
||||||
// 🚫 Lompatan keras (langsung > 800 m)
|
|
||||||
if ($distance > $maxHardJump) {
|
if ($distance > $maxHardJump) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🚫 Lompat saat idle (dianggap tidak wajar jika dua titik idle dan lompat jauh)
|
|
||||||
if ($distance > $maxIdleJump && $p->speed < 5 && $last->speed < 5) {
|
if ($distance > $maxIdleJump && $p->speed < 5 && $last->speed < 5) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🚫 Lompat dalam waktu pendek dan speed terlalu tinggi
|
|
||||||
if ($timeGap <= $maxTimeGap && $speed > $maxSpeed) {
|
if ($timeGap <= $maxTimeGap && $speed > $maxSpeed) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🚫 Speed tidak masuk akal
|
|
||||||
if ($realSpeedKmh > $maxRealSpeed) {
|
if ($realSpeedKmh > $maxRealSpeed) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🚫 Lompat dari titik awal terlalu jauh (anomaly GPS loncat)
|
if ($jumpFromStart > 500 && $p->speed < 5) {
|
||||||
if ($jumpFromStart > 10000 && $p->speed < 5) {
|
|
||||||
continue;
|
continue;
|
||||||
} // >10 km dari area awal tapi status idle
|
} // >10 km dari area awal tapi status idle
|
||||||
|
|
||||||
|
|||||||
@ -307,12 +307,10 @@ class Tracks_copy extends Model
|
|||||||
|
|
||||||
public static function lastMoveTracks($vid, $filter = [])
|
public static function lastMoveTracks($vid, $filter = [])
|
||||||
{
|
{
|
||||||
$now = time();
|
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
$query = "SELECT";
|
$query = "SELECT";
|
||||||
$query .= " v.id as vid,v.device_id,v.nopol1,v.nopol2,v.nopol3";
|
$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.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.ignition,tr.stts_engine";
|
||||||
$query .= " ,tr.pre_milleage,tr.sum_milleage,tr.vhc_milleage,v.sum_milleage AS vhc_sum_milleage_1";
|
$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 .= " 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.id = tr.vhc_id";
|
||||||
$query .= " LEFT JOIN " . self::T_TRACKS_ADDR . " AS addr ON tr.id = addr.master_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;
|
$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"], $filter["end_date"])) {
|
||||||
|
|
||||||
if (isset($filter["start_date"]) && isset($filter["end_date"])) {
|
|
||||||
$query .= " AND tr.crt_d BETWEEN ? AND ?";
|
$query .= " AND tr.crt_d BETWEEN ? AND ?";
|
||||||
$params[] = $filter["start_date"];
|
$params[] = $filter["start_date"];
|
||||||
$params[] = $filter["end_date"];
|
$params[] = $filter["end_date"];
|
||||||
@ -338,84 +335,19 @@ class Tracks_copy extends Model
|
|||||||
$params[] = $filter["start_at"];
|
$params[] = $filter["start_at"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ASC supaya filter berurutan waktu
|
$query .= " ORDER BY tr.crt_d DESC";
|
||||||
$query .= " ORDER BY tr.crt DESC";
|
$limit = isset($filter["limit"]) && $filter["limit"] > 500 ? $filter["limit"] : 3000;
|
||||||
|
|
||||||
if (isset($filter["limit"])) {
|
|
||||||
$query .= " LIMIT ?";
|
$query .= " LIMIT ?";
|
||||||
$params[] = $filter["limit"] ?? 500;
|
$params[] = $limit;
|
||||||
}
|
|
||||||
|
|
||||||
$query .= " ;";
|
$raw = DB::select($query, $params);
|
||||||
|
$rawAscCleaned = self::removeSpeedSandwich($raw);
|
||||||
|
$filtered = self::filterJumps($rawAscCleaned);
|
||||||
|
$combined = $filtered;
|
||||||
|
|
||||||
// Ambil data
|
usort($combined, fn($a, $b) => $b->lst_loc_crt_d <=> $a->lst_loc_crt_d);
|
||||||
$rawTracks = DB::select($query, $params);
|
$final = array_slice($combined, 0, 500);
|
||||||
|
return $final;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function haversineDistance($lat1, $lon1, $lat2, $lon2)
|
public static function haversineDistance($lat1, $lon1, $lat2, $lon2)
|
||||||
@ -436,6 +368,101 @@ class Tracks_copy extends Model
|
|||||||
return $earthRadius * $c;
|
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 = [])
|
public static function nearestInCircle($lat, $lng, $rad, $filter = [])
|
||||||
{
|
{
|
||||||
$earth_rad = Helper::EARTH_RADIUS_M;
|
$earth_rad = Helper::EARTH_RADIUS_M;
|
||||||
|
|||||||
Reference in New Issue
Block a user