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'); } }