WIP 2025-01-16 ConstructionConsent Rimo Plan

This commit is contained in:
Frank Schubert
2025-01-17 13:48:50 +01:00
parent e3f1fe07ad
commit 27cc45e23c
4 changed files with 368 additions and 8 deletions

View File

@@ -154,8 +154,24 @@
<hr />
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="name">Planskizze / Bilddatei</label>
<label class="col-lg-2 col-form-label">Planskizze / Bilddatei</label>
<div class="col-lg-10">
<label for="plan_adb_hausnummer_id">Plan aus Rimo holen</label>
<select class="form-control" name="plan_adb_hausnummer_id" id="plan_adb_hausnummer_id">
<?php if(isset($item) && $item->plan_adb_hausnummer_id): ?>
<option value="<?=$item->plan_adb_hausnummer_id?>" selected="selected"><?=$item->plan_adb_hausnummer->street->name?> <?=$item->plan_adb_hausnummer->hausnummer?>, <?=$item->plan_adb_hausnummer->street->gemeinde->name?></option>
<?php endif; ?>
</select>
Vorschau:
<div class="card">
<div class="card-body" id="rimo-plan-container">
<img id="plan_preview" style="max-width: 1200px;" />
</div>
</div>
<label>Oder Plan hochladen</label>
<input type="file" class="form-control" name="consent_plan_image" id="consent_plan_image" />
</div>
</div>
@@ -222,11 +238,51 @@
placeholder: "Suche nach Straße",
allowClear: true
});
$('#adb_strasse_id').on('select2:close', function(e) {
if(!$('#adb_strasse_id').val()) {
$('#new-address-toggle').show();
}
$('#plan_adb_hausnummer_id').select2({
ajax: {
url: '<?=self::getUrl("ConstructionConsent", "api")?>',
data: (params) => {
return {
q: params.term,
do: "findAddress",
project_id: $("#constructionconsentproject_id :selected").val()
}
},
delay: 250,
dataType: 'json'
},
minimumInputLength: 2,
placeholder: "Suche nach Adresse",
allowClear: true
});
$('#plan_adb_hausnummer_id').change( async () => {
if(!$("#plan_adb_hausnummer_id").val()) return;
var building_id = $('#plan_adb_hausnummer_id').val();
// get plan image preview
try {
var response = await fetch('<?=self::getUrl("ConstructionConsent", "Api", ["do" => "getRimoPlanPreview"])?>&building_id=' + building_id);
if (!response.ok) {
return false;
}
var resp_json = await response.json();
var plan_data = resp_json.result;
var img_mimetype = plan_data.image_mimetype;
var img_base64 = plan_data.image_base64;
$("#plan_preview").attr("src" ,"data:" + img_mimetype + ";base64," + img_base64);
} catch (error) {
console.log("Exception fetching plan preview:");
console.log(error);
return false;
}
});
$("#constructionconsentproject_id").change(() => {
$("#adb_strasse_id").val("").change();

View File

@@ -281,6 +281,15 @@ class ConstructionConsentController extends mfBaseController {
case "findStreet":
$return = $this->findStreetApi();
break;
case "findAddress":
$return = $this->findAddressApi();
break;
case "getRimoPlanPreview":
$return = $this->getRimoPlanPreviewApi();
break;
case "saveRimoPlanPreview":
$return = $this->saveRimoPlanPreviewApi();
break;
default:
$this->log->warn(__METHOD__ . ": Called API function '$do' does not exist");
$return = false;
@@ -425,4 +434,221 @@ class ConstructionConsentController extends mfBaseController {
exit;
}
private function findAddressApi() {
$addresses = [];
$search = trim($this->request->q);
$project_id = $this->request->project_id;
$include_gst = $this->request->include_gst ? $this->request->include_gst : false;
$scluster_ids = [];
if($project_id) {
$project = new ConstructionConsentProject($project_id);
if(!$project->id) {
header("Content-Type: application/json");
echo json_encode(["results" => []]);
exit;
}
foreach($project->adb_networks as $network) {
$scluster_ids[] = $network->id;
}
} else {
// get all salesclusters
foreach(ADBNetzgebietModel::getAll() as $network) {
$scluster_ids[] = $network->id;
}
}
$results = [];
$search_parts = explode(" ", $search);
$ort_search = $strasse_search = $plz_search = $hausnummer_search = $gst_search = [];
foreach($search_parts as $p) {
$p = $this->db->escape(trim($p));
if(!$p) continue;
$ort_search[] = "ortschaft like '$p%'";
$strasse_search[] = "strasse like '$p%'";
$plz_search[] = "plz like '%$p%'";
$hausnummer_search[] = "hausnummer like '%$p%'";
$gst_search[] = "grund_nr like '%$p%'";
}
$where = "1=1";
if(count($scluster_ids)) {
$where .= " AND netzgebiet_id IN (".implode(', ',$scluster_ids).")";
}
if($include_gst) {
$sql = "SELECT * FROM view_hausnummer WHERE $where AND ((".implode(" OR ", $ort_search).") OR (".implode(" OR ", $strasse_search).") OR (".implode(" OR ", $plz_search).") OR (".implode(" OR ", $hausnummer_search).") OR (".implode(" OR ", $gst_search).") ) ORDER BY strasse, LENGTH(hausnummer), hausnummer";
} else {
$sql = "SELECT * FROM view_hausnummer WHERE $where AND ((".implode(" OR ", $ort_search).") OR (".implode(" OR ", $strasse_search).") OR (".implode(" OR ", $plz_search).") OR (".implode(" OR ", $hausnummer_search).")) ORDER BY strasse, LENGTH(hausnummer), hausnummer";
}
$this->log->debug($sql);
$adb = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
$res = $adb->query($sql);
$this->log->debug("done");
if(!$adb->num_rows($res)) {
header("Content-Type: application/json");
echo json_encode(["results" => []]);
exit;
}
while($data = $adb->fetch_object($res)) {
$address_string = $data->plz." ".$data->ortschaft.", ".$data->strasse." ".$data->hausnummer;
if($include_gst) {
$address_string .= " | GST: ".$data->grund_nr;
}
$sort_key = $data->plz." ".$data->ortschaft." ".$data->strasse;
$address = [];
$address['id'] = $data->hausnummer_id;
$address["text"] = $address_string;
$address['sort_key'] = $sort_key;
$addresses[] = $address;
}
// sort results by most occurences of search strings
$sort = [];
foreach($addresses as $key => $address) {
$includes_int = false;
$count = 0;
foreach($search_parts as $p) {
$p = $this->db->escape(trim($p));
if(!$p) continue;
if(is_numeric(($p))) {
$includes_int = true;
if(substr_count(strtolower($address['text']), strtolower($p))) {
$count++;
}
} else {
$count += substr_count(strtolower($address['text']), strtolower($p));
}
}
unset($address['sort_key']);
//echo $address['text']." $p $count<br />\n";
if($includes_int && (($count + 1) - count($search_parts) ) < 1) {
continue;
}
if(!array_key_exists($count, $sort)) {
$sort[$count] = [];
}
$sort[$count][] = $address;
}
ksort($sort, SORT_NUMERIC);
$sort = array_reverse($sort, true);
//var_dump($sort);exit;
foreach($sort as $res) {
foreach($res as $a) {
$results[] = $a;
}
}
header("Content-Type: application/json");
echo json_encode(["results" => $results]);
exit;
}
private function getRimoPlanPreviewApi() {
$adb_hausnummer_id = $this->request->building_id;
$hausnummer = new ADBHausnummer($adb_hausnummer_id);
if(!$hausnummer->id) {
return false;
}
$filename = "consent_plan_map_h{$adb_hausnummer_id}";
$bpi_file = PreorderFile::getFirst(["preorder_id" => $this->id, "filename" => $filename]);
if($bpi_file) {
return $bpi_file;
}
// get new Borderpoint Image from Mapbox API
$params = [
"pin" => null,
"gps_lat" => $hausnummer->gps_lat,
"gps_long" => $hausnummer->gps_long,
"zoom" => 19,
"size_x" => 640,
"size_y" => 640,
"style" => "satellite-streets-v12",
"paths" => "",
"access_token" => TT_MAPBOX_TILE_API_TOKEN
];
if($hausnummer->trenches) {
$trenches = json_decode($hausnummer->trenches);
$params["paths"] = [
"line_width" => 5,
"line_color" => "ff0000",
"line_opacity" => 1,
"line_fill_color" => "ff0000",
"line_fill_opacity" => 1,
"coords" => $trenches
];
}
$image_content = Mapbox_StaticImageApi::getImageFileContent($params);
if(!$image_content) {
return false;
}
$fs_filename = "$filename.jpg";
if(!file_put_contents(MFUPLOAD_FILE_SAVE_PATH."/".TT_CONSTRUCTIONCONSENT_FILE_UPLOAD_SUBFOLDER."/$fs_filename", $image_content)) {
$this->log->error(__METHOD__.": Error saving Borderpoint Static Map Image File");
return false;
}
$file = FileModel::create([
"name" => "consent_plan_map",
"description" => $adb_hausnummer_id,
"filename" => "$filename.jpg",
"orig_filename" => "$filename.jpg",
"store_filename" => $fs_filename,
"subfolder" => TT_CONSTRUCTIONCONSENT_FILE_UPLOAD_SUBFOLDER,
]);
if(!$file->save()) {
$this->log->error(__METHOD__.": Error saving File Object");
return false;
}
$file->mimetype = $file->getMimetype();
$file->save();
return ["image_mimetype" => $file->mimetype, "image_base64" => base64_encode($image_content)];
/*$pf = PreorderFile::create([
"preorder_id" => $this->id,
"file_id" => $file->id,
"filename" => $filename
]);
if(!$pf->save()) {
$this->log->error(__METHOD__.": Error saving PreorderFile Object");
return false;
}*/
//return $pf;
}
private function saveRimoPlanPreviewApi() {
$adb_hausnummer_id = $this->request->building_id;
$consent_id = $this->request->constructionconsent_id;
}
}

View File

@@ -11,6 +11,7 @@ class Mapbox_StaticImageApi {
$size_y = $params["size_y"];
$style = $params["style"];
$pin = $params["pin"];
$paths = $params["paths"];
$pin_part = "";
@@ -23,12 +24,50 @@ class Mapbox_StaticImageApi {
$pin_color = $pin["color"];
$pin_icon = $pin["icon"];
$pin_part .= "/pin-$pin_size";
$pin_part .= "pin-$pin_size";
if($pin_icon) $pin_part .= "-$pin_icon";
$pin_part .= "+$pin_color($pin_gps_long,$pin_gps_lat)";
}
$url .= "$pin_part/$gps_long,$gps_lat,$zoom/{$size_x}x{$size_y}?access_token=$access_token";
$path_parts = [];
if(is_array($paths) && count($paths)) {
$path_stroke_width = $paths["line_width"];
$path_stroke_color = $paths["line_color"];
$path_stroke_opacity = $paths["line_opacity"];
$path_fill_color = $paths["line_fill_color"];
$path_fill_opacity = $paths["line_fill_opacity"];
foreach($paths["coords"] as $path) {
if(!is_array($path)) {
mfLoghandler::singleton()->debug("path not array: ".print_r($path, true));
continue;
}
$path_enc_polyline = self::encodeCoordArrayToPolyline($path);
if(!$path_enc_polyline) continue;
$path_parts[] = "path-$path_stroke_width+$path_stroke_color-$path_stroke_opacity+$path_fill_color-$path_fill_opacity($path_enc_polyline)";
}
}
// build url
$url_opt_parts = [];
if($pin_part) $url_opt_parts[] = $pin_part;
if(count($path_parts)) {
foreach($path_parts as $path_part) {
$url_opt_parts[] = $path_part;
}
}
if(is_array($url_opt_parts)) {
$url .= "/".implode(",", $url_opt_parts);
}
$url .= "/auto/{$size_x}x{$size_y}?access_token=$access_token";
mfLoghandler::singleton()->debug($url);
//exit;
$ctx_opts = [
'http' => [
@@ -47,4 +86,43 @@ class Mapbox_StaticImageApi {
return $response;
}
public static function encodeCoordArrayToPolyline($coords, $precision = 5) {
//if(!is_array($coords)) return false;
$points = [];
array_walk_recursive(
$coords,
function ($current) use (&$points) {
$points[] = $current;
}
);
mfLoghandler::singleton()->debug(__METHOD__.": flattened path: ".print_r($points, true));
$encodedString = '';
$index = 0;
$previous = array(0,0);
foreach ( $points as $number ) {
$number = (float)($number);
$number = (int)round($number * pow(10, $precision));
$diff = $number - $previous[$index % 2];
$previous[$index % 2] = $number;
$number = $diff;
$index++;
$number = ($number < 0) ? ~($number << 1) : ($number << 1);
$chunk = '';
while ( $number >= 0x20 ) {
$chunk .= chr((0x20 | ($number & 0x1f)) + 63);
$number >>= 5;
}
$chunk .= chr($number + 63);
$encodedString .= $chunk;
}
mfLoghandler::singleton()->debug(__METHOD__.": encoded polyline: $encodedString");
return str_replace("?", "%3f", $encodedString);
}
}

View File

@@ -680,7 +680,7 @@ foreach ($clusters as $cluster_data) {
if($wo_home_external_id) {
$wo_home = \ADBWohneinheitModel::getFirst(["extref" => $wo_home_external_id]);
if($wo_home != $wo->adb_wohneinheit_id) {
$addressErrors[] = "Wohneinheit für Workorder ".$wo->name." hat sich geändert von ".$wo->adb_wohneinheit_id." auf ".$wo_home->extref." (aber wurde nicht im Tool übernommen)";
$addressErrors[] = "Wohneinheit für Workorder ".$wo->rimo_name." hat sich geändert von ".$wo->adb_wohneinheit_id." auf ".$wo_home->extref." (aber wurde nicht im Tool übernommen)";
}
} else {
$addressErrors[] = "Wohneinheit für Workorder ".$wo->name." ist jetzt leer";