mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-16 18:44:47 +00:00
Measure tool - single and area measurement now persist on screen.
Also, the measure polyline properties now stores the area and the total length that will be used by the decorator in later development.
This commit is contained in:
@@ -573,7 +573,7 @@ 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 = self.input_ui.format_input_ui_units(context, value)
|
||||
formatted_value = tool.Polyline.format_input_ui_units(context, value)
|
||||
text = f"{prefix}: {formatted_value}"
|
||||
text_length = blf.dimensions(self.font_id, text)
|
||||
self.draw_text_background(context, dim_text_coords, text_length)
|
||||
|
||||
@@ -751,8 +751,10 @@ class PolylinePoint(PropertyGroup):
|
||||
|
||||
|
||||
class MeasurePolyline(PropertyGroup):
|
||||
polyline_point: bpy.props.CollectionProperty(type=PolylinePoint)
|
||||
polyline_points: bpy.props.CollectionProperty(type=PolylinePoint)
|
||||
measurement_type: bpy.props.StringProperty(name="Measurement Type")
|
||||
area: bpy.props.StringProperty(name="Measured Area")
|
||||
total_length: bpy.props.StringProperty(name="Total Length")
|
||||
|
||||
|
||||
class BIMPolylineProperties(PropertyGroup):
|
||||
|
||||
@@ -42,6 +42,11 @@ def toggle_decorations_on_load(*args):
|
||||
# as queried object is linked from separate .blend file.
|
||||
|
||||
|
||||
def transparent_color(color, alpha=0.1):
|
||||
color = [i for i in color]
|
||||
color[3] = alpha
|
||||
return color
|
||||
|
||||
class ProjectDecorator:
|
||||
installed = None
|
||||
|
||||
@@ -239,6 +244,45 @@ class MeasureDecorator:
|
||||
shader.uniform_float("color", color)
|
||||
batch.draw(shader)
|
||||
|
||||
def calculate_measurement_x_y_and_z(self, context, measurement_prop):
|
||||
|
||||
if len(measurement_prop) == 0 or len(measurement_prop) > 2:
|
||||
return None, None
|
||||
|
||||
start = measurement_prop[0]
|
||||
if len(measurement_prop) == 1:
|
||||
end = context.scene.BIMPolylineProperties.snap_mouse_point[0]
|
||||
else:
|
||||
end = measurement_prop[1]
|
||||
|
||||
x_axis = (Vector((start.x, start.y, start.z)), Vector((end.x, start.y, start.z)))
|
||||
y_axis = (Vector((end.x, start.y, start.z)), Vector((end.x, end.y, start.z)))
|
||||
z_axis = (Vector((end.x, end.y, start.z)), Vector((end.x, end.y, end.z)))
|
||||
x_middle = (x_axis[1] + x_axis[0]) / 2
|
||||
y_middle = (y_axis[1] + y_axis[0]) / 2
|
||||
z_middle = (z_axis[1] + z_axis[0]) / 2
|
||||
|
||||
return (x_axis, y_axis, z_axis), (x_middle, y_middle, z_middle)
|
||||
|
||||
def calculate_polygon(self, points):
|
||||
bm = bmesh.new()
|
||||
|
||||
new_verts = [bm.verts.new(v) for v in points]
|
||||
new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(points) - 1)]
|
||||
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
|
||||
new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges)
|
||||
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()]
|
||||
|
||||
bm.free()
|
||||
|
||||
return tris
|
||||
|
||||
def draw_text_background(self, context, coords_dim, text_dim):
|
||||
padding = 5
|
||||
theme = context.preferences.themes.items()[0][1]
|
||||
@@ -255,6 +299,7 @@ class MeasureDecorator:
|
||||
def draw_measurements(self, context):
|
||||
region = context.region
|
||||
rv3d = region.data
|
||||
|
||||
self.addon_prefs = tool.Blender.get_addon_preferences()
|
||||
self.font_id = 1
|
||||
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||
@@ -263,36 +308,56 @@ class MeasureDecorator:
|
||||
blf.enable(self.font_id, blf.SHADOW)
|
||||
blf.shadow(self.font_id, 6, 0, 0, 0, 1)
|
||||
color = self.addon_prefs.decorations_colour
|
||||
blf.color(self.font_id, *color)
|
||||
|
||||
|
||||
blf.color(self.font_id, *color)
|
||||
measure_data = context.scene.BIMPolylineProperties.measurement_polyline
|
||||
for data in measure_data:
|
||||
measurement_prop = data.polyline_point
|
||||
measurement_prop = data.polyline_points
|
||||
measure_type = data.measurement_type
|
||||
|
||||
for i in range(len(measurement_prop)):
|
||||
if i == 0:
|
||||
continue
|
||||
pos_dim = (Vector(measurement_prop[i].position) + Vector(measurement_prop[i - 1].position)) / 2
|
||||
coords_dim = view3d_utils.location_3d_to_region_2d(region, rv3d, pos_dim)
|
||||
dim_text_pos = (Vector(measurement_prop[i].position) + Vector(measurement_prop[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
|
||||
|
||||
blf.position(self.font_id, coords_dim[0], coords_dim[1], 0)
|
||||
blf.position(self.font_id, dim_text_coords[0], dim_text_coords[1], 0)
|
||||
text = "d: " + formatted_value
|
||||
text_dim = blf.dimensions(self.font_id, text)
|
||||
self.draw_text_background(context, coords_dim, text_dim)
|
||||
text_length = blf.dimensions(self.font_id, text)
|
||||
self.draw_text_background(context, dim_text_coords, text_length)
|
||||
blf.draw(self.font_id, text)
|
||||
|
||||
if i == 1:
|
||||
continue
|
||||
pos_angle = measurement_prop[i - 1].position
|
||||
coords_angle = view3d_utils.location_3d_to_region_2d(region, rv3d, pos_angle)
|
||||
blf.position(self.font_id, coords_angle[0], coords_angle[1], 0)
|
||||
angle_text_pos = measurement_prop[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_dim = blf.dimensions(self.font_id, text)
|
||||
self.draw_text_background(context, coords_angle, text_dim)
|
||||
text_length = blf.dimensions(self.font_id, text)
|
||||
self.draw_text_background(context, angle_text_coords, text_length)
|
||||
blf.draw(self.font_id, text)
|
||||
blf.disable(self.font_id, blf.SHADOW)
|
||||
|
||||
if measure_type == "SINGLE":
|
||||
axis_line, axis_line_center = self.calculate_measurement_x_y_and_z(context, measurement_prop)
|
||||
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)
|
||||
value = round((axis_line[i][1] - axis_line[i][0]).length, 4)
|
||||
direction = axis_line[i][1] - axis_line[i][0]
|
||||
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)
|
||||
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)
|
||||
|
||||
blf.disable(self.font_id, blf.SHADOW)
|
||||
|
||||
|
||||
def __call__(self, context):
|
||||
|
||||
@@ -321,7 +386,7 @@ class MeasureDecorator:
|
||||
|
||||
measure_data = context.scene.BIMPolylineProperties.measurement_polyline
|
||||
for data in measure_data:
|
||||
polyline_data = data.polyline_point
|
||||
polyline_data = data.polyline_points
|
||||
|
||||
polyline_points = []
|
||||
polyline_edges = []
|
||||
@@ -332,6 +397,22 @@ class MeasureDecorator:
|
||||
for i in range(len(polyline_points) - 1):
|
||||
polyline_edges.append([i, i + 1])
|
||||
|
||||
# Lines for X, Y, Z of single measure
|
||||
measure_type = data.measurement_type
|
||||
if measure_type == "SINGLE":
|
||||
axis, _ = self.calculate_measurement_x_y_and_z(context, polyline_data)
|
||||
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
|
||||
if area:
|
||||
if float(area) > 0:
|
||||
tris = self.calculate_polygon(polyline_points)
|
||||
self.draw_batch("TRIS", polyline_points, 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)
|
||||
|
||||
@@ -2421,7 +2421,7 @@ class MeasureTool(bpy.types.Operator, PolylineOperator):
|
||||
) or single_mode:
|
||||
context.workspace.status_text_set(text=None)
|
||||
PolylineDecorator.uninstall()
|
||||
tool.Snap.move_polyline_to_measure()
|
||||
tool.Snap.move_polyline_to_measure(context, self.input_ui)
|
||||
tool.Snap.clear_polyline()
|
||||
MeasureDecorator.install(context)
|
||||
tool.Blender.update_viewport()
|
||||
|
||||
@@ -71,20 +71,8 @@ class Polyline(bonsai.core.tool.Polyline):
|
||||
value = float(self.get_text_value(attribute_name))
|
||||
return f"{value:.2f}"
|
||||
else:
|
||||
return self.format_input_ui_units(context, value)
|
||||
return Polyline.format_input_ui_units(context, value)
|
||||
|
||||
def format_input_ui_units(cls, context, value):
|
||||
unit_system = tool.Drawing.get_unit_system()
|
||||
if unit_system == "IMPERIAL":
|
||||
precision = context.scene.DocProperties.imperial_precision
|
||||
factor = 3.28084
|
||||
else:
|
||||
precision = None
|
||||
factor = 1
|
||||
if context.scene.unit_settings.length_unit == "MILLIMETERS":
|
||||
factor = 1000
|
||||
|
||||
return format_distance(value * factor, precision=precision, suppress_zero_inches=True, in_unit_length=True)
|
||||
|
||||
@dataclass
|
||||
class ToolState:
|
||||
@@ -500,3 +488,17 @@ class Polyline(bonsai.core.tool.Polyline):
|
||||
return True, str(result)
|
||||
except:
|
||||
return False, "0"
|
||||
|
||||
@classmethod
|
||||
def format_input_ui_units(cls, context, value):
|
||||
unit_system = tool.Drawing.get_unit_system()
|
||||
if unit_system == "IMPERIAL":
|
||||
precision = context.scene.DocProperties.imperial_precision
|
||||
factor = 3.28084
|
||||
else:
|
||||
precision = None
|
||||
factor = 1
|
||||
if context.scene.unit_settings.length_unit == "MILLIMETERS":
|
||||
factor = 1000
|
||||
|
||||
return format_distance(value * factor, precision=precision, suppress_zero_inches=True, in_unit_length=True)
|
||||
|
||||
@@ -157,13 +157,13 @@ class Snap(bonsai.core.tool.Snap):
|
||||
polyline_data.remove(len(polyline_data) - 1)
|
||||
|
||||
@classmethod
|
||||
def move_polyline_to_measure(cls):
|
||||
def move_polyline_to_measure(cls, context, input_ui):
|
||||
polyline_data = bpy.context.scene.BIMPolylineProperties.polyline_points
|
||||
measurement_data = bpy.context.scene.BIMPolylineProperties.measurement_polyline.add()
|
||||
measurement_type = bpy.context.scene.MeasureToolSettings.measure_type
|
||||
measurement_data.measurement_type = measurement_type
|
||||
for point in polyline_data:
|
||||
measurement_point = measurement_data.polyline_point.add()
|
||||
measurement_point = measurement_data.polyline_points.add()
|
||||
measurement_point.x = point.x
|
||||
measurement_point.y = point.y
|
||||
measurement_point.z = point.z
|
||||
@@ -171,6 +171,22 @@ class Snap(bonsai.core.tool.Snap):
|
||||
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
|
||||
|
||||
@classmethod
|
||||
def snap_on_axis(cls, intersection, tool_state, lock_angle=False):
|
||||
def create_axis_line_data(rot_mat, origin):
|
||||
@@ -396,7 +412,7 @@ class Snap(bonsai.core.tool.Snap):
|
||||
# Measure
|
||||
measure_data = context.scene.BIMPolylineProperties.measurement_polyline
|
||||
for measure in measure_data:
|
||||
measure_points = measure.polyline_point
|
||||
measure_points = measure.polyline_points
|
||||
snap_points = tool.Raycast.ray_cast_to_measure(context, event, measure_points)
|
||||
if snap_points:
|
||||
detected_snaps.append({"Polyline": snap_points})
|
||||
|
||||
Reference in New Issue
Block a user