Repository navigation
Expand file tree
/
Copy pathmonitor.py
More file actions
134 lines (104 loc) · 4.51 KB
/
Copy pathmonitor.py
File metadata and controls
134 lines (104 loc) · 4.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python3
"""
Monitor Module
-------------
Handles the conversion between pixel coordinates and physical world coordinates
for individual monitors, providing a clean abstraction for monitor operations.
"""
import logging
class Monitor:
"""Represents a physical monitor with coordinate conversion methods."""
def __init__(self, config_data, logger=None):
"""
Initialize a monitor from configuration data.
Args:
config_data: Dictionary with monitor configuration (from config.json)
logger: Optional logger instance
"""
self.logger = logger or logging.getLogger(__name__)
self.name = config_data["name"]
# Physical dimensions (mm)
self.width_mm = float(config_data["width_mm"])
self.height_mm = float(config_data["height_mm"])
# Pixel dimensions
self.width_px = int(config_data["width"])
self.height_px = int(config_data["height"])
self.x_offset_px = int(config_data["x_offset"])
self.y_offset_px = int(config_data["y_offset"])
# Calculate pixels per mm (PPI factor)
self.ppi_x = self.width_px / self.width_mm
self.ppi_y = self.height_px / self.height_mm
self.logger.info(f"Monitor {self.name}: {self.width_mm}mm × {self.height_mm}mm, "
f"{self.width_px}px × {self.height_px}px")
self.logger.info(f"Monitor {self.name} PPI: {self.ppi_x:.2f}px/mm × {self.ppi_y:.2f}px/mm")
def pixels_to_world(self, x_px, y_px):
"""
Convert absolute screen pixel coordinates to physical world coordinates (mm).
Args:
x_px: Absolute X pixel coordinate
y_px: Absolute Y pixel coordinate
Returns:
Tuple (x_mm, y_mm) with physical coordinates in mm
"""
# Convert from absolute to monitor-relative pixel coordinates
rel_x_px = x_px - self.x_offset_px
rel_y_px = y_px - self.y_offset_px
# Check if point is actually on this monitor
if not (0 <= rel_x_px <= self.width_px and 0 <= rel_y_px <= self.height_px):
self.logger.warning(f"Pixel coordinates ({x_px}, {y_px}) are outside monitor {self.name}")
# Convert to physical coordinates
x_mm = rel_x_px / self.ppi_x
y_mm = rel_y_px / self.ppi_y
return (x_mm, y_mm)
def world_to_pixels(self, x_mm, y_mm):
"""
Convert physical world coordinates (mm) to absolute screen pixel coordinates.
Args:
x_mm: X coordinate in mm (relative to monitor's left edge)
y_mm: Y coordinate in mm (relative to monitor's top edge)
Returns:
Tuple (x_px, y_px) with absolute pixel coordinates
"""
# Convert mm to pixels using PPI
rel_x_px = x_mm * self.ppi_x
rel_y_px = y_mm * self.ppi_y
# Convert to absolute screen coordinates
x_px = self.x_offset_px + rel_x_px
y_px = self.y_offset_px + rel_y_px
return (int(round(x_px)), int(round(y_px)))
def is_point_on_monitor(self, x_px, y_px):
"""
Check if an absolute pixel coordinate is on this monitor.
Args:
x_px: Absolute X pixel coordinate
y_px: Absolute Y pixel coordinate
Returns:
True if point is within this monitor's bounds, False otherwise
"""
rel_x_px = x_px - self.x_offset_px
rel_y_px = y_px - self.y_offset_px
return (0 <= rel_x_px <= self.width_px and 0 <= rel_y_px <= self.height_px)
def get_physical_extents(self):
"""
Get the physical extents of this monitor.
Returns:
Dictionary with width_mm, height_mm
"""
return {
"width_mm": self.width_mm,
"height_mm": self.height_mm
}
def get_pixel_extents(self):
"""
Get the pixel extents of this monitor.
Returns:
Dictionary with width_px, height_px, x_offset_px, y_offset_px
"""
return {
"width_px": self.width_px,
"height_px": self.height_px,
"x_offset_px": self.x_offset_px,
"y_offset_px": self.y_offset_px
}
def __str__(self):
return f"Monitor({self.name}, {self.width_mm}mm × {self.height_mm}mm, offset: ({self.x_offset_px}, {self.y_offset_px})px)"