phg-vis 1.3.2__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- phg/__init__.py +113 -42
- phg/ai_bridge.py +174 -0
- phg/gcu_api.py +709 -0
- phg/pipe_string_phg.py +144 -116
- phg/shader_render.py +26 -12
- phg/visphg.py +79 -55
- phg/web_three.py +164 -0
- {phg_vis-1.3.2.dist-info → phg_vis-1.4.0.dist-info}/METADATA +56 -1
- {phg_vis-1.3.2.dist-info → phg_vis-1.4.0.dist-info}/RECORD +12 -9
- {phg_vis-1.3.2.dist-info → phg_vis-1.4.0.dist-info}/LICENSE +0 -0
- {phg_vis-1.3.2.dist-info → phg_vis-1.4.0.dist-info}/WHEEL +0 -0
- {phg_vis-1.3.2.dist-info → phg_vis-1.4.0.dist-info}/top_level.txt +0 -0
phg/pipe_string_phg.py
CHANGED
|
@@ -6,18 +6,27 @@ This module provides functionality to convert pipe strings into PHG (Python Grap
|
|
|
6
6
|
Supports both world coordinate system and local coordinate system pipe descriptions.
|
|
7
7
|
|
|
8
8
|
Main Features:
|
|
9
|
-
- world_pipe_to_phg: World coordinate system pipe conversion
|
|
10
9
|
- local_pipe_to_phg: Local coordinate system pipe conversion
|
|
11
|
-
- world_pipestr_vis: Direct visualization for world coordinate pipes
|
|
10
|
+
- world_pipestr_vis: Direct visualization for world coordinate pipes (converts to local first)
|
|
12
11
|
- local_pipestr_vis: Direct visualization for local coordinate pipes
|
|
12
|
+
- multiple_pipes_vis: Advanced visualization for multiple pipes
|
|
13
13
|
|
|
14
14
|
Pipe String Format:
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
15
|
+
World Coordinate System:
|
|
16
|
+
- N: North (World X+)
|
|
17
|
+
- S: South (World X-)
|
|
18
|
+
- E: East (World Z+)
|
|
19
|
+
- W: West (World Z-)
|
|
20
|
+
- U: Up (World Y+)
|
|
21
|
+
- D: Down (World Y-)
|
|
22
|
+
|
|
23
|
+
Local Coordinate System:
|
|
24
|
+
- F: Forward (Local Z+)
|
|
25
|
+
- B: Backward (Local Z-)
|
|
26
|
+
- R: Right (Local X+)
|
|
27
|
+
- L: Left (Local X-)
|
|
28
|
+
- U: Up (Local Y+)
|
|
29
|
+
- D: Down (Local Y-)
|
|
21
30
|
"""
|
|
22
31
|
|
|
23
32
|
import phg
|
|
@@ -27,124 +36,90 @@ from coordinate_system import vec3, quat, coord3
|
|
|
27
36
|
DEFAULT_PIPE_COLOR = (0, 55, 255)
|
|
28
37
|
DEFAULT_PIPE_RADIUS = 0.3
|
|
29
38
|
|
|
30
|
-
def
|
|
39
|
+
def world_to_local_pipe_str(world_pipe_str, start_c):
|
|
31
40
|
"""
|
|
32
|
-
Convert world coordinate system pipe string to
|
|
41
|
+
Convert world coordinate system pipe string to local coordinate system
|
|
33
42
|
|
|
34
43
|
Parameters:
|
|
35
|
-
world_pipe_str: World coordinate pipe string (e.g., "
|
|
44
|
+
world_pipe_str: World coordinate pipe string (e.g., "NNEUD")
|
|
36
45
|
start_c: Starting coordinate system
|
|
37
|
-
pipe_color: Pipe color as (R, G, B) tuple
|
|
38
|
-
pipe_radius: Pipe radius
|
|
39
46
|
|
|
40
47
|
Returns:
|
|
41
|
-
|
|
48
|
+
Local coordinate pipe string
|
|
42
49
|
"""
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
'
|
|
50
|
-
'
|
|
51
|
-
'
|
|
51
|
+
if not world_pipe_str:
|
|
52
|
+
return ""
|
|
53
|
+
|
|
54
|
+
# World coordinate system direction definitions (cardinal directions)
|
|
55
|
+
directions = {
|
|
56
|
+
'E': vec3(1, 0, 0), # East (X+)
|
|
57
|
+
'W': vec3(-1, 0, 0), # West (X-)
|
|
58
|
+
'N': vec3(0, 0, 1), # North (Z+)
|
|
59
|
+
'S': vec3(0, 0, -1), # South (Z-)
|
|
60
|
+
'U': vec3(0, 1, 0), # Up (Y+)
|
|
61
|
+
'D': vec3(0, -1, 0) # Down (Y-)
|
|
52
62
|
}
|
|
53
63
|
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
'
|
|
60
|
-
'
|
|
61
|
-
'
|
|
62
|
-
'L': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:-90;m:x;z:-1.0;x:-1.0}}}},{{x:-1.0;ry:90;}}',
|
|
63
|
-
'U': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:90;y:1.0;z:-1}}}},{{y:1.0;rx:90;}}',
|
|
64
|
-
'D': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:-90;y:-1;z:-1}}}},{{y:-1.0;rx:-90;}}'
|
|
64
|
+
# Local coordinate system direction definitions
|
|
65
|
+
local_directions = {
|
|
66
|
+
'F': vec3(0, 0, 1), # Forward (local Z+)
|
|
67
|
+
'B': vec3(0, 0, -1), # Backward (local Z-)
|
|
68
|
+
'R': vec3(1, 0, 0), # Right (local X+)
|
|
69
|
+
'L': vec3(-1, 0, 0), # Left (local X-)
|
|
70
|
+
'U': vec3(0, 1, 0), # Up (local Y+)
|
|
71
|
+
'D': vec3(0, -1, 0) # Down (local Y-)
|
|
65
72
|
}
|
|
66
73
|
|
|
67
|
-
# Initialize
|
|
68
|
-
cur_c =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# Iterate through each character in pipe string
|
|
74
|
-
for move_char in world_pipe_str:
|
|
75
|
-
if move_char not in pipe_components:
|
|
76
|
-
print(f"Warning: Unknown pipe character '{move_char}', skipped")
|
|
74
|
+
# Initialize local coordinate system
|
|
75
|
+
cur_c = start_c.Q()
|
|
76
|
+
local_pipe_str = ""
|
|
77
|
+
|
|
78
|
+
for i, move in enumerate(world_pipe_str):
|
|
79
|
+
if move not in directions:
|
|
77
80
|
continue
|
|
78
|
-
|
|
79
|
-
# Get
|
|
80
|
-
world_dir =
|
|
81
|
-
|
|
82
|
-
# Transform world direction to current local coordinate system
|
|
83
|
-
local_dir =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
world_dir.dot(cur_c.uz) # Component in local Z-axis
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
# Find component with largest absolute value to determine main movement direction
|
|
81
|
+
|
|
82
|
+
# Get movement direction vector in world coordinate system
|
|
83
|
+
world_dir = directions[move]
|
|
84
|
+
|
|
85
|
+
# Transform world direction vector to current local coordinate system
|
|
86
|
+
local_dir = world_dir / cur_c
|
|
87
|
+
|
|
88
|
+
# Find the component with largest absolute value to determine primary movement direction
|
|
90
89
|
abs_components = [abs(local_dir.x), abs(local_dir.y), abs(local_dir.z)]
|
|
91
90
|
max_idx = abs_components.index(max(abs_components))
|
|
92
|
-
|
|
93
|
-
# Determine
|
|
91
|
+
|
|
92
|
+
# Determine movement direction based on the largest component
|
|
94
93
|
if max_idx == 0: # X-axis
|
|
95
|
-
local_move = '
|
|
94
|
+
local_move = 'L' if local_dir.x > 0 else 'R'
|
|
96
95
|
elif max_idx == 1: # Y-axis
|
|
97
96
|
local_move = 'U' if local_dir.y > 0 else 'D'
|
|
98
97
|
else: # Z-axis
|
|
99
|
-
local_move = 'F' if local_dir.z > 0 else 'B'
|
|
100
|
-
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
# Backward: move 1.0 unit along local Z-axis negative direction
|
|
110
|
-
cur_c = cur_c * coord3(vec3(0, 0, -1.0))
|
|
111
|
-
elif local_move == 'R':
|
|
112
|
-
# Right turn: rotate -90 degrees around Y-axis, then move 1.0 unit along X-axis
|
|
98
|
+
local_move = 'F' if local_dir.z > 0 else 'B' # NO BACKWARD!
|
|
99
|
+
|
|
100
|
+
# Debug first 8 characters
|
|
101
|
+
if i < 8:
|
|
102
|
+
print(f" [{i}] world:'{move}' → local_dir:({local_dir.x:.2f},{local_dir.y:.2f},{local_dir.z:.2f}) → local:'{local_move}', uz:({cur_c.uz.x:.2f},{cur_c.uz.y:.2f},{cur_c.uz.z:.2f})")
|
|
103
|
+
|
|
104
|
+
local_pipe_str += local_move
|
|
105
|
+
|
|
106
|
+
# Update local coordinate system (when turning)
|
|
107
|
+
if local_move == 'R':
|
|
113
108
|
rotation = quat(-3.1416 / 2, cur_c.uy)
|
|
114
109
|
cur_c = cur_c * rotation
|
|
115
|
-
cur_c = cur_c * coord3(vec3(1.0, 0, 0))
|
|
116
110
|
elif local_move == 'L':
|
|
117
|
-
# Left turn: rotate 90 degrees around Y-axis, then move 1.0 unit along X-axis
|
|
118
111
|
rotation = quat(3.1416 / 2, cur_c.uy)
|
|
119
112
|
cur_c = cur_c * rotation
|
|
120
|
-
cur_c = cur_c * coord3(vec3(-1.0, 0, 0))
|
|
121
113
|
elif local_move == 'U':
|
|
122
|
-
|
|
123
|
-
rotation = quat(3.1416 / 2, cur_c.ux)
|
|
114
|
+
rotation = quat(3.1416 / 2, -cur_c.ux)
|
|
124
115
|
cur_c = cur_c * rotation
|
|
125
|
-
cur_c = cur_c * coord3(vec3(0, 1.0, 0))
|
|
126
116
|
elif local_move == 'D':
|
|
127
|
-
|
|
128
|
-
rotation = quat(-3.1416 / 2, cur_c.ux)
|
|
117
|
+
rotation = quat(-3.1416 / 2, -cur_c.ux)
|
|
129
118
|
cur_c = cur_c * rotation
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
# Combine all pipe component scripts
|
|
133
|
-
inner_script = ',\n'.join(script_parts)
|
|
134
|
-
|
|
135
|
-
# Get quaternion of starting coordinate system
|
|
136
|
-
q = start_c.Q()
|
|
137
|
-
|
|
138
|
-
# Build complete PHG script
|
|
139
|
-
complete_script = f"""{{
|
|
140
|
-
{{xyz:{start_c.o.x},{start_c.o.y},{start_c.o.z};q:{q.w},{q.x},{q.y},{q.z};s:0.5;
|
|
141
|
-
<{inner_script}>}}
|
|
142
|
-
}}"""
|
|
143
|
-
|
|
144
|
-
return complete_script
|
|
145
|
-
|
|
119
|
+
|
|
120
|
+
return local_pipe_str
|
|
146
121
|
|
|
147
|
-
def local_pipe_to_phg(local_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
122
|
+
def local_pipe_to_phg(local_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
148
123
|
"""
|
|
149
124
|
Convert local coordinate system pipe string to PHG script
|
|
150
125
|
|
|
@@ -161,10 +136,10 @@ def local_pipe_to_phg(local_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pi
|
|
|
161
136
|
# Parse color
|
|
162
137
|
r, g, b = pipe_color
|
|
163
138
|
|
|
164
|
-
# Pipe component mapping
|
|
139
|
+
# Pipe component mapping
|
|
165
140
|
pipe_components = {
|
|
166
141
|
'F': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:90;z:-0.5;}};z:1.0}}',
|
|
167
|
-
'B': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:-90;z
|
|
142
|
+
'B': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:-90;z:-1.5;}};z:-1.0}}',
|
|
168
143
|
'R': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:90;x:1.0;z:-1.0}}}},{{x:1.0;ry:-90;}}',
|
|
169
144
|
'L': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:-90;m:x;z:-1.0;x:-1.0}}}},{{x:-1.0;ry:90;}}',
|
|
170
145
|
'U': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:90;y:1.0;z:-1}}}},{{y:1.0;rx:90;}}',
|
|
@@ -195,15 +170,31 @@ def local_pipe_to_phg(local_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pi
|
|
|
195
170
|
<{inner_script}>}}
|
|
196
171
|
}}"""
|
|
197
172
|
|
|
198
|
-
return complete_script
|
|
199
|
-
|
|
173
|
+
return complete_script
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def world_pipe_to_phg(world_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
177
|
+
"""
|
|
178
|
+
Convert world coordinate pipe string to PHG script.
|
|
179
|
+
|
|
180
|
+
Parameters:
|
|
181
|
+
world_pipe_str: World coordinate pipe string (e.g., "NNEUD")
|
|
182
|
+
start_c: Starting coordinate system
|
|
183
|
+
pipe_color: Pipe color as (R, G, B) tuple
|
|
184
|
+
pipe_radius: Pipe radius
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
PHG script string
|
|
188
|
+
"""
|
|
189
|
+
local_pipe_str = world_to_local_pipe_str(world_pipe_str, start_c)
|
|
190
|
+
return local_pipe_to_phg(local_pipe_str, start_c, pipe_color, pipe_radius)
|
|
200
191
|
|
|
201
192
|
def world_pipestr_vis(world_pipe_strs, start_c=None, pipe_colors=None, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
202
193
|
"""
|
|
203
194
|
Direct visualization for world coordinate pipe strings with support for multiple pipes
|
|
204
195
|
|
|
205
196
|
Parameters:
|
|
206
|
-
world_pipe_strs: World coordinate pipe string or list of strings (e.g., "
|
|
197
|
+
world_pipe_strs: World coordinate pipe string or list of strings (e.g., "NNEUD" or ["NNE", "SSU"])
|
|
207
198
|
start_c: Starting coordinate system, defaults to origin
|
|
208
199
|
pipe_colors: Single color or list of colors as (R, G, B) tuples
|
|
209
200
|
pipe_radius: Pipe radius
|
|
@@ -233,7 +224,10 @@ def world_pipestr_vis(world_pipe_strs, start_c=None, pipe_colors=None, pipe_radi
|
|
|
233
224
|
# Generate PHG scripts for all pipes
|
|
234
225
|
script_parts = []
|
|
235
226
|
for i, (pipe_str, color) in enumerate(zip(world_pipe_strs, pipe_colors)):
|
|
236
|
-
|
|
227
|
+
# Convert world coordinate pipe string to local coordinate system first
|
|
228
|
+
local_pipe_str = world_to_local_pipe_str(pipe_str, start_c)
|
|
229
|
+
# Generate PHG script from local pipe string
|
|
230
|
+
phg_script = local_pipe_to_phg(local_pipe_str, start_c, color, pipe_radius)
|
|
237
231
|
# Extract inner content between outer braces
|
|
238
232
|
inner_content = phg_script.strip()[1:-1].strip()
|
|
239
233
|
script_parts.append(inner_content)
|
|
@@ -244,13 +238,12 @@ def world_pipestr_vis(world_pipe_strs, start_c=None, pipe_colors=None, pipe_radi
|
|
|
244
238
|
# Call visualization function
|
|
245
239
|
try:
|
|
246
240
|
phg.vis(combined_script)
|
|
247
|
-
print(f"Visualizing {len(world_pipe_strs)} world coordinate pipes")
|
|
241
|
+
print(f"Visualizing {len(world_pipe_strs)} world coordinate pipes (converted to local)")
|
|
248
242
|
except ImportError:
|
|
249
243
|
print("Warning: Cannot import visualization module, returning PHG script")
|
|
250
244
|
|
|
251
245
|
return combined_script
|
|
252
246
|
|
|
253
|
-
|
|
254
247
|
def local_pipestr_vis(local_pipe_strs, start_c=None, pipe_colors=None, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
255
248
|
"""
|
|
256
249
|
Direct visualization for local coordinate pipe strings with support for multiple pipes
|
|
@@ -303,7 +296,6 @@ def local_pipestr_vis(local_pipe_strs, start_c=None, pipe_colors=None, pipe_radi
|
|
|
303
296
|
|
|
304
297
|
return combined_script
|
|
305
298
|
|
|
306
|
-
|
|
307
299
|
def multiple_pipes_vis(pipe_configs, coordinate_system='world'):
|
|
308
300
|
"""
|
|
309
301
|
Advanced visualization for multiple pipes with individual configurations
|
|
@@ -328,8 +320,11 @@ def multiple_pipes_vis(pipe_configs, coordinate_system='world'):
|
|
|
328
320
|
radius = config.get('radius', DEFAULT_PIPE_RADIUS)
|
|
329
321
|
|
|
330
322
|
if coordinate_system.lower() == 'world':
|
|
331
|
-
|
|
323
|
+
# Convert world coordinate pipe string to local coordinate system first
|
|
324
|
+
local_pipe_str = world_to_local_pipe_str(pipe_str, start_c)
|
|
325
|
+
phg_script = local_pipe_to_phg(local_pipe_str, start_c, color, radius)
|
|
332
326
|
else:
|
|
327
|
+
# Use local coordinate pipe string directly
|
|
333
328
|
phg_script = local_pipe_to_phg(pipe_str, start_c, color, radius)
|
|
334
329
|
|
|
335
330
|
# Extract inner content
|
|
@@ -348,16 +343,22 @@ def multiple_pipes_vis(pipe_configs, coordinate_system='world'):
|
|
|
348
343
|
|
|
349
344
|
return combined_script
|
|
350
345
|
|
|
351
|
-
|
|
352
346
|
# Usage Examples
|
|
353
347
|
if __name__ == "__main__":
|
|
354
348
|
# Create starting coordinate system (example)
|
|
355
349
|
start_coord = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
356
350
|
|
|
357
|
-
# Example 1:
|
|
358
|
-
example_world_pipe = "
|
|
351
|
+
# Example 1: World coordinate pipe string visualization
|
|
352
|
+
example_world_pipe = "NNEUD" # North twice, east, up, down
|
|
359
353
|
print("World Coordinate Pipe Example:")
|
|
360
|
-
|
|
354
|
+
print(f"Original world pipe: '{example_world_pipe}'")
|
|
355
|
+
|
|
356
|
+
# Convert to local coordinate system
|
|
357
|
+
local_pipe_str = world_to_local_pipe_str(example_world_pipe, start_coord)
|
|
358
|
+
print(f"Converted to local: '{local_pipe_str}'")
|
|
359
|
+
|
|
360
|
+
# Generate PHG script
|
|
361
|
+
phg_script = local_pipe_to_phg(local_pipe_str, start_coord)
|
|
361
362
|
print("Generated PHG Script:")
|
|
362
363
|
print(phg_script)
|
|
363
364
|
print()
|
|
@@ -374,7 +375,7 @@ if __name__ == "__main__":
|
|
|
374
375
|
print("Multiple Pipes Visualization Example:")
|
|
375
376
|
|
|
376
377
|
# Multiple world coordinate pipes with different colors
|
|
377
|
-
world_pipes = ["
|
|
378
|
+
world_pipes = ["NNE", "SSU", "EEW"]
|
|
378
379
|
world_colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] # Red, Green, Blue
|
|
379
380
|
world_pipestr_vis(world_pipes, start_coord, world_colors)
|
|
380
381
|
print()
|
|
@@ -389,23 +390,50 @@ if __name__ == "__main__":
|
|
|
389
390
|
print("Advanced Multiple Pipes Configuration:")
|
|
390
391
|
pipe_configs = [
|
|
391
392
|
{
|
|
392
|
-
'pipe_str': '
|
|
393
|
+
'pipe_str': 'NNE',
|
|
393
394
|
'start_c': coord3(vec3(0, 0, 0), quat(1, 0, 0, 0)),
|
|
394
395
|
'color': (255, 100, 100),
|
|
395
396
|
'radius': 0.4
|
|
396
397
|
},
|
|
397
398
|
{
|
|
398
|
-
'pipe_str': '
|
|
399
|
+
'pipe_str': 'SSU',
|
|
399
400
|
'start_c': coord3(vec3(5, 0, 0), quat(1, 0, 0, 0)),
|
|
400
401
|
'color': (100, 255, 100),
|
|
401
402
|
'radius': 0.3
|
|
402
403
|
},
|
|
403
404
|
{
|
|
404
|
-
'pipe_str': '
|
|
405
|
+
'pipe_str': 'FFR', # Local coordinate pipe
|
|
405
406
|
'start_c': coord3(vec3(0, 5, 0), quat(1, 0, 0, 0)),
|
|
406
407
|
'color': (100, 100, 255),
|
|
407
408
|
'radius': 0.2
|
|
408
409
|
}
|
|
409
410
|
]
|
|
410
411
|
|
|
411
|
-
|
|
412
|
+
# Visualize with mixed coordinate systems
|
|
413
|
+
multiple_pipes_vis(pipe_configs, 'world') # First two are world, third is local but will be treated as world
|
|
414
|
+
print()
|
|
415
|
+
|
|
416
|
+
# Example 5: Explicit coordinate system specification
|
|
417
|
+
print("Explicit Coordinate System Example:")
|
|
418
|
+
world_configs = [
|
|
419
|
+
{
|
|
420
|
+
'pipe_str': 'NNE',
|
|
421
|
+
'start_c': coord3(vec3(0, 0, 0), quat(1, 0, 0, 0)),
|
|
422
|
+
'color': (255, 0, 0),
|
|
423
|
+
'radius': 0.3
|
|
424
|
+
}
|
|
425
|
+
]
|
|
426
|
+
|
|
427
|
+
local_configs = [
|
|
428
|
+
{
|
|
429
|
+
'pipe_str': 'FFR',
|
|
430
|
+
'start_c': coord3(vec3(3, 0, 0), quat(1, 0, 0, 0)),
|
|
431
|
+
'color': (0, 255, 0),
|
|
432
|
+
'radius': 0.3
|
|
433
|
+
}
|
|
434
|
+
]
|
|
435
|
+
|
|
436
|
+
# Visualize world coordinate pipe
|
|
437
|
+
world_result = multiple_pipes_vis(world_configs, 'world')
|
|
438
|
+
# Visualize local coordinate pipe
|
|
439
|
+
local_result = multiple_pipes_vis(local_configs, 'local')
|
phg/shader_render.py
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import
|
|
1
|
+
import sys
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
import pygame
|
|
6
|
+
import numpy as np
|
|
7
|
+
from OpenGL.GL import * # noqa: F401,F403 - OpenGL symbols used dynamically
|
|
8
|
+
from OpenGL.GL.shaders import compileProgram, compileShader
|
|
9
|
+
_IMPORT_ERROR = None
|
|
10
|
+
except Exception as exc: # pragma: no cover - optional dependency
|
|
11
|
+
pygame = None
|
|
12
|
+
np = None
|
|
13
|
+
compileProgram = None
|
|
14
|
+
compileShader = None
|
|
15
|
+
_IMPORT_ERROR = exc
|
|
7
16
|
|
|
8
17
|
class Camera:
|
|
9
18
|
"""Camera class with mouse interaction controls"""
|
|
@@ -93,7 +102,7 @@ def normalize(v):
|
|
|
93
102
|
return v
|
|
94
103
|
return v / norm
|
|
95
104
|
|
|
96
|
-
class ShaderRenderer:
|
|
105
|
+
class ShaderRenderer:
|
|
97
106
|
"""
|
|
98
107
|
Shader renderer class for visualizing GLSL shaders
|
|
99
108
|
|
|
@@ -102,15 +111,20 @@ class ShaderRenderer:
|
|
|
102
111
|
renderer.render_shader(fragment_shader_code)
|
|
103
112
|
"""
|
|
104
113
|
|
|
105
|
-
def __init__(self, width=800, height=600, title="Shader Renderer"):
|
|
106
|
-
"""
|
|
107
|
-
Initialize Shader renderer
|
|
114
|
+
def __init__(self, width=800, height=600, title="Shader Renderer"):
|
|
115
|
+
"""
|
|
116
|
+
Initialize Shader renderer
|
|
108
117
|
|
|
109
118
|
Args:
|
|
110
119
|
width: Window width
|
|
111
120
|
height: Window height
|
|
112
121
|
title: Window title
|
|
113
|
-
"""
|
|
122
|
+
"""
|
|
123
|
+
if _IMPORT_ERROR is not None:
|
|
124
|
+
raise ImportError(
|
|
125
|
+
"ShaderRenderer requires pygame, numpy, and PyOpenGL. "
|
|
126
|
+
"Install with: pip install phg_vis[shader]"
|
|
127
|
+
) from _IMPORT_ERROR
|
|
114
128
|
self.width = width
|
|
115
129
|
self.height = height
|
|
116
130
|
self.title = title
|
|
@@ -422,4 +436,4 @@ def render_shader(fragment_shader, width=800, height=600, duration=0, title="Sha
|
|
|
422
436
|
renderer = ShaderRenderer(width, height, title)
|
|
423
437
|
success = renderer.render_shader(fragment_shader, duration)
|
|
424
438
|
renderer.close()
|
|
425
|
-
return success
|
|
439
|
+
return success
|
phg/visphg.py
CHANGED
|
@@ -1,55 +1,79 @@
|
|
|
1
|
-
#################################
|
|
2
|
-
# Launch vis.exe
|
|
3
|
-
#################################
|
|
4
|
-
import http.client
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
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
|
-
|
|
1
|
+
#################################
|
|
2
|
+
# Launch vis.exe
|
|
3
|
+
#################################
|
|
4
|
+
import http.client
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import subprocess
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
import psutil
|
|
11
|
+
except Exception: # pragma: no cover - optional dependency
|
|
12
|
+
psutil = None
|
|
13
|
+
|
|
14
|
+
# Set the path to vis.exe in the current directory of the current script
|
|
15
|
+
current_directory = os.path.dirname(os.path.abspath(__file__))
|
|
16
|
+
vis_exe_path = os.path.join(current_directory, "vis", "vis.exe")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Check if vis.exe is running
|
|
20
|
+
def is_vis_running():
|
|
21
|
+
if psutil is None:
|
|
22
|
+
return False
|
|
23
|
+
for proc in psutil.process_iter(["name"]):
|
|
24
|
+
if proc.info.get("name") == "vis.exe":
|
|
25
|
+
return True
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Send network message
|
|
30
|
+
def HTTPPOST(ip, phg):
|
|
31
|
+
headers = {
|
|
32
|
+
"Connection": "keep-alive",
|
|
33
|
+
"Content-Type": "text/plain",
|
|
34
|
+
}
|
|
35
|
+
conn = http.client.HTTPConnection(f"{ip}:5088")
|
|
36
|
+
conn.request("POST", "/phg", phg, headers)
|
|
37
|
+
conn.getresponse()
|
|
38
|
+
conn.close()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Call HTTPPOST function to send network message
|
|
42
|
+
def vis(phg):
|
|
43
|
+
if not is_vis_running():
|
|
44
|
+
subprocess.Popen(vis_exe_path)
|
|
45
|
+
return HTTPPOST("127.0.0.1", phg.encode())
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Build image request payload with parameters
|
|
49
|
+
def _build_img_request(phg, filename):
|
|
50
|
+
if "|||" not in phg:
|
|
51
|
+
return f"{phg}|||file={filename}"
|
|
52
|
+
code, params = phg.split("|||", 1)
|
|
53
|
+
params = params.strip()
|
|
54
|
+
if "file=" in params:
|
|
55
|
+
params = re.sub(r"file=\\S+", f"file={filename}", params)
|
|
56
|
+
else:
|
|
57
|
+
params = f"{params} file={filename}".strip()
|
|
58
|
+
return f"{code}|||{params}"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Send image request
|
|
62
|
+
def HTTPPOST_IMG(ip, phg, filename="shot.png"):
|
|
63
|
+
headers = {
|
|
64
|
+
"Connection": "keep-alive",
|
|
65
|
+
"Content-Type": "text/plain",
|
|
66
|
+
}
|
|
67
|
+
request_body = _build_img_request(phg, filename)
|
|
68
|
+
|
|
69
|
+
conn = http.client.HTTPConnection(f"{ip}:5088")
|
|
70
|
+
conn.request("POST", "/phg_img", request_body, headers)
|
|
71
|
+
conn.getresponse()
|
|
72
|
+
conn.close()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# Call HTTPPOST function to send network message
|
|
76
|
+
def image(phg, filename="shot.png"):
|
|
77
|
+
if not is_vis_running():
|
|
78
|
+
subprocess.Popen(vis_exe_path)
|
|
79
|
+
return HTTPPOST_IMG("127.0.0.1", phg.encode("utf-8").decode("utf-8"), filename)
|