phg-vis 1.3.0__py3-none-any.whl → 1.3.2__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 CHANGED
@@ -1,48 +1,68 @@
1
1
  """
2
- __init__.py
3
- PHG主库 - 集成PHG到Shader转换功能
2
+ PHG - Python Hypergraphics Library
3
+ ===================================
4
+
5
+ A powerful graphics library for procedural 3D visualization using PHG scripts.
6
+
7
+ Main Features:
8
+ - PHG script visualization via vis.exe
9
+ - Shader-based rendering with GLSL conversion
10
+ - Pipe system visualization with world/local coordinate systems
11
+ - Multiple pipe visualization support
12
+ - Real-time and image rendering capabilities
13
+
14
+ Version: 1.3.1
15
+ Author: PanGuoJun
16
+ License: MIT
4
17
  """
5
18
 
6
19
  from .visphg import vis, image
7
20
  from .shader_render import ShaderRenderer, render_shader
8
21
  from .phg_to_shader import PHGToShaderConverter, phg_to_shader
22
+ from .pipe_string_phg import (
23
+ world_pipe_to_phg,
24
+ local_pipe_to_phg,
25
+ world_pipestr_vis,
26
+ local_pipestr_vis,
27
+ multiple_pipes_vis
28
+ )
9
29
 
10
- # 扩展ShaderRenderer类以支持PHG直接渲染
30
+ # Extend ShaderRenderer class to support direct PHG rendering
11
31
  class PHGShaderRenderer(ShaderRenderer):
12
- """支持PHG直接渲染的Shader渲染器"""
32
+ """Shader renderer that supports direct PHG rendering"""
13
33
 
14
34
  def render_phg(self, phg_script: str, duration=0, interactive=True):
15
35
  """
16
- 渲染PHG脚本
36
+ Render PHG script
17
37
 
18
- 参数:
19
- phg_script: PHG脚本代码
20
- duration: 渲染持续时间
21
- interactive: 是否允许交互
38
+ Parameters:
39
+ phg_script: PHG script code
40
+ duration: Render duration
41
+ interactive: Whether to allow interaction
22
42
 
23
- 返回:
24
- success: 是否成功渲染
43
+ Returns:
44
+ success: Whether rendering was successful
25
45
  """
26
46
  converter = PHGToShaderConverter()
27
47
  shader_code = converter.generate_shader_code(phg_script)
28
48
 
29
49
  if not shader_code:
30
- print("错误: PHG转换失败")
50
+ print("Error: PHG conversion failed")
31
51
  return False
32
52
 
33
53
  return self.render_shader(shader_code, duration, interactive)
34
54
 
35
- # 便捷函数
55
+ # Convenience functions
36
56
  def render_phg(phg_script: str, width=800, height=600, duration=0, title="PHG Renderer"):
37
57
  """
38
- 直接渲染PHG脚本
39
-
40
- 参数:
41
- phg_script: PHG脚本代码
42
- width: 窗口宽度
43
- height: 窗口高度
44
- duration: 渲染持续时间
45
- title: 窗口标题
58
+ Directly render PHG script
59
+
60
+ Parameters:
61
+ phg_script: PHG script code
62
+ width: Window width
63
+ height: Window height
64
+ duration: Render duration
65
+ title: Window title
46
66
  """
47
67
  renderer = PHGShaderRenderer(width, height, title)
48
68
  success = renderer.render_phg(phg_script, duration)
