2024-08-13 20:06:10 +08:00
|
|
|
import QtQuick
|
2024-08-14 20:01:38 +08:00
|
|
|
import QtQuick.Controls
|
2024-08-13 20:06:10 +08:00
|
|
|
import AntiClipSettings
|
|
|
|
|
|
|
|
Item {
|
|
|
|
id: root
|
2024-08-14 20:01:38 +08:00
|
|
|
property int dargWidth: 12
|
|
|
|
property color openDoorAreaColor: "green"
|
2024-08-13 20:06:10 +08:00
|
|
|
property var openDoorAreaPoints: []
|
2024-08-14 20:01:38 +08:00
|
|
|
property bool openDoorAreaEnabled: false
|
|
|
|
property var shieldedAreaPoints: []
|
|
|
|
property bool shieldedAreaEnabled: false
|
|
|
|
property color antiClipAreaColor: "blue"
|
|
|
|
property var antiClipAreaPoints: []
|
|
|
|
property bool antiClipAreaEnabled: false
|
|
|
|
property var defaultShieldedAreaPoints: [Qt.point(6, 6), Qt.point(40, 60),
|
|
|
|
Qt.point(598, 6), Qt.point(633, 60)]
|
|
|
|
Item {
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.bottom: controlBar.top
|
|
|
|
Image {
|
|
|
|
id: image
|
|
|
|
anchors.centerIn: parent
|
|
|
|
cache: false
|
|
|
|
fillMode: Image.PreserveAspectFit
|
|
|
|
source: "image://videoframe/"
|
|
|
|
property real aspectRatio: 16 / 9
|
|
|
|
width: Math.min(parent.width, parent.height * aspectRatio)
|
|
|
|
height: width / aspectRatio
|
2024-08-13 20:06:10 +08:00
|
|
|
|
2024-08-14 20:01:38 +08:00
|
|
|
Canvas {
|
|
|
|
id: canvas
|
|
|
|
anchors.fill: parent
|
|
|
|
onPaint: {
|
|
|
|
var ctx = canvas.getContext("2d")
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
|
|
|
if (openDoorAreaEnabled &&(openDoorAreaPoints.length > 0)) {
|
|
|
|
ctx.strokeStyle = openDoorAreaColor
|
|
|
|
ctx.lineWidth = 2
|
2024-08-13 20:06:10 +08:00
|
|
|
|
2024-08-14 20:01:38 +08:00
|
|
|
ctx.beginPath()
|
|
|
|
let point = scaledPoint(openDoorAreaPoints[0],
|
|
|
|
width, height)
|
|
|
|
ctx.moveTo(point.x, point.y)
|
|
|
|
for (var i = 1; i < openDoorAreaPoints.length; i++) {
|
|
|
|
point = scaledPoint(openDoorAreaPoints[i],
|
|
|
|
width, height)
|
|
|
|
ctx.lineTo(point.x, point.y)
|
|
|
|
}
|
|
|
|
ctx.closePath()
|
|
|
|
ctx.stroke()
|
|
|
|
}
|
|
|
|
if (antiClipAreaEnabled && (antiClipAreaPoints.length > 0)) {
|
|
|
|
ctx.strokeStyle = antiClipAreaColor
|
|
|
|
ctx.lineWidth = 2
|
|
|
|
|
|
|
|
ctx.beginPath()
|
|
|
|
let point = scaledPoint(antiClipAreaPoints[0],
|
|
|
|
width, height)
|
|
|
|
ctx.moveTo(point.x, point.y)
|
|
|
|
for (var i = 1; i < antiClipAreaPoints.length; i++) {
|
|
|
|
point = scaledPoint(antiClipAreaPoints[i],
|
|
|
|
width, height)
|
|
|
|
ctx.lineTo(point.x, point.y)
|
|
|
|
}
|
|
|
|
ctx.closePath()
|
|
|
|
ctx.stroke()
|
|
|
|
}
|
|
|
|
if (shieldedAreaEnabled &&(shieldedAreaPoints.length > 0)) {
|
|
|
|
ctx.strokeStyle = "green"
|
|
|
|
let point0 = scaledPoint(shieldedAreaPoints[0],
|
|
|
|
width, height)
|
|
|
|
let point1 = scaledPoint(shieldedAreaPoints[1],
|
|
|
|
width, height)
|
|
|
|
let point2 = scaledPoint(shieldedAreaPoints[2],
|
|
|
|
width, height)
|
|
|
|
let point3 = scaledPoint(shieldedAreaPoints[3],
|
|
|
|
width, height)
|
|
|
|
ctx.strokeRect(point0.x, point0.y, point1.x - point0.x,
|
|
|
|
point1.y - point0.y)
|
|
|
|
ctx.strokeRect(point2.x, point2.y, point3.x - point2.x,
|
|
|
|
point3.y - point2.y)
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-14 20:01:38 +08:00
|
|
|
Repeater {
|
|
|
|
id: repeater
|
|
|
|
visible: openDoorAreaEnabled
|
|
|
|
model: openDoorAreaPoints
|
|
|
|
delegate: Rectangle {
|
|
|
|
width: dargWidth
|
|
|
|
height: dargWidth
|
|
|
|
visible: openDoorAreaEnabled
|
|
|
|
color: openDoorAreaColor
|
|
|
|
x: scaledPoint(modelData, canvas.width,
|
|
|
|
canvas.height).x - width / 2
|
|
|
|
y: scaledPoint(modelData, canvas.width,
|
|
|
|
canvas.height).y - height / 2
|
|
|
|
}
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
|
2024-08-14 20:01:38 +08:00
|
|
|
Repeater {
|
|
|
|
id: shieldedAreaRepeater
|
|
|
|
model: shieldedAreaPoints
|
|
|
|
visible: shieldedAreaEnabled
|
|
|
|
delegate: Rectangle {
|
|
|
|
width: dargWidth
|
|
|
|
height: dargWidth
|
|
|
|
visible: shieldedAreaEnabled
|
|
|
|
color: "green"
|
|
|
|
x: scaledPoint(modelData, canvas.width,
|
|
|
|
canvas.height).x - width / 2
|
|
|
|
y: scaledPoint(modelData, canvas.width,
|
|
|
|
canvas.height).y - height / 2
|
|
|
|
}
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
2024-08-14 20:01:38 +08:00
|
|
|
|
|
|
|
Repeater {
|
|
|
|
id: antiAreaRepeater
|
|
|
|
visible: antiClipAreaEnabled
|
|
|
|
model: antiClipAreaPoints
|
|
|
|
delegate: Rectangle {
|
|
|
|
visible: antiClipAreaEnabled
|
|
|
|
width: dargWidth
|
|
|
|
height: dargWidth
|
|
|
|
color: antiClipAreaColor
|
|
|
|
x: scaledPoint(modelData, canvas.width,
|
|
|
|
canvas.height).x - width / 2
|
|
|
|
y: scaledPoint(modelData, canvas.width,
|
|
|
|
canvas.height).y - height / 2
|
|
|
|
}
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
2024-08-14 20:01:38 +08:00
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
|
|
|
property int draggedOpenDoorAreaPointIndex: -1
|
|
|
|
property int draggedShieldedAreaPointIndex: -1
|
|
|
|
property int draggedAntiAreaPointIndex: -1
|
|
|
|
onPressed: mouse => {
|
|
|
|
if(openDoorAreaEnabled){
|
|
|
|
for (var i = 0; i < openDoorAreaPoints.length; i++) {
|
|
|
|
let point = scaledPoint(
|
|
|
|
openDoorAreaPoints[i], canvas.width,
|
|
|
|
canvas.height)
|
|
|
|
if (isInside(mouse.x, mouse.y, point)) {
|
|
|
|
draggedOpenDoorAreaPointIndex = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (draggedOpenDoorAreaPointIndex >= 0)
|
|
|
|
return
|
|
|
|
if(shieldedAreaEnabled){
|
|
|
|
for (let i = 0; i < shieldedAreaPoints.length; i++) {
|
|
|
|
let point = scaledPoint(
|
|
|
|
shieldedAreaPoints[i], canvas.width,
|
|
|
|
canvas.height)
|
|
|
|
if (isInside(mouse.x, mouse.y, point)) {
|
|
|
|
draggedShieldedAreaPointIndex = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (draggedShieldedAreaPointIndex >= 0)
|
|
|
|
return
|
|
|
|
if(antiClipAreaEnabled){
|
|
|
|
for (let i = 0; i < antiClipAreaPoints.length; i++) {
|
|
|
|
let point = scaledPoint(
|
|
|
|
antiClipAreaPoints[i], canvas.width,
|
|
|
|
canvas.height)
|
|
|
|
if (isInside(mouse.x, mouse.y, point)) {
|
|
|
|
draggedAntiAreaPointIndex = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
onReleased: {
|
|
|
|
if (draggedOpenDoorAreaPointIndex >= 0) {
|
|
|
|
App.updateOpenDoorAreaPoints(openDoorAreaPoints)
|
|
|
|
draggedOpenDoorAreaPointIndex = -1
|
|
|
|
}
|
|
|
|
if (draggedShieldedAreaPointIndex >= 0) {
|
|
|
|
App.updateShieldedAreaPoints(shieldedAreaPoints)
|
|
|
|
draggedShieldedAreaPointIndex = -1
|
|
|
|
}
|
|
|
|
if (draggedAntiAreaPointIndex >= 0) {
|
|
|
|
App.updateAntiClipAreaPoints(antiClipAreaPoints)
|
|
|
|
draggedAntiAreaPointIndex = -1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
onPositionChanged: mouse => {
|
|
|
|
if ((mouse.x < 0) || (mouse.x > canvas.width) || (mouse.y < 0) || (mouse.y > canvas.height)) return
|
|
|
|
if (draggedOpenDoorAreaPointIndex >= 0) {
|
|
|
|
openDoorAreaPoints[draggedOpenDoorAreaPointIndex]
|
|
|
|
= standardPoint(Qt.point(mouse.x, mouse.y), canvas.width, canvas.height)
|
|
|
|
canvas.requestPaint()
|
|
|
|
repeater.model = openDoorAreaPoints
|
|
|
|
} else if (draggedShieldedAreaPointIndex >= 0) {
|
|
|
|
shieldedAreaPoints[draggedShieldedAreaPointIndex]
|
|
|
|
= standardPoint(Qt.point(mouse.x,
|
|
|
|
mouse.y),
|
|
|
|
canvas.width,
|
|
|
|
canvas.height)
|
|
|
|
canvas.requestPaint()
|
|
|
|
shieldedAreaRepeater.model = shieldedAreaPoints
|
|
|
|
} else if (draggedAntiAreaPointIndex >= 0) {
|
|
|
|
antiClipAreaPoints[draggedAntiAreaPointIndex]
|
|
|
|
= standardPoint(Qt.point(mouse.x,
|
|
|
|
mouse.y),
|
|
|
|
canvas.width,
|
|
|
|
canvas.height)
|
|
|
|
canvas.requestPaint()
|
|
|
|
antiAreaRepeater.model = antiClipAreaPoints
|
|
|
|
}
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
|
2024-08-14 20:01:38 +08:00
|
|
|
function isInside(x, y, point) {
|
|
|
|
let edge = dargWidth / 2
|
|
|
|
return x >= point.x - edge && x <= point.x + edge
|
|
|
|
&& y >= point.y - edge && y <= point.y + edge
|
|
|
|
}
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-08-14 20:01:38 +08:00
|
|
|
Row {
|
|
|
|
id: controlBar
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
Switch {
|
|
|
|
text: "开门区域"
|
|
|
|
checked: openDoorAreaEnabled
|
|
|
|
onToggled: App.currentOpenDoorAreaEnabled = checked
|
|
|
|
}
|
|
|
|
Switch {
|
|
|
|
text: "防夹区域"
|
|
|
|
checked: antiClipAreaEnabled
|
|
|
|
onToggled: App.currentAntiClipAreaEnabled = checked
|
|
|
|
}
|
|
|
|
Switch {
|
|
|
|
text: "屏蔽区域"
|
|
|
|
checked: shieldedAreaEnabled
|
|
|
|
onToggled: App.currentShieldedAreaEnabled = checked
|
|
|
|
}
|
|
|
|
}
|
2024-08-13 20:06:10 +08:00
|
|
|
// 转换为显示画点
|
|
|
|
function scaledPoint(point, width, height) {
|
|
|
|
let x = point.x * width / 640
|
|
|
|
let y = point.y * height / 360
|
|
|
|
return Qt.point(x, y)
|
|
|
|
}
|
|
|
|
|
2024-08-14 20:01:38 +08:00
|
|
|
// 转换为设备画点(640x360)
|
2024-08-13 20:06:10 +08:00
|
|
|
function standardPoint(point, width, height) {
|
|
|
|
let x = point.x * 640 / width
|
|
|
|
let y = point.y * 360 / height
|
|
|
|
return Qt.point(x, y)
|
|
|
|
}
|
|
|
|
|
|
|
|
Connections {
|
|
|
|
target: App
|
|
|
|
function onNewVideoFrame() {
|
|
|
|
image.source = ""
|
|
|
|
image.source = "image://videoframe/"
|
|
|
|
}
|
|
|
|
function onCurrentOpenDoorAreaPointsChanged() {
|
|
|
|
canvas.requestPaint()
|
|
|
|
}
|
2024-08-14 20:01:38 +08:00
|
|
|
function onCurrentShieldedAreaPointsChanged() {
|
|
|
|
canvas.requestPaint()
|
|
|
|
}
|
|
|
|
function onCurrentAntiClipAreaPointsChanged() {
|
|
|
|
canvas.requestPaint()
|
|
|
|
}
|
|
|
|
function onCurrentOpenDoorAreaEnabledChanged(){
|
|
|
|
canvas.requestPaint()
|
|
|
|
}
|
|
|
|
function onCurrentShieldedAreaEnabledChanged(){
|
|
|
|
canvas.requestPaint()
|
|
|
|
}
|
|
|
|
function onCurrentAntiClipAreaEnabledChanged(){
|
|
|
|
canvas.requestPaint()
|
|
|
|
}
|
2024-08-13 20:06:10 +08:00
|
|
|
}
|
|
|
|
}
|