Files
zoneminder/web/includes/Zone.php
Isaac Connor a90a3bccea fix: auto-detect and convert pixel zone coordinates to percentages in web layer
When zone coordinates are stored as pixel values (e.g. from a missed DB
migration), the web layer now detects values > 100 and converts them to
percentages using the monitor's dimensions, mirroring the existing C++
detection logic in zm_zone.cpp. This prevents limitPoints() from clamping
pixel values to 0-100 and zones rendering incorrectly in SVG overlays.

- Add convertPixelPointsToPercent() helper in functions.php
- Call conversion before limitPoints() in zone.php and zones.php
- Update Zone::svg_polygon() to accept monitor dimensions and convert
- Pass ViewWidth/ViewHeight to svg_polygon() from Monitor::getStreamHTML()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 17:49:14 -05:00

86 lines
2.5 KiB
PHP

<?php
namespace ZM;
require_once('database.php');
require_once('Object.php');
require_once('Monitor.php');
class Zone extends ZM_Object {
protected static $table = 'Zones';
protected $defaults = array(
'Id' => null,
'MonitorId' => null,
'Name' => '',
'Type' => 'Active',
'Units' => 'Percent',
'NumCoords' => '4',
'Coords' => '',
'Area' => '0',
'AlarmRGB' => 0xff0000,
'CheckMethod' => 'Blobs',
'MinPixelThreshold' => 25,
'MaxPixelThreshold' => null,
'MinAlarmPixels' => null,
'MaxAlarmPixels' => null,
'FilterX' => 3,
'FilterY' => 3,
'MinFilterPixels' => null,
'MaxFilterPixels' => null,
'MinBlobPixels' => null,
'MaxBlobPixels' => null,
'MinBlobs' => 1,
'MaxBlobs' => null,
'OverloadFrames' => 0,
'ExtendAlarmFrames' => 0,
);
public static function find( $parameters = array(), $options = array() ) {
return ZM_Object::_find(self::class, $parameters, $options);
}
public static function find_one( $parameters = array(), $options = array() ) {
return ZM_Object::_find_one(self::class, $parameters, $options);
}
public function Monitor() {
if (isset($this->{'MonitorId'})) {
$Monitor = Monitor::find_one(array('Id'=>$this->{'MonitorId'}));
if ( $Monitor )
return $Monitor;
}
return new Monitor();
}
public function Points() {
return coordsToPoints($this->Coords());
}
public function AreaCoords() {
return preg_replace('/\s+/', ',', $this->Coords());
}
public function svg_polygon($width=0, $height=0) {
$areaCoords = $this->AreaCoords();
if ($width && $height) {
$points = coordsToPoints($this->Coords());
$isPixel = false;
foreach ($points as $point) {
if ($point['x'] > 100 || $point['y'] > 100) {
$isPixel = true;
break;
}
}
if ($isPixel) {
foreach ($points as &$point) {
$point['x'] = round($point['x'] / $width * 100, 2);
$point['y'] = round($point['y'] / $height * 100, 2);
}
unset($point);
$areaCoords = preg_replace('/\s+/', ',', pointsToCoords($points));
}
}
return '<polygon points="'.$areaCoords.'" class="'.$this->Type().'" data-mid="'.$this->MonitorId().'" data-zid="'.$this->Id().'"><title>'.$this->Name().'</title></polygon>';
}
} # end class Zone
?>