update
This commit is contained in:
@ -310,21 +310,6 @@ class Tracks extends Model
|
||||
$now = time();
|
||||
$params = [];
|
||||
|
||||
/**
|
||||
* bikin lemot 30s timeout karena ada 2 join di rows yang banyak
|
||||
* solution: indexing column
|
||||
* show index from t_gps_tracks_address;
|
||||
* create index addr_device_id on t_gps_tracks_address (device_id);
|
||||
* create index addr_master_id on t_gps_tracks_address (master_id);
|
||||
* show index from t_gps_tracks;
|
||||
* create index tracks_device_id on t_gps_tracks (device_id);
|
||||
* show index from t_vehicles;
|
||||
* create index vhc_device_id on t_vehicles (device_id);
|
||||
*
|
||||
* solution not working. Don't reinvent the wheel
|
||||
* create view. not working
|
||||
*/
|
||||
|
||||
$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";
|
||||
@ -335,22 +320,17 @@ class Tracks extends Model
|
||||
$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 .= " FROM t_vehicles AS v";
|
||||
// $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 .= " 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 = ?";
|
||||
array_push($params, $vid);
|
||||
$query .= " AND tr.latitude is not null";
|
||||
$query .= " AND tr.longitude is not null";
|
||||
$query .= " WHERE v.dlt is null AND v.id = ?";
|
||||
$params[] = $vid;
|
||||
|
||||
// last move based on date
|
||||
// $query .= " AND tr.crt BETWEEN ? AND ?";
|
||||
// array_push($params, strtotime('-24 hours', $now), $now);
|
||||
$query .= " AND tr.latitude is not null AND tr.longitude is not null";
|
||||
|
||||
if (isset($filter["start_date"]) && isset($filter["end_date"])) {
|
||||
$query .= " AND tr.crt_d BETWEEN ? AND ?";
|
||||
array_push($params, $filter["start_date"], $filter["end_date"]);
|
||||
$params[] = $filter["start_date"];
|
||||
$params[] = $filter["end_date"];
|
||||
}
|
||||
|
||||
if (isset($filter["start_at"])) {
|
||||
@ -358,10 +338,8 @@ 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";
|
||||
// array_push($params, strtotime('-24 hours', $now), $now);
|
||||
// ASC supaya filter berurutan waktu
|
||||
$query .= " ORDER BY tr.crt DESC";
|
||||
|
||||
if (isset($filter["limit"])) {
|
||||
$query .= " LIMIT ?";
|
||||
@ -370,14 +348,75 @@ class Tracks extends Model
|
||||
|
||||
$query .= " ;";
|
||||
|
||||
// return DB::select($query, $params);
|
||||
// Ambil data
|
||||
$rawTracks = DB::select($query, $params);
|
||||
$cleanTracks = self::filterJumps($rawTracks);
|
||||
|
||||
if (isset($filter["limit"])) {
|
||||
return array_slice($cleanTracks, 0, $filter["limit"]);
|
||||
// Sort manual jika perlu
|
||||
usort($rawTracks, fn($a, $b) => $a->lst_loc_crt <=> $b->lst_loc_crt);
|
||||
|
||||
// Filter loncatan
|
||||
$filtered = self::filterJumps($rawTracks, 1000, 5, 300);
|
||||
|
||||
// return $filtered;
|
||||
return array_reverse($filtered);
|
||||
}
|
||||
|
||||
public static function filterJumps($points, $maxDistance = 1000, $maxTimeGap = 5, $maxSpeed = 300)
|
||||
{
|
||||
$filtered = [];
|
||||
$last = null;
|
||||
|
||||
foreach ($points as $p) {
|
||||
// 🛡️ 1. Validasi data koordinat
|
||||
if (!is_numeric($p->latitude) || !is_numeric($p->longitude)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen((string) abs($p->latitude)) < 8 || strlen((string) abs($p->longitude)) < 8) {
|
||||
// Buang lat/lon kurang dari 8 digit desimal (umumnya noise)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$last) {
|
||||
$filtered[] = $p;
|
||||
$last = $p;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. Hitung jarak dan waktu
|
||||
$distance = self::haversineDistance(
|
||||
$last->latitude,
|
||||
$last->longitude,
|
||||
$p->latitude,
|
||||
$p->longitude
|
||||
);
|
||||
$timeGap = $p->lst_loc_crt - $last->lst_loc_crt;
|
||||
|
||||
if ($timeGap <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$speed = ($distance / $timeGap) * 3.6; // m/s to km/h
|
||||
|
||||
// 🧠 3. Validasi kombinasi logis
|
||||
if ($speed <= $maxSpeed && ($distance <= $maxDistance || $timeGap >= $maxTimeGap)) {
|
||||
$filtered[] = $p;
|
||||
$last = $p;
|
||||
} else {
|
||||
// Optional debug:
|
||||
// Log::info("LONCAT: speed={$speed}, dist={$distance}, timeGap={$timeGap}, pointID={$p->master_id}");
|
||||
}
|
||||
}
|
||||
return $cleanTracks;
|
||||
|
||||
// ⏳ Tambahkan titik terakhir jika tidak masuk
|
||||
if (!empty($points)) {
|
||||
$lastPoint = end($points);
|
||||
if (empty($filtered) || end($filtered)->lst_loc_crt !== $lastPoint->lst_loc_crt) {
|
||||
$filtered[] = $lastPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
public static function haversineDistance($lat1, $lon1, $lat2, $lon2)
|
||||
@ -398,35 +437,6 @@ class Tracks extends Model
|
||||
return $earthRadius * $c;
|
||||
}
|
||||
|
||||
public static function filterJumps($points, $maxDistance = 50, $maxTimeGap = 10)
|
||||
{
|
||||
$filtered = [];
|
||||
$last = null;
|
||||
|
||||
foreach ($points as $p) {
|
||||
if (!$last) {
|
||||
$filtered[] = $p;
|
||||
$last = $p;
|
||||
continue;
|
||||
}
|
||||
|
||||
$distance = self::haversineDistance(
|
||||
$last->latitude,
|
||||
$last->longitude,
|
||||
$p->latitude,
|
||||
$p->longitude
|
||||
);
|
||||
$timeGap = $p->lst_loc_crt - $last->lst_loc_crt;
|
||||
|
||||
if ($distance <= $maxDistance || $timeGap > $maxTimeGap) {
|
||||
$filtered[] = $p;
|
||||
$last = $p;
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
public static function nearestInCircle($lat, $lng, $rad, $filter = [])
|
||||
{
|
||||
$earth_rad = Helper::EARTH_RADIUS_M;
|
||||
|
||||
@ -128,19 +128,19 @@ class Tracks_copy extends Model
|
||||
}
|
||||
if (isset($filter["get_order_data"])) {
|
||||
// the old way => only 1 order 1 vehicle
|
||||
// $query .= " LEFT JOIN t_orders as ord ON v.ord_id = ord.id";
|
||||
// $query .= " LEFT JOIN t_orders_pickups as ord_pck ON v.ord_id = ord_pck.ord_id";
|
||||
// $query .= " LEFT JOIN t_orders_drops as ord_drop ON v.ord_id = ord_drop.ord_id";
|
||||
// $query .= " LEFT JOIN t_orders_drivers as ord_drv ON v.ord_id = ord_drv.ord_id";
|
||||
// $query .= " LEFT JOIN t_orders_clients as ord_c ON v.ord_id = ord_c.ord_id";
|
||||
$query .= " LEFT JOIN t_orders as ord ON v.ord_id = ord.id";
|
||||
$query .= " LEFT JOIN t_orders_pickups as ord_pck ON v.ord_id = ord_pck.ord_id";
|
||||
$query .= " LEFT JOIN t_orders_drops as ord_drop ON v.ord_id = ord_drop.ord_id";
|
||||
$query .= " LEFT JOIN t_orders_drivers as ord_drv ON v.ord_id = ord_drv.ord_id";
|
||||
$query .= " LEFT JOIN t_orders_clients as ord_c ON v.ord_id = ord_c.ord_id";
|
||||
|
||||
// the new way => can handle 2 order in 1 vehicle
|
||||
$query .= " LEFT JOIN t_orders_vehicles as ord_vhc ON v.id = ord_vhc.vhc_id";
|
||||
$query .= " LEFT JOIN t_orders as ord ON ord_vhc.ord_id = ord.id";
|
||||
$query .= " LEFT JOIN t_orders_pickups as ord_pck ON ord_vhc.ord_id = ord_pck.ord_id";
|
||||
$query .= " LEFT JOIN t_orders_drops as ord_drop ON ord_vhc.ord_id = ord_drop.ord_id";
|
||||
$query .= " LEFT JOIN t_orders_drivers as ord_drv ON ord_vhc.ord_id = ord_drv.ord_id";
|
||||
$query .= " LEFT JOIN t_orders_clients as ord_c ON ord_vhc.ord_id = ord_c.ord_id";
|
||||
// $query .= " LEFT JOIN t_orders_vehicles as ord_vhc ON v.id = ord_vhc.vhc_id";
|
||||
// $query .= " LEFT JOIN t_orders as ord ON ord_vhc.ord_id = ord.id";
|
||||
// $query .= " LEFT JOIN t_orders_pickups as ord_pck ON ord_vhc.ord_id = ord_pck.ord_id";
|
||||
// $query .= " LEFT JOIN t_orders_drops as ord_drop ON ord_vhc.ord_id = ord_drop.ord_id";
|
||||
// $query .= " LEFT JOIN t_orders_drivers as ord_drv ON ord_vhc.ord_id = ord_drv.ord_id";
|
||||
// $query .= " LEFT JOIN t_orders_clients as ord_c ON ord_vhc.ord_id = ord_c.ord_id";
|
||||
}
|
||||
$query .= " WHERE v.dlt is null";
|
||||
// $query .= " AND tr.action IN ('location','alarm')"; // kalo gamau ngambil data heartbeat(idling)
|
||||
@ -211,6 +211,7 @@ class Tracks_copy extends Model
|
||||
$query .= " AND ord_c.c_id = ?";
|
||||
$params[] = $filter["client_id"];
|
||||
}
|
||||
// $query .= " AND ord.status IN (22,4)";
|
||||
}
|
||||
if (isset($filter["company"])) {
|
||||
$query .= " AND client.id = ?";
|
||||
|
||||
Reference in New Issue
Block a user