Measure tool - show text decorator for polyline area and length.

This commit is contained in:
Bruno Perdigão
2024-10-05 14:51:52 -03:00
parent ce1f1bc394
commit 93457051da
6 changed files with 140 additions and 65 deletions
+45 -13
View File
@@ -524,9 +524,13 @@ class PolylineDecorator:
def draw_measurements(self, context):
region = context.region
rv3d = region.data
measure_type = context.scene.MeasureToolSettings.measure_type
measure_type = context.scene.MeasureToolSettings.measurement_type
polyline_data = context.scene.BIMPolylineProperties.insertion_polyline
polyline_points = polyline_data[0].polyline_points if polyline_data else []
if not polyline_data:
return
else:
polyline_data = context.scene.BIMPolylineProperties.insertion_polyline[0]
polyline_points = polyline_data.polyline_points
self.addon_prefs = tool.Blender.get_addon_preferences()
self.font_id = 1
@@ -554,7 +558,7 @@ class PolylineDecorator:
if i == 1:
continue
angle_text_pos = polyline_points[i - 1].position
angle_text_pos = Vector(polyline_points[i - 1].position)
angle_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, angle_text_pos)
blf.position(self.font_id, angle_text_coords[0], angle_text_coords[1], 0)
text = "a: " + polyline_points[i].angle
@@ -572,12 +576,40 @@ class PolylineDecorator:
if (i == 0 and direction.x < 0) or (i == 1 and direction.y < 0) or (i == 2 and direction.z < 0):
value = -value
prefix = "xyz"[i]
formatted_value = tool.Polyline.format_input_ui_units(context, value)
formatted_value = tool.Polyline.format_input_ui_units(value)
text = f"{prefix}: {formatted_value}"
text_length = blf.dimensions(self.font_id, text)
self.draw_text_background(context, dim_text_coords, text_length)
blf.draw(self.font_id, text)
# Area and Length text
polyline_verts = [Vector((p.x, p.y, p.z)) for p in polyline_points]
center = sum(polyline_verts, Vector()) / len(polyline_verts) # center between all polyline points
area_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, center)
total_length_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, polyline_verts[-1])
# Area
if measure_type == "AREA":
if len(polyline_verts) < 3:
return
blf.position(self.font_id, area_text_coords[0], area_text_coords[1], 0)
value = polyline_data.area
text = f"area: {value}"
text_length = blf.dimensions(self.font_id, text)
self.draw_text_background(context, area_text_coords, text_length)
blf.draw(self.font_id, text)
# Length
if measure_type in {"POLYLINE","AREA"}:
if len(polyline_verts) < 2:
return
blf.position(self.font_id, total_length_text_coords[0], total_length_text_coords[1], 0)
value = polyline_data.total_length
text = f"length: {value}"
text_length = blf.dimensions(self.font_id, text)
self.draw_text_background(context, total_length_text_coords, text_length)
blf.draw(self.font_id, text)
blf.disable(self.font_id, blf.SHADOW)
@@ -673,7 +705,11 @@ class PolylineDecorator:
# Create polyline with selected points
polyline_data = context.scene.BIMPolylineProperties.insertion_polyline
polyline_points = polyline_data[0].polyline_points if polyline_data else []
if not polyline_data:
return
else:
polyline_data = context.scene.BIMPolylineProperties.insertion_polyline[0]
polyline_points = polyline_data.polyline_points
polyline_verts = []
polyline_edges = []
for point_prop in polyline_points:
@@ -703,8 +739,7 @@ class PolylineDecorator:
self.draw_batch("LINES", [self.axis_start, self.axis_end], axis_color, [(0, 1)])
# Lines for X, Y, Z of single measure
measure_type = context.scene.MeasureToolSettings.measure_type
if measure_type == "SINGLE":
if polyline_data.measurement_type == "SINGLE":
axis, _ = self.calculate_measurement_x_y_and_z(context)
x_axis, y_axis, z_axis = axis
self.draw_batch("LINES", [*x_axis], decorator_color_x_axis, [(0, 1)])
@@ -712,12 +747,9 @@ class PolylineDecorator:
self.draw_batch("LINES", [*z_axis], decorator_color_z_axis, [(0, 1)])
# Area highlight
try:
has_area = self.input_ui.init_area
except:
has_area = False
if has_area:
if self.input_ui.get_number_value("AREA") > 0:
area = polyline_data.area
if area:
if float(area) > 0:
tris = self.calculate_polygon(polyline_verts)
self.draw_batch("TRIS", polyline_verts, transparent_color(decorator_color_special), tris)
@@ -274,6 +274,7 @@ class MeasureDecorator:
bm.edges.index_update()
new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges)
center = bm.faces[0]
bm.verts.index_update()
bm.edges.index_update()
@@ -281,7 +282,7 @@ class MeasureDecorator:
bm.free()
return tris
return tris, center
def draw_text_background(self, context, coords_dim, text_dim):
padding = 5
@@ -312,17 +313,18 @@ class MeasureDecorator:
blf.color(self.font_id, *color)
measure_data = context.scene.BIMPolylineProperties.measurement_polyline
for data in measure_data:
measurement_prop = data.polyline_points
measure_type = data.measurement_type
for polyline_data in measure_data:
polyline_points = polyline_data.polyline_points
measure_type = polyline_data.measurement_type
for i in range(len(measurement_prop)):
all_positions = []
for i in range(len(polyline_points)):
if i == 0:
continue
dim_text_pos = (Vector(measurement_prop[i].position) + Vector(measurement_prop[i - 1].position)) / 2
dim_text_pos = (Vector(polyline_points[i].position) + Vector(polyline_points[i - 1].position)) / 2
dim_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, dim_text_pos)
formatted_value = measurement_prop[i].dim
formatted_value = polyline_points[i].dim
blf.position(self.font_id, dim_text_coords[0], dim_text_coords[1], 0)
text = "d: " + formatted_value
@@ -332,16 +334,16 @@ class MeasureDecorator:
if i == 1:
continue
angle_text_pos = measurement_prop[i - 1].position
angle_text_pos = Vector(polyline_points[i - 1].position)
angle_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, angle_text_pos)
blf.position(self.font_id, angle_text_coords[0], angle_text_coords[1], 0)
text = "a: " + measurement_prop[i].angle
text = "a: " + polyline_points[i].angle
text_length = blf.dimensions(self.font_id, text)
self.draw_text_background(context, angle_text_coords, text_length)
blf.draw(self.font_id, text)
if measure_type == "SINGLE":
axis_line, axis_line_center = self.calculate_measurement_x_y_and_z(context, measurement_prop)
axis_line, axis_line_center = self.calculate_measurement_x_y_and_z(context, polyline_points)
for i, dim_text_pos in enumerate(axis_line_center):
dim_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, dim_text_pos)
blf.position(self.font_id, dim_text_coords[0], dim_text_coords[1], 0)
@@ -350,12 +352,40 @@ class MeasureDecorator:
if (i == 0 and direction.x < 0) or (i == 1 and direction.y < 0) or (i == 2 and direction.z < 0):
value = -value
prefix = "xyz"[i]
formatted_value = tool.Polyline.format_input_ui_units(context, value)
formatted_value = tool.Polyline.format_input_ui_units(value)
text = f"{prefix}: {formatted_value}"
text_length = blf.dimensions(self.font_id, text)
self.draw_text_background(context, dim_text_coords, text_length)
blf.draw(self.font_id, text)
# Area and Length text
polyline_verts = [Vector((p.x, p.y, p.z)) for p in polyline_points]
center = sum(polyline_verts, Vector()) / len(polyline_verts) # center between all polyline points
area_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, center)
total_length_text_coords = view3d_utils.location_3d_to_region_2d(region, rv3d, polyline_verts[-1])
# Area
if measure_type == "AREA":
if len(polyline_verts) < 3:
return
blf.position(self.font_id, area_text_coords[0], area_text_coords[1], 0)
value = polyline_data.area
text = f"area: {value}"
text_length = blf.dimensions(self.font_id, text)
self.draw_text_background(context, area_text_coords, text_length)
blf.draw(self.font_id, text)
# Length
if measure_type in {"POLYLINE","AREA"}:
if len(polyline_verts) < 2:
return
blf.position(self.font_id, total_length_text_coords[0], total_length_text_coords[1], 0)
value = polyline_data.total_length
text = f"length: {value}"
text_length = blf.dimensions(self.font_id, text)
self.draw_text_background(context, total_length_text_coords, text_length)
blf.draw(self.font_id, text)
blf.disable(self.font_id, blf.SHADOW)
@@ -385,36 +415,36 @@ class MeasureDecorator:
gpu.state.point_size_set(6)
measure_data = context.scene.BIMPolylineProperties.measurement_polyline
for data in measure_data:
polyline_data = data.polyline_points
for polyline_data in measure_data:
polyline_points = polyline_data.polyline_points
polyline_points = []
polyline_verts = []
polyline_edges = []
for point_prop in polyline_data:
for point_prop in polyline_points:
point = Vector((point_prop.x, point_prop.y, point_prop.z))
polyline_points.append(point)
polyline_verts.append(point)
for i in range(len(polyline_points) - 1):
for i in range(len(polyline_verts) - 1):
polyline_edges.append([i, i + 1])
# Lines for X, Y, Z of single measure
measure_type = data.measurement_type
measure_type = polyline_data.measurement_type
if measure_type == "SINGLE":
axis, _ = self.calculate_measurement_x_y_and_z(context, polyline_data)
axis, _ = self.calculate_measurement_x_y_and_z(context, polyline_points)
x_axis, y_axis, z_axis = axis
self.draw_batch("LINES", [*x_axis], decorator_color_x_axis, [(0, 1)])
self.draw_batch("LINES", [*y_axis], decorator_color_y_axis, [(0, 1)])
self.draw_batch("LINES", [*z_axis], decorator_color_z_axis, [(0, 1)])
# Area highlight
area = data.area
area = polyline_data.area
if area:
if float(area) > 0:
tris = self.calculate_polygon(polyline_points)
self.draw_batch("TRIS", polyline_points, transparent_color(decorator_color_special), tris)
tris, _ = self.calculate_polygon(polyline_verts)
self.draw_batch("TRIS", polyline_verts, transparent_color(decorator_color_special), tris)
# Draw polyline with selected points
self.line_shader.uniform_float("lineWidth", 2.0)
self.draw_batch("POINTS", polyline_points, decorator_color_special)
if len(polyline_points) > 1:
self.draw_batch("LINES", polyline_points, decorator_color_special, polyline_edges)
self.draw_batch("POINTS", polyline_verts, decorator_color_special)
if len(polyline_verts) > 1:
self.draw_batch("LINES", polyline_verts, decorator_color_special, polyline_edges)
@@ -2435,6 +2435,18 @@ class MeasureTool(bpy.types.Operator, PolylineOperator):
self.handle_keyboard_input(context, event)
self.handle_inserting_polyline(context, event)
# Add measurement type to the insertion polyline
polyline_data = context.scene.BIMPolylineProperties.insertion_polyline
if not polyline_data:
pass
else:
polyline_data = context.scene.BIMPolylineProperties.insertion_polyline[0]
measurement_type = bpy.context.scene.MeasureToolSettings.measurement_type
if not polyline_data.measurement_type:
polyline_data.measurement_type = measurement_type
tool.Polyline.calculate_area(context, self.input_ui)
if event.type == "E":
+2 -2
View File
@@ -232,10 +232,10 @@ class BIMProjectProperties(PropertyGroup):
class MeasureToolSettings(PropertyGroup):
measure_type_items = [
measurement_type_items = [
("SINGLE", "SINGLE", "Single", "FIXED_SIZE",1),
("POLYLINE", "POLYLINE", "Polyline", "DRIVER_ROTATIONAL_DIFFERENCE", 2),
("AREA", "AREA", "Area", "OUTLINER_DATA_LIGHTPROBE", 3),
]
measure_type: bpy.props.EnumProperty(items=measure_type_items, default="POLYLINE")
measurement_type: bpy.props.EnumProperty(items=measurement_type_items, default="POLYLINE")
@@ -67,7 +67,7 @@ class ExploreTool(bpy.types.WorkSpaceTool):
op = row.operator("bim.explore_hotkey", text="Measure Tool", icon="CON_DISTLIMIT")
op.hotkey = "S_M"
row = layout.row(align=True)
row.prop(prop, "measure_type", text="Measure Type", expand=True, icon_only=True, emboss=True)
row.prop(prop, "measurement_type", text="Measure Type", expand=True, icon_only=True, emboss=True)
class ExploreHotkey(bpy.types.Operator):
@@ -103,5 +103,5 @@ class ExploreHotkey(bpy.types.Operator):
def hotkey_S_M(self):
for obj in tool.Blender.get_selected_objects():
obj.select_set(False)
measure_type = bpy.context.scene.MeasureToolSettings.measure_type
measure_type = bpy.context.scene.MeasureToolSettings.measurement_type
bpy.ops.bim.measure_tool("INVOKE_DEFAULT", measure_type=measure_type)
+24 -23
View File
@@ -71,8 +71,7 @@ class Polyline(bonsai.core.tool.Polyline):
value = float(self.get_text_value(attribute_name))
return f"{value:.2f}"
else:
return Polyline.format_input_ui_units(context, value)
return Polyline.format_input_ui_units(value)
@dataclass
class ToolState:
@@ -215,6 +214,11 @@ class Polyline(bonsai.core.tool.Polyline):
if input_ui.get_text_value("AREA") is not None:
input_ui.set_value("AREA", area)
area = input_ui.get_number_value("AREA")
if area:
area = tool.Polyline.format_input_ui_units(area)
polyline_data.area = area
return
@classmethod
@@ -226,6 +230,7 @@ class Polyline(bonsai.core.tool.Polyline):
last_point_data = polyline_points[len(polyline_points) - 1]
last_point = Vector((last_point_data.x, last_point_data.y, last_point_data.z))
except:
polyline_points = []
default_container_elevation = 0
last_point = Vector((0, 0, 0))
@@ -495,20 +500,19 @@ class Polyline(bonsai.core.tool.Polyline):
return False, "0"
@classmethod
def format_input_ui_units(cls, context, value):
def format_input_ui_units(cls, value):
unit_system = tool.Drawing.get_unit_system()
if unit_system == "IMPERIAL":
precision = context.scene.DocProperties.imperial_precision
precision = bpy.context.scene.DocProperties.imperial_precision
factor = 3.28084
else:
precision = None
factor = 1
if context.scene.unit_settings.length_unit == "MILLIMETERS":
if bpy.context.scene.unit_settings.length_unit == "MILLIMETERS":
factor = 1000
return format_distance(value * factor, precision=precision, suppress_zero_inches=True, in_unit_length=True)
@classmethod
def insert_polyline_point(cls, input_ui, tool_state):
x = input_ui.get_number_value("X")
@@ -529,7 +533,6 @@ class Polyline(bonsai.core.tool.Polyline):
y = snap_vertex.y
z = snap_vertex.z
polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline
if not polyline_data:
polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline.add()
@@ -558,6 +561,17 @@ class Polyline(bonsai.core.tool.Polyline):
polyline_point.angle = a
polyline_point.position = Vector((x, y, z))
# Add total length
total_length = 0
for i, point in enumerate(polyline_points):
if i == 0:
continue
dim = float(tool.Polyline.validate_input(point.dim, "D")[1])
total_length += dim
total_length = tool.Polyline.format_input_ui_units(total_length)
polyline_data.total_length = total_length
@classmethod
def close_polyline(cls):
polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline
@@ -586,7 +600,7 @@ class Polyline(bonsai.core.tool.Polyline):
polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline
polyline_points = polyline_data[0].polyline_points if polyline_data else []
measurement_data = bpy.context.scene.BIMPolylineProperties.measurement_polyline.add()
measurement_type = bpy.context.scene.MeasureToolSettings.measure_type
measurement_type = bpy.context.scene.MeasureToolSettings.measurement_type
measurement_data.measurement_type = measurement_type
for point in polyline_points:
measurement_point = measurement_data.polyline_points.add()
@@ -597,18 +611,5 @@ class Polyline(bonsai.core.tool.Polyline):
measurement_point.angle = point.angle
measurement_point.position = point.position
# Add total length
total_length = 0
for i, point in enumerate(measurement_data.polyline_points):
if i == 0:
continue
dim = float(tool.Polyline.validate_input(point.dim, "D")[1])
total_length += dim
total_length = tool.Polyline.format_input_ui_units(context, total_length)
measurement_data.total_length = total_length
# Add area
area = input_ui.get_number_value("AREA")
if area:
area = tool.Polyline.format_input_ui_units(context, area)
measurement_data.area = area
measurement_data.total_length = polyline_data[0].total_length
measurement_data.area = polyline_data[0].area