@@ -51,32 +71,259 @@ def render_phg(phg_script: str, width=800, height=600, duration=0, title="PHG Re
51
71
 
52
72
  def convert_phg_to_shader(phg_script: str) -> str:
53
73
  """
54
- PHG脚本转换为GLSL着色器代码
74
+ Convert PHG script to GLSL shader code
75
+
76
+ Parameters:
77
+ phg_script: PHG script
78
+
79
+ Returns:
80
+ shader_code: GLSL shader code
81
+ """
82
+ return phg_to_shader(phg_script)
83
+
84
+ def visualize_pipe_variants(pipe_variants, start_position=None, colors=None, coordinate_system='world'):
85
+ """
86
+ Visualize multiple pipe variants for comparison
87
+
88
+ Parameters:
89
+ pipe_variants: List of pipe strings or configuration dictionaries
90
+ start_position: Starting coordinate (optional)
91
+ colors: List of colors for each pipe variant
92
+ coordinate_system: 'world' or 'local' coordinate system
93
+
94
+ Returns:
95
+ PHG script string
96
+ """
97
+ from coordinate_system import vec3, quat, coord3
98
+
99
+ # Handle start position
100
+ if start_position is None:
101
+ start_c = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
102
+ else:
103
+ start_c = start_position
55
104
 
56
- 参数:
57
- phg_script: PHG脚本
105
+ # Handle different input formats
106
+ if isinstance(pipe_variants[0], str):
107
+ # Simple list of pipe strings
108
+ if colors is None:
109
+ # Generate distinct colors for each variant
110
+ import colorsys
111
+ colors = []
112
+ for i in range(len(pipe_variants)):
113
+ hue = i / len(pipe_variants)
114
+ rgb = colorsys.hsv_to_rgb(hue, 0.8, 0.9)
115
+ colors.append(tuple(int(c * 255) for c in rgb))
58
116
 
59
- 返回:
60
- shader_code: GLSL着色器代码
117
+ if coordinate_system == 'world':
118
+ return world_pipestr_vis(pipe_variants, start_c, colors)
119
+ else:
120
+ return local_pipestr_vis(pipe_variants, start_c, colors)
121
+
122
+ else:
123
+ # List of configuration dictionaries
124
+ pipe_configs = []
125
+ for i, variant in enumerate(pipe_variants):
126
+ if isinstance(variant, str):
127
+ config = {
128
+ 'pipe_str': variant,
129
+ 'start_c': start_c,
130
+ 'color': colors[i] if colors else None,
131
+ 'radius': 0.3
132
+ }
133
+ else:
134
+ config = variant
135
+ if 'start_c' not in config:
136
+ config['start_c'] = start_c
137
+
138
+ pipe_configs.append(config)
139
+
140
+ return multiple_pipes_vis(pipe_configs, coordinate_system)
141
+
142
+ def create_pipe_comparison_grid(pipe_strings, grid_size=(2, 2), start_position=None,
143
+ base_color=(0, 55, 255), coordinate_system='world'):
61
144
  """
62
- return phg_to_shader(phg_script)
145
+ Create a grid layout for comparing multiple pipe paths
146
+
147
+ Parameters:
148
+ pipe_strings: List of pipe strings to compare
149
+ grid_size: (rows, cols) for grid layout
150
+ start_position: Base starting position
151
+ base_color: Base color for pipes
152
+ coordinate_system: 'world' or 'local'
153
+
154
+ Returns:
155
+ PHG script string
156
+ """
157
+ from coordinate_system import vec3, quat, coord3
158
+
159
+ if start_position is None:
160
+ start_position = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
161
+
162
+ rows, cols = grid_size
163
+ spacing = 5.0 # Space between pipes in grid
164
+
165
+ pipe_configs = []
166
+
167
+ for i, pipe_str in enumerate(pipe_strings):
168
+ if i >= rows * cols:
169
+ break
170
+
171
+ row = i // cols
172
+ col = i % cols
173
+
174
+ # Calculate position in grid
175
+ x_offset = col * spacing
176
+ z_offset = row * spacing
177
+
178
+ # Create individual start position for this pipe
179
+ individual_start = coord3(
180
+ vec3(
181
+ start_position.o.x + x_offset,
182
+ start_position.o.y,
183
+ start_position.o.z + z_offset
184
+ ),
185
+ start_position.Q()
186
+ )
187
+
188
+ # Generate color variation
189
+ color_variation = (
190
+ min(255, base_color[0] + (i * 30) % 100),
191
+ min(255, base_color[1] + (i * 50) % 100),
192
+ min(255, base_color[2] + (i * 70) % 100)
193
+ )
194
+
195
+ pipe_configs.append({
196
+ 'pipe_str': pipe_str,
197
+ 'start_c': individual_start,
198
+ 'color': color_variation,
199
+ 'radius': 0.25 + (i * 0.05) # Vary radius slightly
200
+ })
201
+
202
+ return multiple_pipes_vis(pipe_configs, coordinate_system)
203
+
204
+ def generate_pipe_variants_from_rules(base_pipe, num_variants=5, apply_rules=None):
205
+ """
206
+ Generate pipe variants using transformation rules
207
+
208
+ Parameters:
209
+ base_pipe: Base pipe string
210
+ num_variants: Number of variants to generate
211
+ apply_rules: List of rules to apply ('swap', 'insert', 'cancel')
212
+
213
+ Returns:
214
+ List of pipe variant strings
215
+ """
216
+ if apply_rules is None:
217
+ apply_rules = ['swap', 'insert', 'cancel']
218
+
219
+ variants = [base_pipe]
220
+
221
+ # Import the pipe transformer if available
222
+ try:
223
+ from .pipe_string_phg import PipeStringTransformer
224
+ transformer = PipeStringTransformer()
225
+
226
+ for _ in range(num_variants - 1):
227
+ current_pipe = base_pipe
228
+
229
+ # Apply random transformations
230
+ import random
231
+ for _ in range(random.randint(1, 3)):
232
+ rule = random.choice(apply_rules)
233
+
234
+ if rule == 'swap' and len(current_pipe) >= 2:
235
+ i, j = random.sample(range(len(current_pipe)), 2)
236
+ current_pipe = transformer.swap_positions(current_pipe, i, j)
237
+
238
+ elif rule == 'insert':
239
+ position = random.randint(0, len(current_pipe))
240
+ direction = random.choice(list(transformer.CANCEL_PAIRS.keys()))
241
+ current_pipe = transformer.insert_cancel_pair(current_pipe, position, direction)
242
+
243
+ elif rule == 'cancel':
244
+ current_pipe = transformer.cancel_adjacent_pairs(current_pipe)
245
+
246
+ # Simplify and add if valid
247
+ simplified = transformer.simplify_path(current_pipe)
248
+ if simplified not in variants:
249
+ variants.append(simplified)
250
+
251
+ except ImportError:
252
+ # Fallback: simple variant generation
253
+ import random
254
+ for i in range(num_variants - 1):
255
+ # Simple character shuffling
256
+ pipe_list = list(base_pipe)
257
+ random.shuffle(pipe_list)
258
+ variant = ''.join(pipe_list)
259
+ if variant not in variants:
260
+ variants.append(variant)
261
+
262
+ return variants[:num_variants]
263
+
264
+ # Enhanced pipe visualization with transformation support
265
+ def visualize_pipe_with_transformations(pipe_string, start_position=None,
266
+ transformations=None, show_variants=3):
267
+ """
268
+ Visualize a pipe string along with its transformed variants
269
+
270
+ Parameters:
271
+ pipe_string: Base pipe string
272
+ start_position: Starting coordinate
273
+ transformations: List of transformation rules to apply
274
+ show_variants: Number of variants to show
275
+
276
+ Returns:
277
+ PHG script string
278
+ """
279
+ # Generate variants
280
+ variants = generate_pipe_variants_from_rules(
281
+ pipe_string,
282
+ num_variants=show_variants + 1, # +1 for original
283
+ apply_rules=transformations
284
+ )
285
+
286
+ # Create comparison visualization
287
+ return visualize_pipe_variants(variants, start_position)
63
288
 
64
289
  __all__ = [
65
- 'vis',
66
- 'image',
67
- 'ShaderRenderer',
290
+ # Core visualization functions
291
+ 'vis',
292
+ 'image',
293
+
294
+ # Shader rendering
295
+ 'ShaderRenderer',
68
296
  'render_shader',
69
- 'PHGToShaderConverter',
70
- 'PHGShaderRenderer',
71
297
  'render_phg',
298
+ 'PHGShaderRenderer',
299
+
300
+ # PHG conversion
301
+ 'PHGToShaderConverter',
302
+ 'phg_to_shader',
72
303
  'convert_phg_to_shader',
73
- 'phg_to_shader'
304
+
305
+ # Pipe visualization
306
+ 'world_pipe_to_phg',
307
+ 'local_pipe_to_phg',
308
+ 'world_pipestr_vis',
309
+ 'local_pipestr_vis',
310
+ 'multiple_pipes_vis',
311
+
312
+ # Enhanced pipe visualization
313
+ 'visualize_pipe_variants',
314
+ 'create_pipe_comparison_grid',
315
+ 'generate_pipe_variants_from_rules',
316
+ 'visualize_pipe_with_transformations',
74
317
  ]
75
318
 
76
- __version__ = "0.2.0"
77
- __author__ = "PHG Development Team"
78
- __description__ = "Python Graphics Library with PHG to Shader conversion"
319
+ __version__ = "1.3.1"
320
+ __author__ = "PanGuoJun"
321
+ __description__ = "Python Hypergraphics Library"
79
322
 
80
- # 包初始化信息
323
+ # Package initialization information
81
324
  print(f"PHG {__version__} - {__description__}")
82
- print("PHG to Shader转换器已加载")
325
+ print("[OK] Visualization module loaded")
326
+ print("[OK] Shader converter loaded")
327
+ print("[OK] Pipe visualization loaded")
328
+ print("[OK] Multiple pipe visualization support loaded")
329
+ print("[OK] Pipe transformation utilities loaded")
phg/pipe_string_phg.py ADDED
@@ -0,0 +1,411 @@
1
+ """
2
+ Pipe String to PHG Converter
3
+ ============================
4
+
5
+ This module provides functionality to convert pipe strings into PHG (Python Graphics) scripts.
6
+ Supports both world coordinate system and local coordinate system pipe descriptions.
7
+
8
+ Main Features:
9
+ - world_pipe_to_phg: World coordinate system pipe conversion
10
+ - local_pipe_to_phg: Local coordinate system pipe conversion
11
+ - world_pipestr_vis: Direct visualization for world coordinate pipes
12
+ - local_pipestr_vis: Direct visualization for local coordinate pipes
13
+
14
+ Pipe String Format:
15
+ - F: Forward
16
+ - B: Backward
17
+ - R: Right
18
+ - L: Left
19
+ - U: Up
20
+ - D: Down
21
+ """
22
+
23
+ import phg
24
+ from coordinate_system import vec3, quat, coord3
25
+
26
+ # Default color and pipe radius
27
+ DEFAULT_PIPE_COLOR = (0, 55, 255)
28
+ DEFAULT_PIPE_RADIUS = 0.3
29
+
30
+ def world_pipe_to_phg(world_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
31
+ """
32
+ Convert world coordinate system pipe string to PHG script
33
+
34
+ Parameters:
35
+ world_pipe_str: World coordinate pipe string (e.g., "FFRUD")
36
+ start_c: Starting coordinate system
37
+ pipe_color: Pipe color as (R, G, B) tuple
38
+ pipe_radius: Pipe radius
39
+
40
+ Returns:
41
+ PHG script string
42
+ """
43
+
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-)
52
+ }
53
+
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;}}'
65
+ }
66
+
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")
77
+ 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
90
+ abs_components = [abs(local_dir.x), abs(local_dir.y), abs(local_dir.z)]
91
+ max_idx = abs_components.index(max(abs_components))
92
+
93
+ # Determine local movement direction based on maximum component
94
+ if max_idx == 0: # X-axis
95
+ local_move = 'R' if local_dir.x > 0 else 'L'
96
+ elif max_idx == 1: # Y-axis
97
+ local_move = 'U' if local_dir.y > 0 else 'D'
98
+ 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
113
+ rotation = quat(-3.1416 / 2, cur_c.uy)
114
+ cur_c = cur_c * rotation
115
+ cur_c = cur_c * coord3(vec3(1.0, 0, 0))
116
+ elif local_move == 'L':
117
+ # Left turn: rotate 90 degrees around Y-axis, then move 1.0 unit along X-axis
118
+ rotation = quat(3.1416 / 2, cur_c.uy)
119
+ cur_c = cur_c * rotation
120
+ cur_c = cur_c * coord3(vec3(-1.0, 0, 0))
121
+ 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)
124
+ cur_c = cur_c * rotation
125
+ cur_c = cur_c * coord3(vec3(0, 1.0, 0))
126
+ 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)
129
+ 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
+
146
+
147
+ def local_pipe_to_phg(local_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
148
+ """
149
+ Convert local coordinate system pipe string to PHG script
150
+
151
+ Parameters:
152
+ local_pipe_str: Local coordinate pipe string (e.g., "FFRUD")
153
+ start_c: Starting coordinate system
154
+ pipe_color: Pipe color as (R, G, B) tuple
155
+ pipe_radius: Pipe radius
156
+
157
+ Returns:
158
+ PHG script string
159
+ """
160
+
161
+ # Parse color
162
+ r, g, b = pipe_color
163
+
164
+ # Pipe component mapping (all components use fixed length 1.0)
165
+ pipe_components = {
166
+ '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}}',
168
+ '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
+ '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
+ '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;}}',
171
+ '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;}}'
172
+ }
173
+
174
+ # Store all pipe component scripts
175
+ script_parts = []
176
+
177
+ # Iterate through each character in pipe string
178
+ for move_char in local_pipe_str:
179
+ if move_char not in pipe_components:
180
+ print(f"Warning: Unknown pipe character '{move_char}', skipped")
181
+ continue
182
+
183
+ # Directly use local coordinate system movement commands
184
+ script_parts.append(pipe_components[move_char])
185
+
186
+ # Combine all pipe component scripts
187
+ inner_script = ',\n'.join(script_parts)
188
+
189
+ # Get quaternion of starting coordinate system
190
+ q = start_c.Q()
191
+
192
+ # Build complete PHG script
193
+ complete_script = f"""{{
194
+ {{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;
195
+ <{inner_script}>}}
196
+ }}"""
197
+
198
+ return complete_script
199
+
200
+
201
+ def world_pipestr_vis(world_pipe_strs, start_c=None, pipe_colors=None, pipe_radius=DEFAULT_PIPE_RADIUS):
202
+ """
203
+ Direct visualization for world coordinate pipe strings with support for multiple pipes
204
+
205
+ Parameters:
206
+ world_pipe_strs: World coordinate pipe string or list of strings (e.g., "FFRUD" or ["FFR", "LLU"])
207
+ start_c: Starting coordinate system, defaults to origin
208
+ pipe_colors: Single color or list of colors as (R, G, B) tuples
209
+ pipe_radius: Pipe radius
210
+
211
+ Returns:
212
+ PHG script string
213
+ """
214
+ # Handle single string input
215
+ if isinstance(world_pipe_strs, str):
216
+ world_pipe_strs = [world_pipe_strs]
217
+
218
+ # Handle single color input
219
+ if pipe_colors is None:
220
+ pipe_colors = [DEFAULT_PIPE_COLOR] * len(world_pipe_strs)
221
+ elif isinstance(pipe_colors, tuple):
222
+ pipe_colors = [pipe_colors] * len(world_pipe_strs)
223
+
224
+ # Ensure colors list matches pipes list length
225
+ if len(pipe_colors) != len(world_pipe_strs):
226
+ pipe_colors = [DEFAULT_PIPE_COLOR] * len(world_pipe_strs)
227
+ print("Warning: Colors list length doesn't match pipes list, using default colors")
228
+
229
+ # Use default origin if no starting coordinate provided
230
+ if start_c is None:
231
+ start_c = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
232
+
233
+ # Generate PHG scripts for all pipes
234
+ script_parts = []
235
+ 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)
237
+ # Extract inner content between outer braces
238
+ inner_content = phg_script.strip()[1:-1].strip()
239
+ script_parts.append(inner_content)
240
+
241
+ # Combine all pipe scripts
242
+ combined_script = "{\n" + ",\n".join(script_parts) + "\n}"
243
+
244
+ # Call visualization function
245
+ try:
246
+ phg.vis(combined_script)
247
+ print(f"Visualizing {len(world_pipe_strs)} world coordinate pipes")
248
+ except ImportError:
249
+ print("Warning: Cannot import visualization module, returning PHG script")
250
+
251
+ return combined_script
252
+
253
+
254
+ def local_pipestr_vis(local_pipe_strs, start_c=None, pipe_colors=None, pipe_radius=DEFAULT_PIPE_RADIUS):
255
+ """
256
+ Direct visualization for local coordinate pipe strings with support for multiple pipes
257
+
258
+ Parameters:
259
+ local_pipe_strs: Local coordinate pipe string or list of strings (e.g., "FFRUD" or ["FFR", "LLU"])
260
+ start_c: Starting coordinate system, defaults to origin
261
+ pipe_colors: Single color or list of colors as (R, G, B) tuples
262
+ pipe_radius: Pipe radius
263
+
264
+ Returns:
265
+ PHG script string
266
+ """
267
+ # Handle single string input
268
+ if isinstance(local_pipe_strs, str):
269
+ local_pipe_strs = [local_pipe_strs]
270
+
271
+ # Handle single color input
272
+ if pipe_colors is None:
273
+ pipe_colors = [DEFAULT_PIPE_COLOR] * len(local_pipe_strs)
274
+ elif isinstance(pipe_colors, tuple):
275
+ pipe_colors = [pipe_colors] * len(local_pipe_strs)
276
+
277
+ # Ensure colors list matches pipes list length
278
+ if len(pipe_colors) != len(local_pipe_strs):
279
+ pipe_colors = [DEFAULT_PIPE_COLOR] * len(local_pipe_strs)
280
+ print("Warning: Colors list length doesn't match pipes list, using default colors")
281
+
282
+ # Use default origin if no starting coordinate provided
283
+ if start_c is None:
284
+ start_c = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
285
+
286
+ # Generate PHG scripts for all pipes
287
+ script_parts = []
288
+ for i, (pipe_str, color) in enumerate(zip(local_pipe_strs, pipe_colors)):
289
+ phg_script = local_pipe_to_phg(pipe_str, start_c, color, pipe_radius)
290
+ # Extract inner content between outer braces
291
+ inner_content = phg_script.strip()[1:-1].strip()
292
+ script_parts.append(inner_content)
293
+
294
+ # Combine all pipe scripts
295
+ combined_script = "{\n" + ",\n".join(script_parts) + "\n}"
296
+
297
+ # Call visualization function
298
+ try:
299
+ phg.vis(combined_script)
300
+ print(f"Visualizing {len(local_pipe_strs)} local coordinate pipes")
301
+ except ImportError:
302
+ print("Warning: Cannot import visualization module, returning PHG script")
303
+
304
+ return combined_script
305
+
306
+
307
+ def multiple_pipes_vis(pipe_configs, coordinate_system='world'):
308
+ """
309
+ Advanced visualization for multiple pipes with individual configurations
310
+
311
+ Parameters:
312
+ pipe_configs: List of pipe configuration dictionaries with keys:
313
+ - 'pipe_str': Pipe string (required)
314
+ - 'start_c': Starting coordinate (optional, defaults to origin)
315
+ - 'color': Pipe color (optional, defaults to DEFAULT_PIPE_COLOR)
316
+ - 'radius': Pipe radius (optional, defaults to DEFAULT_PIPE_RADIUS)
317
+ coordinate_system: 'world' or 'local' coordinate system
318
+
319
+ Returns:
320
+ PHG script string
321
+ """
322
+ script_parts = []
323
+
324
+ for i, config in enumerate(pipe_configs):
325
+ pipe_str = config.get('pipe_str')
326
+ start_c = config.get('start_c', coord3(vec3(0, 0, 0), quat(1, 0, 0, 0)))
327
+ color = config.get('color', DEFAULT_PIPE_COLOR)
328
+ radius = config.get('radius', DEFAULT_PIPE_RADIUS)
329
+
330
+ if coordinate_system.lower() == 'world':
331
+ phg_script = world_pipe_to_phg(pipe_str, start_c, color, radius)
332
+ else:
333
+ phg_script = local_pipe_to_phg(pipe_str, start_c, color, radius)
334
+
335
+ # Extract inner content
336
+ inner_content = phg_script.strip()[1:-1].strip()
337
+ script_parts.append(inner_content)
338
+
339
+ # Combine all pipe scripts
340
+ combined_script = "{\n" + ",\n".join(script_parts) + "\n}"
341
+
342
+ # Call visualization
343
+ try:
344
+ phg.vis(combined_script)
345
+ print(f"Visualizing {len(pipe_configs)} pipes in {coordinate_system} coordinate system")
346
+ except ImportError:
347
+ print("Warning: Cannot import visualization module, returning PHG script")
348
+
349
+ return combined_script
350
+
351
+
352
+ # Usage Examples
353
+ if __name__ == "__main__":
354
+ # Create starting coordinate system (example)
355
+ start_coord = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
356
+
357
+ # Example 1: Single world coordinate pipe string
358
+ example_world_pipe = "FFRUD" # Forward twice, right, up, down
359
+ print("World Coordinate Pipe Example:")
360
+ phg_script = world_pipe_to_phg(example_world_pipe, start_coord)
361
+ print("Generated PHG Script:")
362
+ print(phg_script)
363
+ print()
364
+
365
+ # Example 2: Single local coordinate pipe string
366
+ example_local_pipe = "FFRUD" # Movements in local coordinate system
367
+ print("Local Coordinate Pipe Example:")
368
+ phg_script = local_pipe_to_phg(example_local_pipe, start_coord)
369
+ print("Generated PHG Script:")
370
+ print(phg_script)
371
+ print()
372
+
373
+ # Example 3: Multiple pipes visualization
374
+ print("Multiple Pipes Visualization Example:")
375
+
376
+ # Multiple world coordinate pipes with different colors
377
+ world_pipes = ["FFR", "LLU", "RRD"]
378
+ world_colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] # Red, Green, Blue
379
+ world_pipestr_vis(world_pipes, start_coord, world_colors)
380
+ print()
381
+
382
+ # Multiple local coordinate pipes
383
+ local_pipes = ["FFR", "BBL", "UUD"]
384
+ local_colors = [(255, 255, 0), (255, 0, 255), (0, 255, 255)] # Yellow, Magenta, Cyan
385
+ local_pipestr_vis(local_pipes, start_coord, local_colors)
386
+ print()
387
+
388
+ # Example 4: Advanced multiple pipes configuration
389
+ print("Advanced Multiple Pipes Configuration:")
390
+ pipe_configs = [
391
+ {
392
+ 'pipe_str': 'FFR',
393
+ 'start_c': coord3(vec3(0, 0, 0), quat(1, 0, 0, 0)),
394
+ 'color': (255, 100, 100),
395
+ 'radius': 0.4
396
+ },
397
+ {
398
+ 'pipe_str': 'LLU',
399
+ 'start_c': coord3(vec3(5, 0, 0), quat(1, 0, 0, 0)),
400
+ 'color': (100, 255, 100),
401
+ 'radius': 0.3
402
+ },
403
+ {
404
+ 'pipe_str': 'RRD',
405
+ 'start_c': coord3(vec3(0, 5, 0), quat(1, 0, 0, 0)),
406
+ 'color': (100, 100, 255),
407
+ 'radius': 0.2
408
+ }
409
+ ]
410
+
411
+ multiple_pipes_vis(pipe_configs, 'world')
phg/vis/vis.ini CHANGED
@@ -1,4 +1,4 @@
1
- CAMERA=0.000,10.000,18.000;0.000,0.000,0.000;0.000,1.000,0.000;0.724;1.610;0;10.000;0.000,0.000,0.000
1
+ CAMERA=4.057,2.604,-0.507;3.490,2.240,-0.436;0.000,1.000,0.000;0.175;1.610;0;10.000;0.000,0.000,0.000
2
2
  CONSOLE=true
