111 lines
4.6 KiB
PHP
111 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* Pulpit / Mapa Obiektów. Nanosi studnie jako kropki na płaszczyznę wg
|
|
* LOKALNYCH współrzędnych geodezyjnych (seg_wells.WLL_LATITUDE/WLL_LONGITUDE -
|
|
* siatka kopalniana w metrach, NIE WGS84). Normalizacja min-max do obszaru mapy
|
|
* daje dokładny względny układ pola studni (bez internetu - air-gap OK).
|
|
*
|
|
* Kolor kropki: zielony = pompa pracuje (ON), czerwony = nie pracuje (OFF).
|
|
*/
|
|
class DashboardController extends Controller
|
|
{
|
|
/** Margines obszaru mapy (%), żeby kropki nie dotykały krawędzi. */
|
|
private const PAD = 6;
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$department = $request->session()->get('department');
|
|
|
|
$rows = DB::connection('softspm')->table('seg_wells as w')
|
|
->join('seg_dev_resources as drw', function ($j) {
|
|
$j->on('drw.DRS_DEV_ID', '=', 'w.WLL_ID')->where('drw.DRS_DEV_TYPE', '=', 12);
|
|
})
|
|
->where('drw.DRS_DEPARTMENT', $department)
|
|
->where('drw.DRS_STATUS_DIC_ID', 3) // w eksploatacji
|
|
->select('drw.DRS_ID as drs_id', 'w.WLL_NAME as name', 'w.WLL_LATITUDE as lat', 'w.WLL_LONGITUDE as lon')
|
|
->get();
|
|
|
|
// Parsowanie współrzędnych (przecinek lub kropka dziesiętna), odrzucenie błędnych.
|
|
$num = function ($v) {
|
|
$s = str_replace([',', ' '], ['.', ''], (string) $v);
|
|
return is_numeric($s) ? (float) $s : null;
|
|
};
|
|
$wells = $rows->map(function ($r) use ($num) {
|
|
$r->lat = $num($r->lat);
|
|
$r->lon = $num($r->lon);
|
|
return $r;
|
|
})->filter(fn ($r) => $r->lat !== null && $r->lon !== null && $r->lat > 0 && $r->lon > 0)->values();
|
|
|
|
// Stan ON/OFF dla naniesionych studni (DRD_RESOURCES_DETAIL=507).
|
|
$onoff = $this->onOff($wells->pluck('drs_id')->all());
|
|
|
|
// Normalizacja do obszaru mapy. Zakres liczony z PERCENTYLI (2-98%), żeby
|
|
// pojedyncze studnie ze skrajnymi współrzędnymi nie rozciągały skali i nie
|
|
// zwijały reszty w jeden punkt. Pozycje przycięte (clamp) do obszaru.
|
|
$minLat = $this->percentile($wells->pluck('lat')->all(), 2);
|
|
$maxLat = $this->percentile($wells->pluck('lat')->all(), 98);
|
|
$minLon = $this->percentile($wells->pluck('lon')->all(), 2);
|
|
$maxLon = $this->percentile($wells->pluck('lon')->all(), 98);
|
|
$latRange = max(1e-6, $maxLat - $minLat);
|
|
$lonRange = max(1e-6, $maxLon - $minLon);
|
|
$span = 100 - 2 * self::PAD;
|
|
$clamp = fn ($v) => max(self::PAD, min(100 - self::PAD, $v));
|
|
|
|
$points = $wells->map(function ($r) use ($minLat, $maxLat, $minLon, $lonRange, $latRange, $span, $clamp, $onoff) {
|
|
return (object) [
|
|
'drs_id' => $r->drs_id,
|
|
'name' => $r->name,
|
|
// X = długość (wschód), Y = szerokość (północ, odwrócona - północ u góry).
|
|
'left' => round($clamp(self::PAD + (($r->lon - $minLon) / $lonRange) * $span), 3),
|
|
'top' => round($clamp(self::PAD + (($maxLat - $r->lat) / $latRange) * $span), 3),
|
|
'on' => ($onoff[$r->drs_id] ?? null) === 'ON',
|
|
];
|
|
});
|
|
|
|
return view('dashboard', [
|
|
'points' => $points,
|
|
'onCount' => $points->where('on', true)->count(),
|
|
'offCount' => $points->where('on', false)->count(),
|
|
]);
|
|
}
|
|
|
|
/** Percentyl p (0-100) z tablicy liczb (interpolacja liniowa). */
|
|
private function percentile(array $values, float $p): float
|
|
{
|
|
if (empty($values)) {
|
|
return 0.0;
|
|
}
|
|
sort($values);
|
|
$i = ($p / 100) * (count($values) - 1);
|
|
$lo = (int) floor($i);
|
|
$hi = (int) ceil($i);
|
|
|
|
return $lo === $hi ? (float) $values[$lo] : $values[$lo] + ($values[$hi] - $values[$lo]) * ($i - $lo);
|
|
}
|
|
|
|
/** Ostatni stan ON/OFF (507) dla zbioru DRS_ID - jednym zapytaniem. */
|
|
private function onOff(array $ids): \Illuminate\Support\Collection
|
|
{
|
|
if (empty($ids)) {
|
|
return collect();
|
|
}
|
|
|
|
return DB::connection('softspm')->table('seg_dev_resources_det as d')
|
|
->joinSub(
|
|
DB::connection('softspm')->table('seg_dev_resources_det')
|
|
->select('DRD_DRS_ID', DB::raw('MAX(DRD_ID) as max_id'))
|
|
->where('DRD_RESOURCES_DETAIL', 507)
|
|
->whereIn('DRD_DRS_ID', $ids)
|
|
->groupBy('DRD_DRS_ID'),
|
|
'mx', 'mx.max_id', '=', 'd.DRD_ID'
|
|
)
|
|
->pluck('d.DRD_VALUE', 'd.DRD_DRS_ID');
|
|
}
|
|
}
|