From 47dbd8f0778ba7c1f4b6f58181f94ee73c17b4df Mon Sep 17 00:00:00 2001 From: ThaHobbyist Date: Tue, 31 Dec 2024 17:32:57 +0530 Subject: [PATCH 1/8] Completed Edge implementation for blockMesh --- __init__.py | 55 +-- lib/global_properties.py | 70 ++++ ...dge_operators.py => edge_operators_old.py} | 2 +- ...rators.py => edges_panel_operators_old.py} | 0 models/edge_gen_algorithms.py | 143 ++++++++ models/edges_panel_operators.py | 315 ++++++++++++++++++ models/run_panel_operators.py | 38 ++- views/mainpanel/view.py | 75 ++++- views/schemas/UIList_schemas.py | 23 +- 9 files changed, 692 insertions(+), 29 deletions(-) rename models/blockmesh/{edge_operators.py => edge_operators_old.py} (99%) rename models/blockmesh/{edges_panel_operators.py => edges_panel_operators_old.py} (100%) create mode 100644 models/edge_gen_algorithms.py create mode 100644 models/edges_panel_operators.py diff --git a/__init__.py b/__init__.py index 0cc6517..09bc8d0 100755 --- a/__init__.py +++ b/__init__.py @@ -46,7 +46,7 @@ VNT_OT_edge_data_control, VNT_OT_boundary_data_control, ) -from venturial.models.blockmesh.edge_operators import * +# from venturial.models.blockmesh.edge_operators import * from venturial.models.tutorials_menu_operators import * # from venturial.models.geometry_designer_operators import * @@ -74,7 +74,9 @@ from venturial.lib.update_methods import * from venturial.lib.preferences_properties import VNT_user_preferences_collection -from venturial.lib.global_properties import VNT_global_properties_collection +from venturial.lib.global_properties import VNT_global_properties_collection, VNT_global_properties_collection_edge_verts, CUSTOM_LocProps + +from venturial.models.edges_panel_operators import * classes = ( VNT_user_preferences_collection, @@ -118,11 +120,15 @@ VNT_MT_about_venturial, VNT_MT_about_fossee, VNT_MT_help_menu, + CUSTOM_LocProps, + VNT_global_properties_collection_edge_verts, VNT_global_properties_collection, VNT_UL_mesh_file_manager, VNT_UL_mesh_file_coroner, CUSTOM_UL_blocks, CUSTOM_UL_faces, + CUSTOM_UL_edges_Main, + CUSTOM_UL_edges_Sub, VNT_OT_faceactions, VNT_OT_set_face_name, VNT_OT_set_type_face, @@ -150,14 +156,19 @@ VNT_OT_vertex_data_control, VNT_OT_edge_data_control, VNT_OT_boundary_data_control, - VNT_OT_generate_edge, - VNT_OT_edit_edge, - VNT_OT_destroy_edge, + # VNT_OT_generate_edge, + # VNT_OT_edit_edge, + # VNT_OT_destroy_edge, VNT_OT_more_tutorials_viewer, VNT_OT_tutorial_viewer, VNT_PT_filter_tutorials, VNT_PT_filter_recents, VNT_OT_active_project_indicator, + OBJECT_OT_add_single_vertex, + VNT_OT_new_edge, + VNT_OT_new_vert, + VNT_OT_remove_edge, + VNT_OT_remove_vert, ) @@ -342,6 +353,16 @@ def register(): bpy.types.Scene.fcustom = CollectionProperty(type=VNT_global_properties_collection) bpy.types.Scene.fcustom_index = IntProperty() + bpy.types.Scene.ecustom = CollectionProperty(type=VNT_global_properties_collection_edge_verts) + bpy.types.Scene.ecustom_index = IntProperty() + + bpy.types.Scene.vert_index = IntProperty(name="Vertex Index", default=0) + + # Temporary Vertex Properties. To be changed later + bpy.types.Scene.vertx = FloatProperty(name="X", default=0.0) + bpy.types.Scene.verty = FloatProperty(name="Y", default=0.0) + bpy.types.Scene.vertz = FloatProperty(name="Z", default=0.0) + bpy.types.Scene.edge_control_methods = EnumProperty( items=[("IP", "Interpolation Points", ""), ("AA", "Axis angle", "")], default="IP", @@ -349,10 +370,10 @@ def register(): bpy.types.Scene.curve_type = EnumProperty( items=[ - ("ARC", "Arc", "", "SPHERECURVE", 0), - ("POLYLINE", "Polyline", "", "LINCURVE", 1), - ("SPLINE", "Spline", "", "SMOOTHCURVE", 2), - ("BSPLINE", "Bspline", "", "ROOTCURVE", 3), + ("ARC", "Arc", "Arc type of edge"), + ("PLY", "Polyline", "Polyline type of edge"), + ("SPL", "Spline", "Spline type of edge"), + ("BSPL", "BSpline", "BSpline type of edge"), ], default="ARC", ) @@ -405,16 +426,6 @@ def register(): default=1, ) - bpy.types.Scene.edgelist = EnumProperty( - description="Type of Edge (pre-defined)", - items=[ - ("arc", "arc", "", "SPHERECURVE", 0), - ("polyLine", "polyLine", "", "LINCURVE", 1), - ("spline", "spline", "", "SMOOTHCURVE", 2), - ("BSpline", "BSpline", "", "ROOTCURVE", 3), - ], - ) - bpy.types.Scene.face_sel_mode = BoolProperty(default=False, update=update_face_mode) bpy.types.Scene.statistics = BoolProperty(default=False) @@ -554,6 +565,12 @@ def unregister(): del bpy.types.Scene.vcustom_index del bpy.types.Scene.fcustom del bpy.types.Scene.fcustom_index + del bpy.types.Scene.ecustom + del bpy.types.Scene.ecustom_index + del bpy.types.Scene.vert_index + del bpy.types.Scene.vertx + del bpy.types.Scene.verty + del bpy.types.Scene.vertz del bpy.types.Scene.cnt del bpy.types.Scene.mode del bpy.types.Scene.bdclist diff --git a/lib/global_properties.py b/lib/global_properties.py index 3e64fb0..2c3fa9e 100755 --- a/lib/global_properties.py +++ b/lib/global_properties.py @@ -6,9 +6,49 @@ PointerProperty, CollectionProperty, EnumProperty) +import bpy from bpy.types import PropertyGroup +class CUSTOM_LocProps(bpy.types.PropertyGroup): + vert_loc: FloatVectorProperty(name='verts') + +def color_change(self,context): + return + +def size_change(self,context): + return + +class VNT_global_properties_collection_edge_verts(bpy.types.PropertyGroup): + vert_collection: CollectionProperty( + name = "Vert Collection", + type = CUSTOM_LocProps) + vertex_col: CollectionProperty( + name = "Vert Collection for changing and storing intermediate values", + type = CUSTOM_LocProps) + vc: CollectionProperty( + name = "Storing intermediate values", + type = CUSTOM_LocProps) + color : FloatVectorProperty( + name = "Color Picker", + subtype = "COLOR", + size = 4, + min = 0.0, + max = 1.0, + default = (1.0,1.0,1.0,1.0), + update = color_change) + size : IntProperty(name="size",default=1,min=1,max=5,update=size_change) + edge_type: EnumProperty( + name="Edge Types", + description="Types of edges supported by OpenFOAM", + items=[ + ("ARC", "Arc", "Arc type of edge"), + ("PLY", "Polyline", "Polyline type of edge"), + ("SPL", "Spline", "Spline type of edge"), + ("BSPL", "BSpline", "BSpline type of edge"), + ], + ) + class VNT_global_properties_collection(PropertyGroup): vertindex : StringProperty() @@ -75,3 +115,33 @@ class VNT_global_properties_collection(PropertyGroup): faceindex : StringProperty() blkindex: StringProperty() + vert_collection: CollectionProperty( + name = "Vert Collection", + type = CUSTOM_LocProps) + vertex_col: CollectionProperty( + name = "Vert Collection for changing and storing intermediate values", + type = CUSTOM_LocProps) + vc: CollectionProperty( + name = "Storing intermediate values", + type = CUSTOM_LocProps) + color : FloatVectorProperty( + name = "Color Picker", + subtype = "COLOR", + size = 4, + min = 0.0, + max = 1.0, + default = (1.0,1.0,1.0,1.0), + update = color_change) + size : IntProperty(name="size",default=1,min=1,max=5,update=size_change) + + edge_type: EnumProperty( + name="Edge Types", + description="Types of edges supported by OpenFOAM", + items=[ + ("ARC", "Arc", "Arc type of edge"), + ("PLY", "Polyline", "Polyline type of edge"), + ("SPL", "Spline", "Spline type of edge"), + ("BSPL", "BSpline", "BSpline type of edge"), + ], + ) + edge_verts: CollectionProperty(type=VNT_global_properties_collection_edge_verts) \ No newline at end of file diff --git a/models/blockmesh/edge_operators.py b/models/blockmesh/edge_operators_old.py similarity index 99% rename from models/blockmesh/edge_operators.py rename to models/blockmesh/edge_operators_old.py index 1704d40..3bf3c0c 100755 --- a/models/blockmesh/edge_operators.py +++ b/models/blockmesh/edge_operators_old.py @@ -26,7 +26,7 @@ def generate_arc(self, context, obj): def generate_polyline(self, context, obj): print("generate polyline") - + def generate_spline(self, context, obj): print("generate spline") diff --git a/models/blockmesh/edges_panel_operators.py b/models/blockmesh/edges_panel_operators_old.py similarity index 100% rename from models/blockmesh/edges_panel_operators.py rename to models/blockmesh/edges_panel_operators_old.py diff --git a/models/edge_gen_algorithms.py b/models/edge_gen_algorithms.py new file mode 100644 index 0000000..2cb894f --- /dev/null +++ b/models/edge_gen_algorithms.py @@ -0,0 +1,143 @@ +import numpy as np + +def generate_catmull_rom_curve(resolution, points): + """ + Generate a Catmull-Rom spline curve. + + :param resolution: Number of points to interpolate between each segment. + :param points: List of interpolation points [(x, y, z), ...]. Minimum 3 points. + :return: List of points [(x, y, z), ...] representing the generated curve. + """ + if len(points) < 3: + raise ValueError("At least 3 points are required for Catmull-Rom interpolation.") + + def catmull_rom_point(p0, p1, p2, p3, t): + """ + Compute a point on the Catmull-Rom spline. + + :param p0: Control point 0. + :param p1: Control point 1 (start of the segment). + :param p2: Control point 2 (end of the segment). + :param p3: Control point 3. + :param t: Parameter t in [0, 1]. + :return: Interpolated point (x, y, z). + """ + t2 = t * t + t3 = t2 * t + + # Basis matrix coefficients + c0 = -0.5 * t3 + t2 - 0.5 * t + c1 = 1.5 * t3 - 2.5 * t2 + 1.0 + c2 = -1.5 * t3 + 2.0 * t2 + 0.5 * t + c3 = 0.5 * t3 - 0.5 * t2 + + # Compute interpolated point + x = c0 * p0[0] + c1 * p1[0] + c2 * p2[0] + c3 * p3[0] + y = c0 * p0[1] + c1 * p1[1] + c2 * p2[1] + c3 * p3[1] + z = c0 * p0[2] + c1 * p1[2] + c2 * p2[2] + c3 * p3[2] + + return (x, y, z) + + # List to store the generated curve points + curve_points = [] + + # Iterate over segments defined by points + for i in range(len(points) - 1): + # Define control points + p0 = points[i - 1] if i > 0 else points[i] + p1 = points[i] + p2 = points[i + 1] + p3 = points[i + 2] if i + 2 < len(points) else points[i + 1] + + # Generate points for the segment + for j in range(resolution): + t = j / resolution + curve_points.append(catmull_rom_point(p0, p1, p2, p3, t)) + + # Add the last point + curve_points.append(points[-1]) + + return curve_points + +def generate_arc_curve(resolution, points): + """ + Generate points representing an arc of a circle passing through three points in 3D space. + + Parameters: + p1: tuple of floats (x1, y1, z1) - First fixed point. + p2: tuple of floats (x2, y2, z2) - Control point. + p3: tuple of floats (x3, y3, z3) - Second fixed point. + resolution: int - Number of points in the output arc. + + Returns: + List of tuples representing points on the arc. + """ + # Convert points to numpy arrays + p1 = np.array(points[0]) + p2 = np.array(points[1]) + p3 = np.array(points[2]) + + # Find the plane normal + v1 = p2 - p1 + v2 = p3 - p1 + normal = np.cross(v1, v2) + normal = normal / np.linalg.norm(normal) + + # Calculate the circle center and radius + def find_circle_center(p1, p2, p3): + mid1 = (p1 + p2) / 2 + mid2 = (p2 + p3) / 2 + + normal1 = np.cross(p2 - p1, normal) + normal2 = np.cross(p3 - p2, normal) + + # Set up linear equations to solve for center + A = np.array([normal1, -normal2]) + b = np.array([np.dot(normal1, mid1), np.dot(normal2, mid2)]) + + try: + center = np.linalg.lstsq(A.T, b, rcond=None)[0] + except np.linalg.LinAlgError: + raise ValueError("The points do not define a unique circle.") + return center + + center = find_circle_center(p1, p2, p3) + radius = np.linalg.norm(p1 - center) + + # Generate points on the arc + def angle_between(v1, v2): + """Calculate the angle between two vectors.""" + v1_u = v1 / np.linalg.norm(v1) + v2_u = v2 / np.linalg.norm(v2) + return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0)) + + v_start = p1 - center + v_end = p3 - center + + theta_start = 0 + theta_end = angle_between(v_start, v_end) + + # Determine direction of rotation + if np.dot(np.cross(v_start, v_end), normal) < 0: + theta_end = -theta_end + + theta = np.linspace(theta_start, theta_end, resolution) + + arc_points = [] + for t in theta: + point = (center + np.cos(t) * v_start + np.sin(t) * np.cross(normal, v_start)) + arc_points.append(tuple(point)) + + return arc_points + + +# Example usage +# interpolation_points = [ +# (0.0, 0.0, 0.0), +# (1.0, 2.0, 0.0), +# (4.0, 2.0, 0.0), +# (7.0, 0.0, 0.0) +# ] +# resolution = 10 +# curve = generate_catmull_rom_curve(resolution, interpolation_points) +# print(curve) diff --git a/models/edges_panel_operators.py b/models/edges_panel_operators.py new file mode 100644 index 0000000..84063a0 --- /dev/null +++ b/models/edges_panel_operators.py @@ -0,0 +1,315 @@ +import bpy +from bpy.types import Operator +import bmesh, time +import numpy as np +import bgl +import gpu +from gpu_extras.batch import batch_for_shader +from bpy_extras import object_utils + +from venturial.models.edge_gen_algorithms import * + +a = [None, ] +verts = [] +def sync(self): + try: + for i in range(len(bpy.context.scene.ecustom)): + for j in range(100): + bpy.context.scene.ecustom[i].vertex_col[j].vert_loc = verts[i][j] + except Exception as e: + print(f"exception in sync ------> {e}") + return + +class OBJECT_OT_add_single_vertex(Operator): + bl_idname = "mesh.add_single_vertex" + bl_label = "Add Single Vertex" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + mesh = bpy.data.meshes.new("Vert") + mesh.vertices.add(1) + + object_utils.object_data_add(context, mesh, operator=None) + bpy.ops.object.mode_set(mode='EDIT') + + return {'FINISHED'} + +class VNT_OT_new_edge(Operator): + ''' + Generate custom edge type for the selected edge + ''' + + bl_idname = "vnt.new_edge" + bl_label = "Generate Edge" + + def execute(self, context): + a.append(None) + verts.append([]) + + cs = context.scene + edg = cs.ecustom.add() + index = len(cs.ecustom) - 1 + a[index] = None + verts[index] = [] + + edg.name = str(time.time()) + edg.edge_type = cs.curve_type + + for i in range(100): + edg.vertex_col.add() + return{'FINISHED'} + +class VNT_OT_new_vert(Operator): + ''' + Generate new vertex for the selected edge + ''' + + bl_idname = "vnt.new_vert" + bl_label = "Generate new Vertex" + + def execute(self, context): + cs = context.scene + try: + self.index = cs.ecustom_index + self.curr_edge = cs.ecustom[int(self.index)] + + except Exception as e: + print(e) + self.report({'ERROR'}, 'No spline selected to add vertex') + return {'CANCELLED'} + + if(len(self.curr_edge.vert_collection) == 0): + self.first(context) + else: + self.n_first(context) + + draw_p(self, context) + sync(self) + return {'FINISHED'} + + def first(self, context): + cs = context.scene + print("Executing first") + try: + bpy.ops.object.mode_set( mode = 'EDIT' ) + selectedEdges = [] + + selectedEdges = [i for i in bmesh.from_edit_mesh(context.active_object.data).edges if i.select] + + if len(selectedEdges) > 1: + self.report({'ERROR', 'Please select only one edge'}) + return + if len(selectedEdges) < 1: + self.report({'ERROR', 'Please select an edge'}) + return + + context.space_data.show_gizmo_object_translate = True + g = context.active_object.matrix_world + + x = g @ selectedEdges[0].verts[0].co + y = g @ selectedEdges[0].verts[1].co + except Exception: + return + + for i in range(3): + self.curr_edge.vc.add() + + self.curr_edge.vc[0].vert_loc=x + self.curr_edge.vc[2].vert_loc=y + # coord = [None, None, None] + + # for i in range(3): + # coord[i] = (x[i] + y[i])/1.5 + + coord = [cs.vertx, cs.verty, cs.vertz] + + self.curr_edge.vert_collection.add() + self.curr_edge.vert_collection[0].vert_loc=coord + self.curr_edge.vc[1].vert_loc=coord + print(coord) + + bpy.ops.object.mode_set(mode='OBJECT') + # bpy.ops.mesh.primitive_vert_add() # to be changed + bpy.ops.mesh.add_single_vertex() + bpy.ops.object.mode_set(mode='OBJECT') + + vertex = context.selected_objects[0] + vertex.location = coord + vertex.name = f"{self.curr_edge.name}01" + vertex=0 + + def n_first(self, context): + print("Executing n_first") + context.space_data.show_gizmo_object_translate = True + len1 = len(self.curr_edge.vertex_col) + + self.curr_edge.vert_collection.add() + length = len(self.curr_edge.vert_collection) + + for i in range(length): + self.curr_edge.vert_collection[i].vert_loc = (self.curr_edge.vertex_col[(i+1)*len1//(length+1)].vert_loc) + + bpy.ops.object.mode_set( mode='OBJECT' ) + # bpy.ops.mesh.primitive_vert_add() # to be changed + bpy.ops.mesh.add_single_vertex() + bpy.ops.object.mode_set( mode='OBJECT' ) + + vertex = bpy.context.selected_objects[0] + vertex.name = f"{self.curr_edge.name}0{length}" + + for i in range(length): + _a_ = bpy.data.objects[f"{self.curr_edge.name}0{i+1}"] + _a_.location = self.curr_edge.vert_collection[i].vert_loc + +class VNT_OT_remove_edge(Operator): + ''' + Remove the selected edge + ''' + + bl_idname = "vnt.remove_edge" + bl_label = "Remove Edge" + + def execute(self, context): + cs = context.scene + try: + index = cs.ecustom_index + cur_spline = cs.ecustom[index] + + except Exception as e: + self.report({'ERROR'}, 'No spline selected to remove') + return {'CANCELLED'} + + for i in range(len(cur_spline.vert_collection)-1, -1, -1): + bpy.data.objects.remove(bpy.data.object[f"{cur_spline.name}0{i+1}"], do_unlink=True) + cur_spline.vert_collection.remove(i) + + cs.ecustom.remove(int(index)) + + try: + bpy.types.SpaceView3D.draw_handler_remove(a[index], 'WINDOW') + except Exception as e: + pass + + a[index] = None + verts[index] = [] + index = index - 1 + + draw_p(self, context) + return {'FINISHED'} + +class VNT_OT_remove_vert(Operator): + ''' + Remove the selected Vertex + ''' + + bl_idname = "vnt.remove_vert" + bl_label = "Remove Vertex" + + def execute(self, context): + cs = context.scene + try: + index = cs.ecustom_index + + r_index = len(cs.ecustom[index].vert_collection) - 1 + + cs.ecustom[int(index)].vert_collection.remove(int(r_index)) + self.index = cs.ecustom_index + self.curr_edge = cs.ecustom[int(self.index)] + except Exception as e: + self.report({'ERROR'}, 'No spline selected to remove vertex from') + return {'CANCELLED'} + + bpy.data.objects.remove(bpy.data.objects[f"{self.curr_edge.name}0{r_index+1}"], do_unlink=True) + len1 = len(self.curr_edge.vertex_col) + length = len(self.curr_edge.vert_collection) + for i in range(length): + self.curr_edge.vert_collection[i].vert_loc=(self.curr_edge.vertex_col[(i+1)*len1//(length+1)].vert_loc) + for i in range(length): + _a_ = bpy.data.objects[f"{self.curr_edge.name}0{i+1}"] + _a_.location = self.curr_edge.vert_collection[i].vert_loc + + if len(cs.ecustom[int(index)].vert_collection) == 0: + cs.ecustom.remove(int(index)) + try: + bpy.types.SpaceView3D.draw_handler_remove(a[index], 'WINDOW') + except Exception as e: + pass + + a[index] = None + verts[index] = [] + index = index - 1 + + draw_p(self, context) + return {'FINISHED'} + +def draw_p(self, context): + ''' + Draws spline using cubic spline interpolation + Algorithm to be changed + ''' + cs = context.scene + for i in range(len(cs.ecustom)): + if a[i] != None: + try: + bpy.types.SpaceView3D.draw_handler_remove(a[i], 'WINDOW') + except Exception as e: + pass + + if (len(cs.ecustom[i].vert_collection) == 0): + break + + verts[i] = [] + for j in range(len(cs.ecustom[i].vert_collection)): + ax = bpy.data.objects[f"{cs.ecustom[i].name}0{j+1}"] + verts[i].append(ax.location) + lin1 = [] + + _a = cs.ecustom[i].vc[0].vert_loc[:] + verts[i].insert(0, _a) + _a = cs.ecustom[i].vc[2].vert_loc[:] + verts[i].append(_a) + + _temp = len(verts[i]) + for k in range(_temp): + lin1.append(int(k*100/(_temp -1 ))) + + # print(f"------> {lin1}") + # print(f"------> {verts[i]}") + # cubic_spline = CubicSpline(lin1, verts[i]) + # print(f"------> {cs.ecustom[i].edge_type}") + curve_p = [] + + ''' # This Piece of code is to be implemented when there is point generating alorithms for each edge type + if cs.ecustom[i].edge_type == 'SPL': + print("Using Splien Gen") + curve_p = generate_catmull_rom_curve(100, verts[i]) + elif cs.ecustom[i].edge_type == 'ARC': + print("Using ARC Gen") + curve_p = generate_catmull_rom_curve(100, verts[i]) + else: + print("Edge type yet to implement") + ''' + curve_p = generate_catmull_rom_curve(100, verts[i]) # To be replaced with previous code block once all spline generating algorithms are implemented + + # print(f"------> {catmull_p}") + + # lin = [] + # lin = np.linspace(0, 100, 101) + # verts[i] = [i for i in catmull_p(lin)] + verts[i] = curve_p + + a[i] = bpy.types.SpaceView3D.draw_handler_add(draw1, ((verts[i], i)), 'WINDOW', 'POST_VIEW') + +def draw1(verts, index): + try: + curr_spline = bpy.context.scene.ecustom[index] + except Exception as e: + return + + shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') + bgl.glLineWidth(curr_spline.size) + col = (curr_spline.color[0], curr_spline.color[1], curr_spline.color[2], curr_spline.color[3]) + batch = batch_for_shader(shader, 'LINE_STRIP', {'pos': verts}) + shader.bind() + shader.uniform_float('color', col) + batch.draw(shader) \ No newline at end of file diff --git a/models/run_panel_operators.py b/models/run_panel_operators.py index 179f524..8cce7e8 100755 --- a/models/run_panel_operators.py +++ b/models/run_panel_operators.py @@ -76,11 +76,11 @@ def write_dict(m, out_fp): ename=edg[0]+" "+str(edg[1][0])+" "+str(edg[1][1]) ed=[] if(ename[:3]=="arc"): - blockdict.append(ename+" "+listToOFStr(edg[2])) + blockdict.append(ename+" "+listToOFStr(edg[2][0])) else: for e in edg[2]: ed.append(listToOFStr(e)) - + blockdict.append(ename) blockdict.append("(") for e in ed: @@ -117,6 +117,7 @@ def write_dict(m, out_fp): blockdict.append("}") blockdict.append(");") #--------boundaries end------------ + #-------mergePatchPairs start--------- #todo blockdict.append("mergePatchPairs") @@ -210,11 +211,13 @@ def execute(self, context): bmdict['boundary'].append([i.face_des, i.face_type, face_strtolist(i.name)]) # Add Edges(arc, polyLine, spline, BSpline) to Dictionary - cp_edge_list = [scn.acustom, scn.pcustom, scn.scustom, scn.bscustom] - edge_type = ["arc", "polyLine", "spline", "BSpline"] + # cp_edge_list = [scn.acustom, scn.pcustom, scn.scustom, scn.bscustom] + # cp_edge_list = [scn.ecustom] + # edge_type = ["arc", "polyLine", "spline", "BSpline"] - for ix in range(0, len(cp_edge_list)): - + for ix in range(0, len(scn.ecustom)): # change the way edges are stored + + ''' Old code if ix == 0: for i in cp_edge_list[ix]: bmdict['edges'].append([edge_type[ix], edge_strtolist(i.fandl), [i.intptx, i.intpty, i.intptz]]) @@ -235,6 +238,29 @@ def execute(self, context): for k in range(0, len(ret)): bmdict['edges'].append([edge_type[ix], ret[k], ev[k]]) + ''' + + vert_index = [] + edge = scn.ecustom[ix] + + # Check type from edge.type + # Get indices for each vert in edge.vc + # Add the vertices into a list from edge.vert_collection + edge_type = { + "ARC": "arc", + "PLY": "polyLine", + "SPL": "spline", + "BSPL": "BSpline" + } + + e_type = edge_type[edge.edge_type] + + vert_index.append(bmdict["vertices"].index(list(edge.vc[0].vert_loc))) + vert_index.append(bmdict["vertices"].index(list(edge.vc[2].vert_loc))) + + e_verts = [list(v.vert_loc) for v in edge.vert_collection] + bmdict["edges"].append([e_type, vert_index, e_verts]) + m = json.dumps(bmdict, sort_keys=True, indent=2) text_obj.from_string(m) diff --git a/views/mainpanel/view.py b/views/mainpanel/view.py index 9b31d2f..e45aede 100755 --- a/views/mainpanel/view.py +++ b/views/mainpanel/view.py @@ -1,6 +1,6 @@ from venturial.models.header.file_handling_operators import * from venturial.models.blockmesh.design_operators import * -from venturial.models.blockmesh.edge_operators import * +# from venturial.models.blockmesh.edge_operators import * from venturial.models.blockmesh.boundary_control_operators import * from venturial.models.run_panel_operators import * from venturial.utils.custom_icon_object_generator import * @@ -9,7 +9,9 @@ from venturial.views.mainpanel.recents import recents_menu from venturial.views.mainpanel.meshing_tools.blockmesh import blockmesh_menu from venturial.views.mainpanel.meshing_tools.snappyhexmesh import snappyhexmesh_menu +from venturial.models.edges_panel_operators import * +import blf import time, bpy @@ -147,7 +149,7 @@ def VNT_ST_visualize(self, layout, context): getattr(visualizer_menu(), "edge_visualizer")(edge_outline, context) getattr(visualizer_menu(), "boundary_visualizer")(boundary_outline, context) - def VNT_ST_edges(self, layout, context): + def VNT_ST_edges_old(self, layout, context): cs = context.scene layout = layout.box() @@ -189,6 +191,75 @@ def VNT_ST_edges(self, layout, context): b.operator(VNT_OT_destroy_edge.bl_idname, icon="TRASH") b.alert = False + def VNT_ST_edges(self, layout, context): + ''' + Code for the edge tab in the addon tab + ''' + + vert_ = None + + def draw_loc(context): + """ + Draws the location of the selected vertex + """ + cs = context.scene + if vert_ != None: + print("removed") + bpy.types.SpaceView3D.draw_handler_remove(vert_, 'WINDOW') + + if len(cs.ecustom) and vert_ == None: + idx = cs.ecustom_index + idx_v = len(cs.ecustom[idx].vert_collection) + + if idx_v >= 1: + a = bpy.data.objects[f"{cs.ecustom[idx].name}0{(idx_v//2)+1}"].location + + # def draw_vertex_properties(context, idx, a): + # text_pos = view3d.location_3d_to_region_2d(context.region, context.space_data.region_3d, a) + # blf.position(0, text_pos[0], text_pos[1], 0) + # blf.size(0, 50, 50) + # blf.color(0,255,255,255,125) + # blf.draw(0, f"Spline{idx}") + + cs = context.scene + ec = cs.ecustom + min_rows = 3 + row = layout.row() + + split = layout.split(factor=0.2) + split.template_list("CUSTOM_UL_edges_Main","", cs, "ecustom", cs, "ecustom_index", rows=min_rows) + + if len(ec) > 0 and cs.ecustom_index != -1: + user = ec[cs.ecustom_index] + split.template_list( + listtype_name = "CUSTOM_UL_edges_Sub", + list_id = "", + dataptr = user, + propname = "vert_collection", + active_dataptr = cs, + active_propname = "ecustom_index", + rows = min_rows + ) + + row1 = layout.row() + draw_p(self, context) + row1.operator('vnt.new_edge') + row1.prop(cs, "curve_type") + row1.operator('vnt.remove_edge') + row2 = layout.row() + row2.operator('vnt.new_vert') + row2.operator('vnt.remove_vert') + row3 = layout.row(align=True) + row3.label(text="Vertex Coordinates") + row3.prop(cs, "vertx") + row3.prop(cs, "verty") + row3.prop(cs, "vertz") + + if len(ec): + layout.prop(ec[cs.ecustom_index], "color") + layout.prop(ec[cs.ecustom_index], "size") + draw_loc(context) + def VNT_ST_boundary(self, layout, context): cs = context.scene layout=layout.box() diff --git a/views/schemas/UIList_schemas.py b/views/schemas/UIList_schemas.py index 1950fde..abb1657 100755 --- a/views/schemas/UIList_schemas.py +++ b/views/schemas/UIList_schemas.py @@ -1,3 +1,4 @@ +import bpy from bpy.types import (UIList, PropertyGroup) from bpy.props import StringProperty, BoolProperty, IntProperty, EnumProperty #from venturial.models.header.file_handling_operators import VNT_OT_deactivate_mesh_file_item @@ -164,7 +165,8 @@ def draw_item(self, context, layout, data, item, icon, active_data, active_propn def invoke(self, context, event): pass - + +''' class CUSTOM_UL_edges(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): split = layout.row() @@ -174,5 +176,24 @@ def draw_item(self, context, layout, data, item, icon, active_data, active_propn split.prop(item, "intptz", text="", emboss=True, translate=False) split.prop(item, "enabled", text="", index=index) + def invoke(self, context, event): + pass +''' + +class CUSTOM_UL_edges_Main(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + row = layout.row() + row.label(text=f"Edge {index}") + row.prop(item, "edge_type", text="") + + def invoke(self, context, event): + pass + +class CUSTOM_UL_edges_Sub(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + sr = f"{context.scene.ecustom[context.scene.ecustom_index].name}0{index+1}" + ob = bpy.data.objects[sr] + layout.prop(ob, 'location') + def invoke(self, context, event): pass \ No newline at end of file From 7cd9ef9d02b65c285578ef67e596d763ea3288e5 Mon Sep 17 00:00:00 2001 From: ThaHobbyist Date: Thu, 16 Jan 2025 12:08:22 +0530 Subject: [PATCH 2/8] Implemented Algorithms for viewing different kinds of edges --- models/edge_gen_algorithms.py | 239 ++++++++++++++++++++++---------- models/edges_panel_operators.py | 38 +++-- 2 files changed, 191 insertions(+), 86 deletions(-) diff --git a/models/edge_gen_algorithms.py b/models/edge_gen_algorithms.py index 2cb894f..66fc830 100644 --- a/models/edge_gen_algorithms.py +++ b/models/edge_gen_algorithms.py @@ -59,85 +59,174 @@ def catmull_rom_point(p0, p1, p2, p3, t): return curve_points +def generate_arc_curve_og(resolution, points): + + if len(points) != 3: + raise ValueError("Exactly 3 points are required for Arc interpolation.") + + print(f"points ----------> {points}") + A = np.array(points[0]) # end point + B = np.array(points[1]) # handler point + C = np.array(points[2]) # end point + + def mod(v): + return np.sqrt(v[0]**2 + v[1]**2 + v[2]**2) + + u1 = (B-A) + + u = u1/mod(u1) + + w1 = np.cross(C-A, u1) + + w = w1/mod(w1) + + v = np.cross(w,u) + + b = (np.dot(B-A, u), 0) + + c = (np.dot(C-A, u), np.dot(C-A, v)) + + h = ( (c[0] - b[0]/2)**2 + c[1]**2 - (b[0]/2)**2 ) / ( 2 * c[1] ) + + Cn = A + ((b[0]/2) * u ) + (h * v) # center of the circle + + r = mod(Cn - A) # Radius of the circle + + axis = np.cross((B-A)/mod(B-A), (C-A)/mod(C-A)) + a = u + b = np.cross(axis, a) + + def arc_point(t, c, a, b, r): + return ( + c[0] + r*np.cos(t)*a[0] + r*np.sin(t)*b[0], + c[1] + r*np.cos(t)*a[1] + r*np.sin(t)*b[1], + c[2] + r*np.cos(t)*a[2] + r*np.sin(t)*b[2] + ) + + def get_arc_param(p, c, a, b, r): + k = (p[0] - c[0]) / r + R = np.sqrt(a[0]**2 + b[0]**2) + phi = np.arctan2(b[0], a[0]) + t = np.arcsin(k / R) - phi + + return t + + t1 = get_arc_param(A, Cn, a, b, r) + t2 = get_arc_param(C, Cn, a, b, r) + + e2 = 0 + e1 = 0 + if t2>t1: + e2 = t2 + e1 = t1 + else: + e2 = t1 + e1 = t2 + + d = (e2 - e1) / resolution + + curve_points = [] + i = e1 + while i <= e2: + curve_points.append(arc_point(i, Cn, a, b, r)) + i += d + + print("Completed ARC Generation") + print(f"curve_points ----------> {curve_points}") + + return curve_points + def generate_arc_curve(resolution, points): + if len(points) != 3: + raise ValueError("Exactly 3 points are required for Arc interpolation.") + + # Extract points + A = np.array(points[0]) # Start point + B = np.array(points[1]) # Control point + C = np.array(points[2]) # End point + + def normalize(v): + return v / np.linalg.norm(v) + + # Basis vectors + u = normalize(B - A) + w = normalize(np.cross(C - A, B - A)) + v = np.cross(w, u) + + # Calculate intermediate parameters + b_u = np.dot(B - A, u) + c_u = np.dot(C - A, u) + c_v = np.dot(C - A, v) + + # Compute circle center and radius + h = ((c_u - b_u / 2) ** 2 + c_v ** 2 - (b_u / 2) ** 2) / (2 * c_v) + Cn = A + (b_u / 2) * u + h * v + r = np.linalg.norm(Cn - A) + + # Calculate angle parameters for the arc + def get_arc_param(p): + dp = p - Cn + return np.arctan2(np.dot(dp, v), np.dot(dp, u)) + + t1 = get_arc_param(A) + t2 = get_arc_param(C) + + # Ensure angles are ordered correctly + if t2 < t1: + t1, t2 = t2, t1 + + # Generate arc points + t_values = np.linspace(t1, t2, resolution) + curve_points = [ + (Cn + r * np.cos(t) * u + r * np.sin(t) * v).tolist() + for t in t_values + ] + + return curve_points + +def generate_bspline_curve(resolution, verts): """ - Generate points representing an arc of a circle passing through three points in 3D space. + Generate a B-spline curve from given control points. Parameters: - p1: tuple of floats (x1, y1, z1) - First fixed point. - p2: tuple of floats (x2, y2, z2) - Control point. - p3: tuple of floats (x3, y3, z3) - Second fixed point. - resolution: int - Number of points in the output arc. + resolution (int): Number of points to generate on the B-spline curve. + verts (list of list/tuple): Control points (at least 3 points). + verts[0] and verts[-1] are endpoints, and verts[1:-1] are control points. Returns: - List of tuples representing points on the arc. + list: List of points forming the B-spline curve. """ - # Convert points to numpy arrays - p1 = np.array(points[0]) - p2 = np.array(points[1]) - p3 = np.array(points[2]) - - # Find the plane normal - v1 = p2 - p1 - v2 = p3 - p1 - normal = np.cross(v1, v2) - normal = normal / np.linalg.norm(normal) - - # Calculate the circle center and radius - def find_circle_center(p1, p2, p3): - mid1 = (p1 + p2) / 2 - mid2 = (p2 + p3) / 2 - - normal1 = np.cross(p2 - p1, normal) - normal2 = np.cross(p3 - p2, normal) - - # Set up linear equations to solve for center - A = np.array([normal1, -normal2]) - b = np.array([np.dot(normal1, mid1), np.dot(normal2, mid2)]) - - try: - center = np.linalg.lstsq(A.T, b, rcond=None)[0] - except np.linalg.LinAlgError: - raise ValueError("The points do not define a unique circle.") - return center - - center = find_circle_center(p1, p2, p3) - radius = np.linalg.norm(p1 - center) - - # Generate points on the arc - def angle_between(v1, v2): - """Calculate the angle between two vectors.""" - v1_u = v1 / np.linalg.norm(v1) - v2_u = v2 / np.linalg.norm(v2) - return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0)) - - v_start = p1 - center - v_end = p3 - center - - theta_start = 0 - theta_end = angle_between(v_start, v_end) - - # Determine direction of rotation - if np.dot(np.cross(v_start, v_end), normal) < 0: - theta_end = -theta_end - - theta = np.linspace(theta_start, theta_end, resolution) - - arc_points = [] - for t in theta: - point = (center + np.cos(t) * v_start + np.sin(t) * np.cross(normal, v_start)) - arc_points.append(tuple(point)) - - return arc_points - - -# Example usage -# interpolation_points = [ -# (0.0, 0.0, 0.0), -# (1.0, 2.0, 0.0), -# (4.0, 2.0, 0.0), -# (7.0, 0.0, 0.0) -# ] -# resolution = 10 -# curve = generate_catmull_rom_curve(resolution, interpolation_points) -# print(curve) + if len(verts) < 3: + raise ValueError("At least 3 control points are required to generate a B-spline.") + + # Define the B-spline basis matrix + basis_matrix = np.array([ + [-1, 3, -3, 1], + [ 3, -6, 3, 0], + [-3, 0, 3, 0], + [ 1, 4, 1, 0] + ]) / 6.0 + + # Ensure verts is a numpy array + verts = np.array(verts) + + # Add extra points at the start and end to handle endpoints properly + extended_verts = np.vstack([verts[0], verts, verts[-1]]) + + # Initialize result list + bspline_points = [verts[0]] + + # Iterate through the segments formed by control points + for i in range(len(extended_verts) - 3): + # Extract 4 control points for the current segment + P = extended_verts[i:i+4] + + # Generate points for the current segment + for j in range(resolution): + t = j / (resolution - 1) # Parameter t in [0, 1] + T = np.array([t**3, t**2, t, 1]) + point = T @ basis_matrix @ P + bspline_points.append(point) + + bspline_points.append(verts[-1]) + return bspline_points diff --git a/models/edges_panel_operators.py b/models/edges_panel_operators.py index 84063a0..02632bd 100644 --- a/models/edges_panel_operators.py +++ b/models/edges_panel_operators.py @@ -279,17 +279,19 @@ def draw_p(self, context): # print(f"------> {cs.ecustom[i].edge_type}") curve_p = [] - ''' # This Piece of code is to be implemented when there is point generating alorithms for each edge type + # This Piece of code is to be implemented when there is point generating alorithms for each edge type if cs.ecustom[i].edge_type == 'SPL': - print("Using Splien Gen") + print("Using Spline Gen") curve_p = generate_catmull_rom_curve(100, verts[i]) elif cs.ecustom[i].edge_type == 'ARC': print("Using ARC Gen") - curve_p = generate_catmull_rom_curve(100, verts[i]) - else: - print("Edge type yet to implement") - ''' - curve_p = generate_catmull_rom_curve(100, verts[i]) # To be replaced with previous code block once all spline generating algorithms are implemented + curve_p = generate_arc_curve(100, verts[i]) + elif cs.ecustom[i].edge_type == 'PLY': + curve_p = verts[i] + elif cs.ecustom[i].edge_type == 'BSPL': + curve_p = generate_bspline_curve(100, verts[i]) + + # curve_p = generate_catmull_rom_curve(100, verts[i]) # To be replaced with previous code block once all spline generating algorithms are implemented # print(f"------> {catmull_p}") @@ -298,18 +300,32 @@ def draw_p(self, context): # verts[i] = [i for i in catmull_p(lin)] verts[i] = curve_p - a[i] = bpy.types.SpaceView3D.draw_handler_add(draw1, ((verts[i], i)), 'WINDOW', 'POST_VIEW') + a[i] = bpy.types.SpaceView3D.draw_handler_add(draw_edge_viewport, ((verts[i], i)), 'WINDOW', 'POST_VIEW') -def draw1(verts, index): +def draw_edge_viewport(verts, index): try: curr_spline = bpy.context.scene.ecustom[index] except Exception as e: return shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') - bgl.glLineWidth(curr_spline.size) + # bgl.glLineWidth(curr_spline.size) + col = (curr_spline.color[0], curr_spline.color[1], curr_spline.color[2], curr_spline.color[3]) + batch = batch_for_shader(shader, 'LINE_STRIP', {'pos': verts}) + + gpu.state.depth_test_set("LESS_EQUAL") + + gpu.state.blend_set("ALPHA") + gpu.state.face_culling_set("BACK") + shader.bind() + shader.uniform_float('color', col) - batch.draw(shader) \ No newline at end of file + + batch.draw(shader) + + gpu.state.blend_set("NONE") + gpu.state.face_culling_set("NONE") + gpu.state.depth_test_set("NONE") \ No newline at end of file From e5bfd3f67c0e32070b2e9b7d92fa92ded7038cb0 Mon Sep 17 00:00:00 2001 From: ThaHobbyist Date: Fri, 17 Jan 2025 17:52:31 +0530 Subject: [PATCH 3/8] Implemented operators for mergePatchPairs in blockMesh --- __init__.py | 17 +++-- lib/global_properties.py | 6 +- .../blockmesh/boundary_control_operators.py | 64 +++++++++++++++++++ models/run_panel_operators.py | 16 +++-- views/mainpanel/view.py | 44 ++++++++----- views/schemas/UIList_schemas.py | 15 ++++- 6 files changed, 135 insertions(+), 27 deletions(-) diff --git a/__init__.py b/__init__.py index 09bc8d0..9716fab 100755 --- a/__init__.py +++ b/__init__.py @@ -129,6 +129,7 @@ CUSTOM_UL_faces, CUSTOM_UL_edges_Main, CUSTOM_UL_edges_Sub, + CUSTOM_UL_face_merge, VNT_OT_faceactions, VNT_OT_set_face_name, VNT_OT_set_type_face, @@ -156,6 +157,8 @@ VNT_OT_vertex_data_control, VNT_OT_edge_data_control, VNT_OT_boundary_data_control, + VNT_OT_merge_faces, + VNT_OT_merge_faces_delete, # VNT_OT_generate_edge, # VNT_OT_edit_edge, # VNT_OT_destroy_edge, @@ -344,16 +347,22 @@ def register(): bpy.types.Scene.simblk = CollectionProperty(type=VNT_global_properties_collection) bpy.types.Scene.simblk_index = IntProperty() - bpy.types.Scene.bcustom = CollectionProperty(type=VNT_global_properties_collection) + bpy.types.Scene.bcustom = CollectionProperty(type=VNT_global_properties_collection) # for blocks bpy.types.Scene.bcustom_index = IntProperty() - bpy.types.Scene.vcustom = CollectionProperty(type=VNT_global_properties_collection) + bpy.types.Scene.vcustom = CollectionProperty(type=VNT_global_properties_collection) # for vertices bpy.types.Scene.vcustom_index = IntProperty() - bpy.types.Scene.fcustom = CollectionProperty(type=VNT_global_properties_collection) + bpy.types.Scene.fcustom = CollectionProperty(type=VNT_global_properties_collection) # for faces bpy.types.Scene.fcustom_index = IntProperty() - bpy.types.Scene.ecustom = CollectionProperty(type=VNT_global_properties_collection_edge_verts) + bpy.types.Scene.faceList_master = EnumProperty("Face List", items=list_current_faces) + bpy.types.Scene.faceList_slave = EnumProperty("Face List", items=list_current_faces) + + bpy.types.Scene.fmcustom = CollectionProperty(type=VNT_global_properties_collection) # for face merging + bpy.types.Scene.fmcustom_index = IntProperty() + + bpy.types.Scene.ecustom = CollectionProperty(type=VNT_global_properties_collection_edge_verts) # for edges bpy.types.Scene.ecustom_index = IntProperty() bpy.types.Scene.vert_index = IntProperty(name="Vertex Index", default=0) diff --git a/lib/global_properties.py b/lib/global_properties.py index 2c3fa9e..6101a41 100755 --- a/lib/global_properties.py +++ b/lib/global_properties.py @@ -10,6 +10,8 @@ from bpy.types import PropertyGroup +from venturial.models.blockmesh.boundary_control_operators import list_current_faces + class CUSTOM_LocProps(bpy.types.PropertyGroup): vert_loc: FloatVectorProperty(name='verts') @@ -69,7 +71,9 @@ class VNT_global_properties_collection(PropertyGroup): min = 0.0, max = 1.0, default = (1.0,1.0,1.0,1.0)) - + + master_face : EnumProperty("Master Face", items=list_current_faces) + slave_face : EnumProperty("Slave Face", items=list_current_faces) b_name: StringProperty() setcellx: IntProperty() diff --git a/models/blockmesh/boundary_control_operators.py b/models/blockmesh/boundary_control_operators.py index 1d4c07e..668e957 100755 --- a/models/blockmesh/boundary_control_operators.py +++ b/models/blockmesh/boundary_control_operators.py @@ -410,3 +410,67 @@ def execute(self, context): else: self.report({'INFO'}, "Nothing to remove") return{'FINISHED'} + +# Operators for mergepatchpairs +class VNT_OT_merge_faces(Operator): + bl_idname = "vnt.merge_faces" + bl_label = "Merge Faces" + bl_description = "Merge selected Faces" + bl_options = {'REGISTER', 'UNDO'} + + def draw(self, context): + layout = self.layout + cs = context.scene + + r1 = layout.row(align=True) + r1.label(text="Master Face:") + r1.prop(cs, "faceList_master") + + r2 = layout.row(align=True) + r2.label(text="Slave:") + r2.prop(cs, "faceList_slave") + + def invoke(self, context, event): + return context.window_manager.invoke_props_dialog(self, width=300) + + def execute(self, context): + cs = context.scene + + if cs.faceList_master == cs.faceList_slave: + self.report({'ERROR'}, "Master and Slave faces cannot be same") + return {'CANCELLED'} + else: + item = cs.fmcustom.add() + item.master_face = cs.faceList_master + item.slave_face = cs.faceList_slave + + return {'FINISHED'} + +class VNT_OT_merge_faces_delete(Operator): + bl_idname = "vnt.merge_faces_delete" + bl_label = "Separate Faces" + bl_description = "Separate selected Face pairs" + bl_options = {'REGISTER', 'UNDO'} + + @classmethod + def poll(cls, context): + return bool(context.scene.fmcustom) + + def invoke(self, context, event): + return context.window_manager.invoke_confirm(self, event) + + def execute(self, context): + if bool(context.scene.fcustom): + context.scene.fmcustom.clear() + self.report({'INFO'}, "All items removed") + else: + self.report({'INFO'}, "Nothing to remove") + return{'FINISHED'} + + + +def list_current_faces(self, context): + items = [] + for i, f in enumerate(context.scene.fcustom): + items.append((str(f.face_des), f.face_des, f"{f.face_des}, {f.name}")) + return items \ No newline at end of file diff --git a/models/run_panel_operators.py b/models/run_panel_operators.py index 8cce7e8..478888d 100755 --- a/models/run_panel_operators.py +++ b/models/run_panel_operators.py @@ -122,6 +122,9 @@ def write_dict(m, out_fp): #todo blockdict.append("mergePatchPairs") blockdict.append("(") + mergePatchPairs=data['mergePatchPairs'] + for mpp in mergePatchPairs: + blockdict.append(f"({mpp[0]} {mpp[1]})") blockdict.append(");") #-------mergePatchPairs end--------- @@ -211,10 +214,11 @@ def execute(self, context): bmdict['boundary'].append([i.face_des, i.face_type, face_strtolist(i.name)]) # Add Edges(arc, polyLine, spline, BSpline) to Dictionary + # cp_edge_list = [scn.acustom, scn.pcustom, scn.scustom, scn.bscustom] # cp_edge_list = [scn.ecustom] - # edge_type = ["arc", "polyLine", "spline", "BSpline"] - + # edge_type = ["arc", "polyLine", "spline", "BSpline"] + for ix in range(0, len(scn.ecustom)): # change the way edges are stored ''' Old code @@ -243,9 +247,6 @@ def execute(self, context): vert_index = [] edge = scn.ecustom[ix] - # Check type from edge.type - # Get indices for each vert in edge.vc - # Add the vertices into a list from edge.vert_collection edge_type = { "ARC": "arc", "PLY": "polyLine", @@ -261,6 +262,11 @@ def execute(self, context): e_verts = [list(v.vert_loc) for v in edge.vert_collection] bmdict["edges"].append([e_type, vert_index, e_verts]) + # Add MergePatchPairs to Dictionary + for i in scn.fmcustom: + pair = (i.master_face, i.slave_face) + bmdict['mergePatchPairs'].append(pair) + m = json.dumps(bmdict, sort_keys=True, indent=2) text_obj.from_string(m) diff --git a/views/mainpanel/view.py b/views/mainpanel/view.py index e45aede..494d48b 100755 --- a/views/mainpanel/view.py +++ b/views/mainpanel/view.py @@ -262,17 +262,17 @@ def draw_loc(context): def VNT_ST_boundary(self, layout, context): cs = context.scene - layout=layout.box() + box_1=layout.box() data = cs.face_name # r0 = layout.row() # r0.label(text="Boundary Controls") - r0 = layout.row() - r0.prop(cs, "face_sel_mode", toggle=True) + b1r0 = box_1.row() + b1r0.prop(cs, "face_sel_mode", toggle=True) - r1 = layout.row() - r1.operator(VNT_OT_New_Boundary.bl_idname, text="New Boundary") + b1r1 = box_1.row() + b1r1.operator(VNT_OT_New_Boundary.bl_idname, text="New Boundary") # r1 = layout.row() @@ -296,18 +296,30 @@ def VNT_ST_boundary(self, layout, context): # r4.active_default = False # new line - r2 = layout.row().grid_flow(row_major=True, columns=4, even_columns=False, align = True) - - r2.operator(VNT_OT_selectfaces.bl_idname, text="", icon="STICKY_UVS_LOC").select_all = True - r2.operator(VNT_OT_selectfaces.bl_idname, text="", icon="STICKY_UVS_DISABLE").select_all = False - r2.operator(VNT_OT_faceactions.bl_idname, text="", icon="REMOVE").action = "REMOVE" - r2.alert = True - r2.operator(VNT_OT_clearfaces.bl_idname, text="", icon="TRASH") - r2.alert = True + b1r2 = box_1.row().grid_flow(row_major=True, columns=4, even_columns=False, align = True) + + b1r2.operator(VNT_OT_selectfaces.bl_idname, text="", icon="STICKY_UVS_LOC").select_all = True + b1r2.operator(VNT_OT_selectfaces.bl_idname, text="", icon="STICKY_UVS_DISABLE").select_all = False + b1r2.operator(VNT_OT_faceactions.bl_idname, text="", icon="REMOVE").action = "REMOVE" + b1r2.alert = True + b1r2.operator(VNT_OT_clearfaces.bl_idname, text="", icon="TRASH") + b1r2.alert = True - r3 = layout.row() - r3.scale_y = 1.4 - r3.template_list("CUSTOM_UL_faces", "", cs, "fcustom", cs, "fcustom_index", rows=2) + b1r3 = box_1.row() + b1r3.scale_y = 1.4 + b1r3.template_list("CUSTOM_UL_faces", "", cs, "fcustom", cs, "fcustom_index", rows=2) + + box_2 = layout.box() + b2r0 = box_2.row() + b2r0.label(text="Face Merging") + + b2r1 = box_2.row() + b2r1.operator(VNT_OT_merge_faces.bl_idname, text="Merge Faces") + b2r1.alert = True + b2r1.operator(VNT_OT_merge_faces_delete.bl_idname, text="", icon="TRASH") + + b2r2 = box_2.row() + b2r2.template_list("CUSTOM_UL_face_merge", "", cs, "fmcustom", cs, "fmcustom_index", rows=2) def VNT_ST_step_controls(self, layout, context): cs = context.scene diff --git a/views/schemas/UIList_schemas.py b/views/schemas/UIList_schemas.py index abb1657..14b6c8e 100755 --- a/views/schemas/UIList_schemas.py +++ b/views/schemas/UIList_schemas.py @@ -166,6 +166,19 @@ def draw_item(self, context, layout, data, item, icon, active_data, active_propn def invoke(self, context, event): pass +class CUSTOM_UL_face_merge(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + box = layout.box() + col = box.column() + row = col.split() + row.prop(item, "master_face", text="Master Face", emboss=True) + row = row.split() + row.prop(item, "slave_face", text="Slave Face", emboss=True) + # row.prop(item, "enabled", text="", index=index) + + def invoke(self, context, event): + pass + ''' class CUSTOM_UL_edges(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): @@ -184,7 +197,7 @@ class CUSTOM_UL_edges_Main(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): row = layout.row() row.label(text=f"Edge {index}") - row.prop(item, "edge_type", text="") + row.prop(item, "edge_type" , text="") def invoke(self, context, event): pass From 04e7007a3b25a73e1807e6a2c8623849ea441fb9 Mon Sep 17 00:00:00 2001 From: ThaHobbyist Date: Mon, 20 Jan 2025 10:48:14 +0530 Subject: [PATCH 4/8] Added vertices UI List to Geometry view --- __init__.py | 1 + views/get_vertices.py | 6 +-- views/mainpanel/meshing_tools/blockmesh.py | 10 ++-- views/mainpanel/view.py | 54 +++++++++++----------- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/__init__.py b/__init__.py index 09bc8d0..854b95b 100755 --- a/__init__.py +++ b/__init__.py @@ -125,6 +125,7 @@ VNT_global_properties_collection, VNT_UL_mesh_file_manager, VNT_UL_mesh_file_coroner, + CUSTOM_UL_verts, CUSTOM_UL_blocks, CUSTOM_UL_faces, CUSTOM_UL_edges_Main, diff --git a/views/get_vertices.py b/views/get_vertices.py index 2b21b62..18efe36 100755 --- a/views/get_vertices.py +++ b/views/get_vertices.py @@ -5,7 +5,7 @@ class get_vertices: def draw(self, ptr, context): cs = context.scene spt = ptr.column().split() - spt.ui_units_y = 0.75 + spt.ui_units_y = 1.25 c1 = spt.row(align=True) c1.scale_y = 1.25 c2 = spt.column(align=True).split(align=True) @@ -31,7 +31,7 @@ def draw(self, ptr, context): text=None, ).select_all = False - c2.scale_y = 1.25 + c2.scale_y = 1.4 c2.alert = True c2.operator(VNT_OT_vertactions.bl_idname, icon="REMOVE", text=None).action = ( "REMOVE" @@ -40,7 +40,7 @@ def draw(self, ptr, context): c2.alert = False row = ptr.row() - row.scale_y = 1.2 + row.scale_y = 1.4 row.template_list( "CUSTOM_UL_verts", "", cs, "vcustom", cs, "vcustom_index", rows=2 ) diff --git a/views/mainpanel/meshing_tools/blockmesh.py b/views/mainpanel/meshing_tools/blockmesh.py index 0c5383e..d7ece18 100755 --- a/views/mainpanel/meshing_tools/blockmesh.py +++ b/views/mainpanel/meshing_tools/blockmesh.py @@ -89,8 +89,6 @@ def layout(self, tools, context): r5c2c1.prop(cs, "cell_z", toggle=True) r5c2c2.prop(cs, "ctm", slider=True) - - getattr(get_vertices(), "draw")(tools, context) row6 = tools.row() row6.scale_y = 1.3 @@ -128,8 +126,12 @@ def layout(self, tools, context): row6bb2.operator(VNT_OT_remove_blocks.bl_idname, icon="CANCEL", text="") row6bb2.operator(VNT_OT_remove_all_blocks.bl_idname, icon="TRASH", text="") row6bb2.operator(VNT_OT_clearblocks.bl_idname, icon="TRASH", text="") - - + + row7 = tools.row() + row7.scale_y = 1.4 + row7.template_list("CUSTOM_UL_blocks", "", cs, "bcustom", cs, "bcustom_index", rows=2) + + getattr(get_vertices(), "draw")(tools, context) class VNT_PT_cell_location(Panel): diff --git a/views/mainpanel/view.py b/views/mainpanel/view.py index e45aede..a3660ad 100755 --- a/views/mainpanel/view.py +++ b/views/mainpanel/view.py @@ -91,40 +91,42 @@ def VNT_ST_geometry(self, layout, context): else: getattr(snappyhexmesh_menu(), "layout")(tools, context) - projects = layout.box() - r7 = projects.row() + + # THis feature is to be implemented later down the line + # projects = layout.box() + # r7 = projects.row() # This shabby piece of code is similar to the draw method of top navigation bar, but relatively better. # This creates a horizontal tabs list of active projects (cases) dynamically. - for i in range(0, len(cs.mfile_item)): - x = r7.column(align=True).row(align=True) + # for i in range(0, len(cs.mfile_item)): + # x = r7.column(align=True).row(align=True) - x.operator("VNT_OT_active_project_indicator", - text=cs.mfile_item[i].ITEM_name, - emboss = True if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier else False).active_file_id = cs.mfile_item[i].ITEM_identifier + # x.operator("VNT_OT_active_project_indicator", + # text=cs.mfile_item[i].ITEM_name, + # emboss = True if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier else False).active_file_id = cs.mfile_item[i].ITEM_identifier - x.operator("vnt.deactivate_mesh_file_item", - text="", - emboss = True if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier else False, - icon="PANEL_CLOSE").dump_file_id = cs.mfile_item[i].ITEM_identifier + # x.operator("vnt.deactivate_mesh_file_item", + # text="", + # emboss = True if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier else False, + # icon="PANEL_CLOSE").dump_file_id = cs.mfile_item[i].ITEM_identifier - x.scale_y = 1.7 if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier else 1.9 - x.scale_x = 0.9730 + len(cs.mfile_item)*(0.009 if len(cs.mfile_item) == 3 else 0.01) if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier else 1.0 + # x.scale_y = 1.7 if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier else 1.9 + # x.scale_x = 0.9730 + len(cs.mfile_item)*(0.009 if len(cs.mfile_item) == 3 else 0.01) if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier else 1.0 - r7.ui_units_y = 0.00001 + # r7.ui_units_y = 0.00001 - r8 = projects.row(align=True) - for i in range(0, len(cs.mfile_item)): - y = r8.column(align=True) - if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier: - y.label(text="") # Active tab in the view - else: - y.scale_y = 0.8 - y.box().label(text="") # Passive tabs in the view - - r10 = projects.row() - r10.scale_y = 1.4 - r10.template_list("CUSTOM_UL_blocks", "", cs, "bcustom", cs, "bcustom_index", rows=2) + # r8 = projects.row(align=True) + # for i in range(0, len(cs.mfile_item)): + # y = r8.column(align=True) + # if cs.mfile_item[i].ITEM_identifier == cs.mfile_item[cs.mfile_item_index].ITEM_identifier: + # y.label(text="") # Active tab in the view + # else: + # y.scale_y = 0.8 + # y.box().label(text="") # Passive tabs in the view + + # r10 = projects.row() + # r10.scale_y = 1.4 + # r10.template_list("CUSTOM_UL_blocks", "", cs, "bcustom", cs, "bcustom_index", rows=2) def VNT_ST_visualize(self, layout, context): outline = layout.box() From 3ef6586089844fcf5be7670d88db95dffd37d632 Mon Sep 17 00:00:00 2001 From: ThaHobbyist Date: Mon, 20 Jan 2025 16:50:02 +0530 Subject: [PATCH 5/8] Fixed Data changes in UIList --- models/run_panel_operators.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/models/run_panel_operators.py b/models/run_panel_operators.py index 8cce7e8..d219bcb 100755 --- a/models/run_panel_operators.py +++ b/models/run_panel_operators.py @@ -204,7 +204,7 @@ def execute(self, context): #Add blocks to Dictionary for i in scn.bcustom: - bmdict['blocks'].append([hex_strtolist(i.name), [scn.cell_x, scn.cell_y, scn.cell_z], i.grading]) + bmdict['blocks'].append([hex_strtolist(i.name), [i.setcellx, i.setcelly, i.setcellz], i.grading]) #Add boundary(faces) to Dictionary for i in scn.fcustom: @@ -258,7 +258,16 @@ def execute(self, context): vert_index.append(bmdict["vertices"].index(list(edge.vc[0].vert_loc))) vert_index.append(bmdict["vertices"].index(list(edge.vc[2].vert_loc))) - e_verts = [list(v.vert_loc) for v in edge.vert_collection] + # f"{context.scene.ecustom[context.scene.ecustom_index].name}0{index+1}" + # ob = bpy.data.objects[sr] + # layout.prop(ob, 'location') + + e_verts = [] + length = len(edge.vert_collection) + for i in range(length): + _a_ = bpy.data.objects[f"{edge.name}0{i+1}"] + e_verts.append(list(_a_.location)) + # e_verts = [list(v.vert_loc) for v in edge.vert_collection] bmdict["edges"].append([e_type, vert_index, e_verts]) m = json.dumps(bmdict, sort_keys=True, indent=2) From 32b8bff86c697d9a549b1a7758d45fecde309226 Mon Sep 17 00:00:00 2001 From: ThaHobbyist Date: Mon, 20 Jan 2025 17:21:34 +0530 Subject: [PATCH 6/8] Fixed Boundary Visualisation --- lib/update_methods.py | 9 +++++++++ models/run_panel_operators.py | 4 ---- models/visualizer_operators.py | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/update_methods.py b/lib/update_methods.py index 832f83d..da73e78 100755 --- a/lib/update_methods.py +++ b/lib/update_methods.py @@ -40,6 +40,15 @@ def update_face_mode(self, context): me.update() else: + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE', action='TOGGLE') + obj = context.edit_object + me = obj.data + bm = bmesh.from_edit_mesh(me) + + for f in bm.faces: + f.select = True + bm.select_flush_mode() + me.update() bpy.ops.object.mode_set(mode = 'OBJECT') diff --git a/models/run_panel_operators.py b/models/run_panel_operators.py index d219bcb..91e92b6 100755 --- a/models/run_panel_operators.py +++ b/models/run_panel_operators.py @@ -258,10 +258,6 @@ def execute(self, context): vert_index.append(bmdict["vertices"].index(list(edge.vc[0].vert_loc))) vert_index.append(bmdict["vertices"].index(list(edge.vc[2].vert_loc))) - # f"{context.scene.ecustom[context.scene.ecustom_index].name}0{index+1}" - # ob = bpy.data.objects[sr] - # layout.prop(ob, 'location') - e_verts = [] length = len(edge.vert_collection) for i in range(length): diff --git a/models/visualizer_operators.py b/models/visualizer_operators.py index 24b40dc..2bf9d8d 100755 --- a/models/visualizer_operators.py +++ b/models/visualizer_operators.py @@ -326,7 +326,7 @@ def get_bound_props(self, cs, geo): # cs = context.scene vertex_props = self.get_vertex_properties(geo) - + # print(vertex_props) res = [] for item in cs.fcustom: From c111e5c08597207bba12f3cb1b44951228b36237 Mon Sep 17 00:00:00 2001 From: ThaHobbyist Date: Wed, 22 Jan 2025 14:32:42 +0530 Subject: [PATCH 7/8] Fixed coordinates of new vertex --- models/edges_panel_operators.py | 8 ++++---- views/mainpanel/view.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/models/edges_panel_operators.py b/models/edges_panel_operators.py index 02632bd..67fc40e 100644 --- a/models/edges_panel_operators.py +++ b/models/edges_panel_operators.py @@ -116,12 +116,12 @@ def first(self, context): self.curr_edge.vc[0].vert_loc=x self.curr_edge.vc[2].vert_loc=y - # coord = [None, None, None] + coord = [None, None, None] - # for i in range(3): - # coord[i] = (x[i] + y[i])/1.5 + for i in range(3): + coord[i] = (x[i] + y[i])/1.5 - coord = [cs.vertx, cs.verty, cs.vertz] + # coord = [cs.vertx, cs.verty, cs.vertz] self.curr_edge.vert_collection.add() self.curr_edge.vert_collection[0].vert_loc=coord diff --git a/views/mainpanel/view.py b/views/mainpanel/view.py index a3660ad..b1363ab 100755 --- a/views/mainpanel/view.py +++ b/views/mainpanel/view.py @@ -251,11 +251,11 @@ def draw_loc(context): row2 = layout.row() row2.operator('vnt.new_vert') row2.operator('vnt.remove_vert') - row3 = layout.row(align=True) - row3.label(text="Vertex Coordinates") - row3.prop(cs, "vertx") - row3.prop(cs, "verty") - row3.prop(cs, "vertz") + # row3 = layout.row(align=True) + # row3.label(text="Vertex Coordinates") + # row3.prop(cs, "vertx") + # row3.prop(cs, "verty") + # row3.prop(cs, "vertz") if len(ec): layout.prop(ec[cs.ecustom_index], "color") From 8c62f106849015a8185a5b5f43e40fd009b878e5 Mon Sep 17 00:00:00 2001 From: ThaHobbyist Date: Wed, 22 Jan 2025 15:04:40 +0530 Subject: [PATCH 8/8] Fixed error where user was able to add more than one vertex to an arc type edge --- __init__.py | 8 -------- models/edges_panel_operators.py | 11 +++++++++-- views/mainpanel/view.py | 5 ----- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/__init__.py b/__init__.py index 854b95b..c9633e3 100755 --- a/__init__.py +++ b/__init__.py @@ -359,11 +359,6 @@ def register(): bpy.types.Scene.vert_index = IntProperty(name="Vertex Index", default=0) - # Temporary Vertex Properties. To be changed later - bpy.types.Scene.vertx = FloatProperty(name="X", default=0.0) - bpy.types.Scene.verty = FloatProperty(name="Y", default=0.0) - bpy.types.Scene.vertz = FloatProperty(name="Z", default=0.0) - bpy.types.Scene.edge_control_methods = EnumProperty( items=[("IP", "Interpolation Points", ""), ("AA", "Axis angle", "")], default="IP", @@ -569,9 +564,6 @@ def unregister(): del bpy.types.Scene.ecustom del bpy.types.Scene.ecustom_index del bpy.types.Scene.vert_index - del bpy.types.Scene.vertx - del bpy.types.Scene.verty - del bpy.types.Scene.vertz del bpy.types.Scene.cnt del bpy.types.Scene.mode del bpy.types.Scene.bdclist diff --git a/models/edges_panel_operators.py b/models/edges_panel_operators.py index 67fc40e..a293d92 100644 --- a/models/edges_panel_operators.py +++ b/models/edges_panel_operators.py @@ -67,6 +67,15 @@ class VNT_OT_new_vert(Operator): bl_idname = "vnt.new_vert" bl_label = "Generate new Vertex" + @classmethod + def poll(cls, context): + cs = context.scene + if len(cs.ecustom) == 0: + return True + else: + curr_edge = cs.ecustom[cs.ecustom_index] + return curr_edge.edge_type != 'ARC' or len(curr_edge.vert_collection) == 0 + def execute(self, context): cs = context.scene try: @@ -120,8 +129,6 @@ def first(self, context): for i in range(3): coord[i] = (x[i] + y[i])/1.5 - - # coord = [cs.vertx, cs.verty, cs.vertz] self.curr_edge.vert_collection.add() self.curr_edge.vert_collection[0].vert_loc=coord diff --git a/views/mainpanel/view.py b/views/mainpanel/view.py index b1363ab..5407d01 100755 --- a/views/mainpanel/view.py +++ b/views/mainpanel/view.py @@ -251,11 +251,6 @@ def draw_loc(context): row2 = layout.row() row2.operator('vnt.new_vert') row2.operator('vnt.remove_vert') - # row3 = layout.row(align=True) - # row3.label(text="Vertex Coordinates") - # row3.prop(cs, "vertx") - # row3.prop(cs, "verty") - # row3.prop(cs, "vertz") if len(ec): layout.prop(ec[cs.ecustom_index], "color")