Merge remote-tracking branch 'origin/v0.7.0' into v0.8.0

This commit is contained in:
Thomas Krijnen
2023-03-29 18:06:50 +02:00
7 changed files with 139 additions and 48 deletions
+1 -1
View File
@@ -88,7 +88,7 @@ jobs:
sudo /usr/bin/python -m pip install lark
sudo /usr/bin/python -m pip install networkx
sudo /usr/bin/python -m pip install tabulate
sudo /usr/bin/python -m pip install dateutil
sudo /usr/bin/python -m pip install python-dateutil
- name: Test
run: |
+1 -1
View File
@@ -114,7 +114,7 @@ jobs:
sudo /usr/bin/python -m pip install networkx
sudo /usr/bin/python -m pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
sudo /usr/bin/python -m pip install tabulate
sudo /usr/bin/python -m pip install dateutil
sudo /usr/bin/python -m pip install python-dateutil
- name: Test
run: |
@@ -115,6 +115,7 @@ class DecoratorData:
# stores 1 type of data per object
data = {}
# used by Ifc Annotations with ObjectType = "BATTING"
@classmethod
def get_batting_thickness(cls, obj):
result = cls.data.get(obj.name, None)
@@ -128,6 +129,7 @@ class DecoratorData:
cls.data[obj.name] = thickness
return thickness
# used by Ifc Annotations with ObjectType = "SECTION"
@classmethod
def get_section_markers_display_data(cls, obj):
result = cls.data.get(obj.name, None)
@@ -169,6 +171,7 @@ class DecoratorData:
cls.data[obj.name] = display_data
return display_data
# used by Ifc Annotations with ObjectType = "TEXT"
@classmethod
def get_ifc_text_data(cls, obj):
"""returns font size in mm for current ifc text object"""
@@ -214,3 +217,22 @@ class DecoratorData:
text_data = {"Literals": literals_data, "FontSize": font_size}
cls.data[obj.name] = text_data
return text_data
# used by Ifc Annotations with ObjectType = "DIMENSION"
@classmethod
def get_dimension_style(cls, obj):
result = cls.data.get(obj.name, None)
if result is not None:
return result
element = tool.Ifc.get_entity(obj)
if not element or not element.is_a("IfcAnnotation") or element.ObjectType != "DIMENSION":
return None
dimension_style = "arrow"
classes = ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Classes")
if classes and "oblique" in classes.lower().split():
dimension_style = "oblique"
cls.data[obj.name] = dimension_style
return dimension_style
@@ -442,7 +442,7 @@ class BaseDecorator:
box_alignment_offset += Vector((0, h))
else:
# middle / center
box_alignment_offset += Vector((0, h / 2))
box_alignment_offset += Vector((0, h / 2))
if "left" in box_alignment:
pass
@@ -451,7 +451,7 @@ class BaseDecorator:
else:
# middle / center
box_alignment_offset += Vector((w / 2, 0))
pos -= rotation_matrix.transposed() @ box_alignment_offset
else:
if center:
@@ -506,6 +506,10 @@ class DimensionDecorator(BaseDecorator):
DEF_GLSL = (
BaseDecorator.DEF_GLSL
+ """
#define OBLIQUE_SYMBOL_ANGLE PI / 4.0
#define OLBIQUE_SYMBOL_SIZE 10.0
#define OBLIQUE_HEAD_VERTS 7
#define ARROW_ANGLE PI / 12.0
#define ARROW_SIZE 16.0
"""
@@ -514,10 +518,23 @@ class DimensionDecorator(BaseDecorator):
GEOM_GLSL = """
uniform vec2 winsize;
uniform float viewportDrawingScale;
uniform float use_oblique_style;
layout(lines) in;
layout(line_strip, max_vertices=MAX_POINTS) out;
void oblique_dimension_head(in vec4 dir, in float size, in float angle, out vec4 head[OBLIQUE_HEAD_VERTS]) {
float c = cos(angle), s = sin(angle);
vec4 ortho = vec4(-dir.y, dir.x, 0, 0);
head[0] = -dir * size*0.66;
head[1] = vec4(0);
head[2] = ortho * size;
head[3] = -ortho * size;
head[4] = vec4(0);
head[5] = vec4((mat2(c, +s, -s, c) * dir.xy) * size * 0.47, 0, 0);
head[6] = -head[5];
}
void main() {
vec4 clip2win = matCLIP2WIN();
vec4 win2clip = matWIN2CLIP();
@@ -529,49 +546,78 @@ class DimensionDecorator(BaseDecorator):
vec4 p;
vec4 head[3];
arrow_head(dir, viewportDrawingScale * ARROW_SIZE, ARROW_ANGLE, head);
if (use_oblique_style > 0) {
vec4 head[OBLIQUE_HEAD_VERTS];
oblique_dimension_head(dir, viewportDrawingScale * OLBIQUE_SYMBOL_SIZE, OBLIQUE_SYMBOL_ANGLE, head);
// start edge arrow
gl_Position = p0;
EmitVertex();
p = p0w + head[1];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p0w + head[2];
gl_Position = WIN2CLIP(p);
EmitVertex();
gl_Position = p0;
EmitVertex();
EndPrimitive();
// start edge arrow
for (int i = 0; i < OBLIQUE_HEAD_VERTS; i++) {
gl_Position = WIN2CLIP((p0w + head[i]));
EmitVertex();
}
EndPrimitive();
// end edge arrow
gl_Position = p1;
EmitVertex();
p = p1w - head[1];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p1w - head[2];
gl_Position = WIN2CLIP(p);
EmitVertex();
gl_Position = p1;
EmitVertex();
EndPrimitive();
// end edge arrow
for (int i = 0; i < OBLIQUE_HEAD_VERTS; i++) {
gl_Position = WIN2CLIP((p1w - head[i]));
EmitVertex();
}
EndPrimitive();
// stem, with gaps for arrows
p = p0w + head[0];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p1w - head[0];
gl_Position = WIN2CLIP(p);
EmitVertex();
EndPrimitive();
// stem
gl_Position = p0;
EmitVertex();
gl_Position = p1;
EmitVertex();
EndPrimitive();
} else {
vec4 head[3];
arrow_head(dir, viewportDrawingScale * ARROW_SIZE, ARROW_ANGLE, head);
// start edge arrow
gl_Position = p0;
EmitVertex();
p = p0w + head[1];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p0w + head[2];
gl_Position = WIN2CLIP(p);
EmitVertex();
gl_Position = p0;
EmitVertex();
EndPrimitive();
// end edge arrow
gl_Position = p1;
EmitVertex();
p = p1w - head[1];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p1w - head[2];
gl_Position = WIN2CLIP(p);
EmitVertex();
gl_Position = p1;
EmitVertex();
EndPrimitive();
// stem, with gaps for arrows
p = p0w + head[0];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p1w - head[0];
gl_Position = WIN2CLIP(p);
EmitVertex();
EndPrimitive();
}
}
"""
def decorate(self, context, obj):
verts, idxs, _ = self.get_path_geom(obj, topo=False)
self.draw_lines(context, obj, verts, idxs)
dimension_style = DecoratorData.get_dimension_style(obj)
self.draw_lines(
context, obj, verts, idxs, extra_float_kwargs={"use_oblique_style": float(dimension_style == "oblique")}
)
self.draw_labels(context, obj, verts, idxs)
def draw_labels(self, context, obj, vertices, indices):
@@ -806,7 +852,7 @@ class LeaderDecorator(BaseDecorator):
props = obj.BIMTextProperties
text_data = props.get_text_edited_data() if props.is_editing else DecoratorData.get_ifc_text_data(obj)
text = text_data["Literals"][0]['CurrentValue']
text = text_data["Literals"][0]["CurrentValue"]
self.draw_label(context, text, pos, dir, gap=0, center=False, vcenter=False)
@@ -1332,18 +1378,22 @@ class PlanLevelDecorator(LevelDecorator):
region = context.region
region3d = context.region_data
for verts in splines:
v0 = verts[0]
v1 = verts[1]
p0 = location_3d_to_region_2d(region, region3d, v0)
p1 = location_3d_to_region_2d(region, region3d, v1)
p0, p1 = [location_3d_to_region_2d(region, region3d, v) for v in verts[:2]]
dir = p1 - p0
if dir.length < 1:
continue
if dir.x > 0:
box_alignment = "bottom-left"
else:
box_alignment = "bottom-right"
dir *= -1
z = verts[-1].z / unit_scale
z = ifcopenshell.util.geolocation.auto_z2e(tool.Ifc.get(), z)
z *= unit_scale
text = "RL " + self.format_value(context, z)
self.draw_label(context, text, p0, dir, gap=8, center=False)
self.draw_label(context, text, p0, dir, gap=8, center=False, box_alignment=box_alignment)
class SectionLevelDecorator(LevelDecorator):
@@ -2094,7 +2144,7 @@ class TextDecorator(BaseDecorator):
def matrix_only_rotation(m):
return m.to_3x3().normalized().to_4x4()
text_dir = Vector((1,0))
text_dir = Vector((1, 0))
text_dir_world = matrix_only_rotation(region3d.perspective_matrix.inverted()) @ text_dir.to_3d()
text_dir_world_rotated = matrix_only_rotation(obj.matrix_world) @ text_dir_world
text_dir = (matrix_only_rotation(region3d.perspective_matrix) @ text_dir_world_rotated).to_2d().normalized()
@@ -562,6 +562,7 @@ def disable_editing_extrusion_profile(context):
element = tool.Ifc.get_entity(obj)
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
profile_mesh = obj.data
blenderbim.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
@@ -571,6 +572,7 @@ def disable_editing_extrusion_profile(context):
is_global=True,
should_sync_changes_first=False,
)
tool.Geometry.delete_data(profile_mesh)
return {"FINISHED"}
@@ -663,6 +665,7 @@ class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
ifcopenshell.util.element.replace_attribute(inverse, old_profile, profile)
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_profile)
profile_mesh = obj.data
blenderbim.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
@@ -672,6 +675,7 @@ class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
is_global=True,
should_sync_changes_first=False,
)
bpy.data.meshes.remove(profile_mesh)
footprint_context = ifcopenshell.util.representation.get_context(
tool.Ifc.get(), "Plan", "FootPrint", "SKETCH_VIEW"
@@ -734,15 +738,20 @@ class SetArcIndex(bpy.types.Operator):
return bool(obj) and obj.type == "MESH"
def cancel_message(self, msg):
self.report({"WARNING"}, msg)
self.report({"ERROR"}, msg)
return {"CANCELLED"}
def execute(self, context):
# NOTE: undo won't remove new verex group
# because of jumping between modes
obj = context.active_object
bm = tool.Blender.get_bmesh_for_mesh(obj.data)
selected_vertices = [v.index for v in bm.verts if v.select]
if len(selected_vertices) != 3:
return self.cancel_message("Select 3 vertices.")
bpy.ops.object.mode_set(mode="OBJECT")
selected_vertices = [v.index for v in obj.data.vertices if v.select]
in_group = any([bool(obj.data.vertices[v].groups) for v in selected_vertices])
for group in obj.vertex_groups:
group.remove(selected_vertices)
@@ -148,7 +148,9 @@ def disable_editing_arbitrary_profile(context):
if obj and obj.data and obj.data.BIMMeshProperties.subshape_type == "PROFILE":
ProfileDecorator.uninstall()
bpy.ops.object.mode_set(mode="OBJECT")
profile_mesh = obj.data
bpy.data.objects.remove(obj)
bpy.data.meshes.remove(profile_mesh)
# need to update profile manager ui
# if this was called from decorator
@@ -191,7 +193,10 @@ class EditArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.object.mode_set(mode="EDIT")
return
profile_mesh = obj.data
bpy.data.objects.remove(obj)
bpy.data.meshes.remove(profile_mesh)
profile.ProfileType = old_profile.ProfileType
profile.ProfileName = old_profile.ProfileName
for inverse in tool.Ifc.get().get_inverse(old_profile):
+5
View File
@@ -176,6 +176,11 @@ class Model(blenderbim.core.tool.Model):
@classmethod
def import_profile(cls, profile, obj=None, position=None):
"""Creates new profile mesh and assigns it to `obj`,
if `obj` is `None` then new "Profile" object will be created.
Need to make sure to remove temporary mesh/object after use to avoid orphan data.
"""
cls.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
if position is None: