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/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
- - F: Forward
16
- - B: Backward
17
- - R: Right
18
- - L: Left
19
- - U: Up
20
- - D: Down
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 world_pipe_to_phg(world_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
39
+ def world_to_local_pipe_str(world_pipe_str, start_c):
31
40
  """
32
- Convert world coordinate system pipe string to PHG script
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., "FFRUD")
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
- PHG script string
48
+ Local coordinate pipe string
42
49
  """
43
50
 
44
- # World coordinate direction definitions
45
- world_directions = {
46
- 'F': vec3(0, 0, 1), # Forward (World Z+)
47
- 'B': vec3(0, 0, -1), # Backward (World Z-)
48
- 'R': vec3(1, 0, 0), # Right (World X+)
49
- 'L': vec3(-1, 0, 0), # Left (World X-)
50
- 'U': vec3(0, 1, 0), # Up (World Y+)
51
- 'D': vec3(0, -1, 0) # Down (World Y-)
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
- # Parse color
55
- r, g, b = pipe_color
56
-
57
- # Pipe component mapping (all components use fixed length 1.0)
58
- pipe_components = {
59
- 'F': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:90;z:-0.5;}};z:1.0}}',
60
- 'B': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:-90;z:{-1.0-0.5};}};z:1.0}}',
61
- '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;}}',
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 current coordinate system (using starting coordinate)
68
- cur_c = coord3(start_c.o, start_c.Q())
69
-
70
- # Store all pipe component scripts
71
- script_parts = []
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 current movement direction in world coordinates
80
- world_dir = world_directions[move_char]
81
-
82
- # Transform world direction to current local coordinate system
83
- local_dir = vec3(
84
- world_dir.dot(cur_c.ux), # Component in local X-axis
85
- world_dir.dot(cur_c.uy), # Component in local Y-axis
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 local movement direction based on maximum component
91
+
92
+ # Determine movement direction based on the largest component
94
93
  if max_idx == 0: # X-axis
95
- local_move = 'R' if local_dir.x > 0 else 'L'
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
- # Add corresponding pipe component script
102
- script_parts.append(pipe_components[local_move])
103
-
104
- # Update current coordinate system (simulate new position and direction after movement)
105
- if local_move == 'F':
106
- # Forward: move 1.0 unit along local Z-axis positive direction
107
- cur_c = cur_c * coord3(vec3(0, 0, 1.0))
108
- elif local_move == 'B':
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
- # Up turn: rotate 90 degrees around X-axis, then move 1.0 unit along Y-axis
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
- # Down turn: rotate -90 degrees around X-axis, then move 1.0 unit along Y-axis
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
- cur_c = cur_c * coord3(vec3(0, -1.0, 0))
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 (all components use fixed length 1.0)
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:{-1.0-0.5};}};z:1.0}}',
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., "FFRUD" or ["FFR", "LLU"])
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
- phg_script = world_pipe_to_phg(pipe_str, start_c, color, pipe_radius)
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
- phg_script = world_pipe_to_phg(pipe_str, start_c, color, radius)
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: Single world coordinate pipe string
358
- example_world_pipe = "FFRUD" # Forward twice, right, up, down
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
- phg_script = world_pipe_to_phg(example_world_pipe, start_coord)
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 = ["FFR", "LLU", "RRD"]
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': 'FFR',
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': 'LLU',
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': 'RRD',
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
- multiple_pipes_vis(pipe_configs, 'world')
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 pygame
2
- import numpy as np
3
- from OpenGL.GL import *
4
- from OpenGL.GL.shaders import compileProgram, compileShader
5
- import sys
6
- import time
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 subprocess
6
- import os
7
- import psutil # Make sure to import psutil
8
-
9
- # Set the path to vis.exe in the current directory of the current script
10
- current_directory = os.path.dirname(os.path.abspath(__file__))
11
- vis_exe_path = os.path.join(current_directory, "vis", "vis.exe")
12
- print(vis_exe_path)
13
- # Check if vis.exe is running
14
- def is_vis_running():
15
- for proc in psutil.process_iter(['name']):
16
- if proc.info['name'] == 'vis.exe':
17
- return True
18
- return False
19
-
20
- # Send network message
21
- def HTTPPOST(ip, phg):
22
- headers = {
23
- "Connection": "keep-alive",
24
- "Content-Type": "text/plain"
25
- }
26
- conn = http.client.HTTPConnection(f"{ip}:5088")
27
- conn.request('POST', '/phg', phg, headers)
28
- res = conn.getresponse()
29
- conn.close()
30
-
31
- # Call HTTPPOST function to send network message
32
- def vis(phg):
33
- if not is_vis_running(): # Check if the process is running
34
- subprocess.Popen(vis_exe_path) # Start the process
35
- return HTTPPOST('127.0.0.1', phg.encode())
36
-
37
- # Send network message
38
- def HTTPPOST_IMG(ip, phg, filename='shot.png'):
39
- headers = {
40
- "Connection": "keep-alive",
41
- "Content-Type": "text/plain"
42
- }
43
- # 构建完整的请求体: phg代码 ||| 渲染参数(包含文件名)
44
- request_body = f"{phg}|||file={filename}"
45
-
46
- conn = http.client.HTTPConnection(f"{ip}:5088")
47
- conn.request('POST', '/phg_img', request_body, headers)
48
- res = conn.getresponse()
49
- conn.close()
50
-
51
- # Call HTTPPOST function to send network message
52
- def image(phg, filename='shot.png'):
53
- if not is_vis_running(): # Check if the process is running
54
- subprocess.Popen(vis_exe_path) # Start the process
55
- return HTTPPOST_IMG('127.0.0.1', phg.encode('utf-8').decode('utf-8'), filename)
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)