3
3
  ENABLE_DUAL_SCREEN=false
4
4
  HOSTIP=127.0.0.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: phg_vis
3
- Version: 1.3.0
3
+ Version: 1.3.2
4
4
  Summary: A package for the PHG modeling language and 3D visualization tool.
5
5
  Home-page: https://github.com/panguojun/Coordinate-System
6
6
  Author: romeosoft
@@ -13,20 +13,21 @@ Requires-Python: >=3.8
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
 
16
- # PHG - Minimalist 3D Modeling Language
16
+ # PHG - Python Hypergraphics Library
17
17
 
18
- PHG (Bacteriophage) is a specialized modeling language for describing 3D scene node trees. Combining concepts from group theory, it provides custom overloading capabilities for variables and operations, making it particularly suitable for describing complex 3D scenes and 2D sprite structures.
18
+ PHG (Python Hypergraphics) is a powerful 3D modeling and visualization library that combines a minimalist modeling language with Python integration. It provides procedural 3D scene generation, shader-based rendering, and specialized pipe system visualization.
19
19
 
20
20
  ---
21
21
 
22
22
  ## 🌟 Features
23
23
 
24
- - **Minimalist Syntax** - Declarative node tree description
24
+ - **Minimalist Syntax** - Declarative node tree description for 3D scenes
25
25
  - **Hierarchical Modeling** - Support for nested nodes and transform inheritance
