summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiptangshu Dey2025-01-22 16:07:22 +0530
committerGitHub2025-01-22 16:07:22 +0530
commit8893803ab929129d6d028858f948a3df6353fd62 (patch)
tree5ad4eb46285994a95981b8079d008b3fcf943c05
parent6f610c4f199cacf56569d001acb078bcead1dfd5 (diff)
parent8c62f106849015a8185a5b5f43e40fd009b878e5 (diff)
downloadventurial-8893803ab929129d6d028858f948a3df6353fd62.tar.gz
venturial-8893803ab929129d6d028858f948a3df6353fd62.tar.bz2
venturial-8893803ab929129d6d028858f948a3df6353fd62.zip
Merge pull request #11 from FOSSEE/bug_fixes
Bug fixes
-rwxr-xr-x__init__.py9
-rwxr-xr-xlib/update_methods.py9
-rw-r--r--models/edge_gen_algorithms.py239
-rw-r--r--models/edges_panel_operators.py55
-rwxr-xr-xmodels/run_panel_operators.py9
-rwxr-xr-xmodels/visualizer_operators.py2
-rwxr-xr-xviews/get_vertices.py6
-rwxr-xr-xviews/mainpanel/meshing_tools/blockmesh.py10
-rwxr-xr-xviews/mainpanel/view.py59
9 files changed, 258 insertions, 140 deletions
diff --git a/__init__.py b/__init__.py
index 9716fab..fc4fd78 100755
--- a/__init__.py
+++ b/__init__.py
@@ -125,6 +125,7 @@ classes = (
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,
@@ -367,11 +368,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",
@@ -577,9 +573,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/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/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 generate_catmull_rom_curve(resolution, points):
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..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:
@@ -116,12 +125,10 @@ class VNT_OT_new_vert(Operator):
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 = [None, None, None]
- coord = [cs.vertx, cs.verty, cs.vertz]
+ for i in range(3):
+ coord[i] = (x[i] + y[i])/1.5
self.curr_edge.vert_collection.add()
self.curr_edge.vert_collection[0].vert_loc=coord
@@ -279,17 +286,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 +307,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
diff --git a/models/run_panel_operators.py b/models/run_panel_operators.py
index 478888d..86f54ff 100755
--- a/models/run_panel_operators.py
+++ b/models/run_panel_operators.py
@@ -207,7 +207,7 @@ class VNT_OT_fill_dict_file(Operator):
#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:
@@ -259,7 +259,12 @@ class VNT_OT_fill_dict_file(Operator):
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]
+ 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])
# Add MergePatchPairs to Dictionary
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 @@ class VNT_OT_boundary_data_control(Operator):
# cs = context.scene
vertex_props = self.get_vertex_properties(geo)
-
+ # print(vertex_props)
res = []
for item in cs.fcustom:
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 @@ class get_vertices:
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 @@ class get_vertices:
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 @@ class blockmesh_menu:
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 @@ class blockmesh_menu:
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 494d48b..3a1ce0f 100755
--- a/views/mainpanel/view.py
+++ b/views/mainpanel/view.py
@@ -91,40 +91,42 @@ class layout_controller:
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()
@@ -249,11 +251,6 @@ class layout_controller:
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")