mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-19 03:33:48 +00:00
Measure tool - show text decorator for polyline area and length.
This commit is contained in:
@@ -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":
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user