26
26
  - **Parametric Design** - Flexible property system and function definitions
27
- - **Topological Structures** - Two organization methods: sequence and array composition
28
- - **Visualization Rendering** - Powerful offscreen rendering and screenshot capabilities
29
- - **Python Integration** - Convenient Python API
27
+ - **Pipe Visualization** - Specialized system for visualizing pipe structures with world/local coordinate support
28
+ - **Shader Conversion** - Convert PHG scripts to GLSL shaders for GPU rendering
29
+ - **Dual Rendering Modes** - Both real-time visualization (vis.exe) and offscreen rendering
30
+ - **Python Integration** - Comprehensive Python API for all features
30
31
 
31
32
  ---
32
33
 
@@ -402,6 +403,122 @@ for size in [5, 10, 15, 20]:
402
403
 
403
404
  ---
404
405
 
406
+ ## 🔧 Pipe Visualization System
407
+
408
+ PHG includes a specialized pipe visualization system for creating 3D pipe structures from simple string commands.
409
+
410
+ ### Pipe String Commands
411
+
412
+ - **F** - Forward (move forward in current direction)
413
+ - **B** - Back (move backward in current direction)
414
+ - **R** - Right (turn right and move)
415
+ - **L** - Left (turn left and move)
416
+ - **U** - Up (turn up and move)
417
+ - **D** - Down (turn down and move)
418
+
419
+ ### World Coordinate System
420
+
421
+ World coordinate pipes use absolute directions regardless of current orientation:
422
+
423
+ ```python
424
+ import phg
425
+ from coordinate_system import vec3, quat, coord3
426
+
427
+ # Create a pipe in world coordinates
428
+ # F moves along world Z+, R moves along world X+, etc.
429
+ start_pos = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
430
+ phg_script = phg.world_pipestr_vis("FFRRUD", start_pos)
431
+
432
+ # Custom pipe appearance
433
+ phg.world_pipestr_vis(
434
+ "FFLLUU",
435
+ start_pos,
436
+ pipe_color=(255, 100, 50), # Orange pipe
437
+ pipe_radius=0.5 # Thicker pipe
438
+ )
439
+ ```
440
+
441
+ ### Local Coordinate System
442
+
443
+ Local coordinate pipes use directions relative to current orientation:
444
+
445
+ ```python
446
+ import phg
447
+ from coordinate_system import vec3, quat, coord3
448
+
449
+ # Create a pipe in local coordinates
450
+ # F moves forward relative to current orientation
451
+ start_pos = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
452
+ phg_script = phg.local_pipestr_vis("FFRRUD", start_pos)
453
+
454
+ # The same string produces different results in local vs world coordinates
455
+ phg.local_pipestr_vis(
456
+ "FFRRFF", # Forward, Forward, Right turn, Right turn, Forward, Forward
457
+ start_pos,
458
+ pipe_color=(0, 255, 100) # Green pipe
459
+ )
460
+ ```
461
+
462
+ ### Direct PHG Script Generation
463
+
464
+ For advanced use cases, you can generate PHG scripts without immediate visualization:
465
+
466
+ ```python
467
+ import phg
468
+ from coordinate_system import vec3, quat, coord3
469
+
470
+ start = coord3(vec3(5, 0, 0), quat(1, 0, 0, 0))
471
+
472
+ # Generate PHG script for world coordinates
473
+ world_phg = phg.world_pipe_to_phg("FFRUD", start)
474
+
475
+ # Generate PHG script for local coordinates
476
+ local_phg = phg.local_pipe_to_phg("FFRUD", start)
477
+
478
+ # Visualize later
479
+ phg.vis(world_phg)
480
+ ```
481
+
482
+ ### Example: Complex Pipe System
483
+
484
+ ```python
485
+ import phg
486
+ from coordinate_system import vec3, quat, coord3
487
+
488
+ # Create a complex pipe network
489
+ def create_pipe_network():
490
+ # Main pipeline
491
+ main_pipe = phg.world_pipestr_vis(
492
+ "FFFFRRFFRRUUFFLLFF",
493
+ coord3(vec3(0, 0, 0), quat(1, 0, 0, 0)),
494
+ pipe_color=(100, 100, 255),
495
+ pipe_radius=0.5
496
+ )
497
+
498
+ # Branch 1
499
+ branch1 = phg.world_pipestr_vis(
500
+ "RRUUFFFF",
501
+ coord3(vec3(4, 0, 0), quat(1, 0, 0, 0)),
502
+ pipe_color=(255, 100, 100),
503
+ pipe_radius=0.3
504
+ )
505
+
506
+ # Branch 2
507
+ branch2 = phg.local_pipestr_vis(
508
+ "FFLLDDFF",
509
+ coord3(vec3(8, 2, 2), quat(1, 0, 0, 0)),
510
+ pipe_color=(100, 255, 100),
511
+ pipe_radius=0.3
512
+ )
513
+
514
+ return main_pipe, branch1, branch2
515
+
516
+ # Create and visualize the network
517
+ pipes = create_pipe_network()
518
+ ```
519
+
520
+ ---
521
+
405
522
  ## 💡 Complete Examples
406
523
 
407
524
  ### Example 1: Simple Geometry
@@ -581,7 +698,6 @@ Recommended maximum resolution is **4096 x 4096**. Excessively large resolutions
581
698
  ## 🔗 Links
582
699
 
583
700
  - [PyPI Package](https://pypi.org/project/phg/)
584
- - [Official Documentation](https://your.documentation.link)
585
701
  - [Mathematical Foundation](https://github.com/panguojun/Coordinate-System)
586
702
 
587
703
  ---
@@ -1,5 +1,6 @@
1
- phg/__init__.py,sha256=S4sIzZXdanLEJ9y407hse4Vm3lLhC_aczBKb4-koiJw,2265
1
+ phg/__init__.py,sha256=kH5hF-vqbLqzBE_xkOYabiYFtdb4CXtlwl67uPbDHpo,10767
2
2
  phg/phg_to_shader.py,sha256=rb_LnGE1Py08oz72ES5CnjyCDbjVWDU3If0cYZq4SUU,15172
3
+ phg/pipe_string_phg.py,sha256=xoG8AtHRae_sOskSZxTc7lBgwnemv1u8Ko9GvnvHr8Q,16257
3
4
  phg/shader_render.py,sha256=_T8IFp1h5Hcj8TMMHwFMbxhGdHLnOqka7pJ4pde7zMA,16780
4
5
  phg/visphg.py,sha256=CtALoNJs0eDT8wnXk_76XG4UsOcV6cWucvWqz7AhOSc,1923
5
6
  phg/vis/GCU.dll,sha256=k_slWZ5nOzZNi9zCe0_SKc0F7zXoLyRuRDomyirPY4I,2687488
@@ -11,11 +12,11 @@ phg/vis/pycoder.exe,sha256=joyuVRBleLmOsxQjaq1iauHxC0BbQGKf8Mnwmx4xrVA,61440
11
12
  phg/vis/script.phg,sha256=HfEBk9omTAfm-KywupQwAwqgHqsr5hCS0f7gfBH1mYY,123
12
13
  phg/vis/sqlite3.dll,sha256=pTf_jpQLK7vaDLipxp4qhPB_MkByPgC-RKXTmmKiy_w,1066496
13
14
  phg/vis/vis.exe,sha256=9LGgETiO4lwhz_gJzdUg6gPP9EwGLT5SuLjN3wR2sso,1388032
14
- phg/vis/vis.ini,sha256=bmF3_kgbLAkiNBQi0ErDE9laZjvOmUSb9GQAISV8qeA,161
15
+ phg/vis/vis.ini,sha256=IjS0Av2BqresPR2oGCOoq5zliXN2wFRMK3rXcU15vKs,161
15
16
  phg/vis/zlib1.dll,sha256=oVw_r326ve3oveVZhlSiF8BloZQ6lfqXJEAhUYfMjOQ,89088
16
17
  phg/vis/imgui/main.lua,sha256=AIB5dpGrPHXuRiNW7Bg7eu5Lpi2DDcn6n4JS7OS1Hdk,4742
17
- phg_vis-1.3.0.dist-info/LICENSE,sha256=tDnRkJxBYPzWdfh2gArRqrUPJxQZRZHJVs68qqBHIq4,1083
18
- phg_vis-1.3.0.dist-info/METADATA,sha256=WojwMRgNuv5I1tbH0VosycYadyq1KQwhUkNNDZZ6mYA,14855
19
- phg_vis-1.3.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
20
- phg_vis-1.3.0.dist-info/top_level.txt,sha256=5GGhpTP8yi-zTXwW2HrI-zcxKxIM_nHXhL7r0iIDE_k,4
21
- phg_vis-1.3.0.dist-info/RECORD,,
18
+ phg_vis-1.3.2.dist-info/LICENSE,sha256=tDnRkJxBYPzWdfh2gArRqrUPJxQZRZHJVs68qqBHIq4,1083
19
+ phg_vis-1.3.2.dist-info/METADATA,sha256=gMSdSe_22WeBMCBSxhLdpIYV4EbiP7NhJPVf_FnKQKU,17945
20
+ phg_vis-1.3.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
21
+ phg_vis-1.3.2.dist-info/top_level.txt,sha256=5GGhpTP8yi-zTXwW2HrI-zcxKxIM_nHXhL7r0iIDE_k,4
22
+ phg_vis-1.3.2.dist-info/RECORD,,