mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 18:21:59 +00:00
Ooops, fix black formatter ignoring bonsai folder #5178
This commit is contained in:
+1
-1
@@ -4,7 +4,7 @@ include = '''
|
|||||||
src/(
|
src/(
|
||||||
bcf
|
bcf
|
||||||
|bcfserver
|
|bcfserver
|
||||||
|blenderbim
|
|bonsai
|
||||||
|bsdd
|
|bsdd
|
||||||
|foundationserver
|
|foundationserver
|
||||||
|ifc2ca
|
|ifc2ca
|
||||||
|
|||||||
@@ -800,4 +800,4 @@ class GenerateCostScheduleBrowser(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
core.generate_cost_schedule_browser(tool.Cost, cost_schedule=tool.Ifc.get().by_id(self.cost_schedule))
|
core.generate_cost_schedule_browser(tool.Cost, cost_schedule=tool.Ifc.get().by_id(self.cost_schedule))
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -73,8 +73,12 @@ class BIM_PT_cost_schedules(Panel):
|
|||||||
row1.label(text="Schedule tools")
|
row1.label(text="Schedule tools")
|
||||||
row1 = col.row(align=True)
|
row1 = col.row(align=True)
|
||||||
row1.alignment = "RIGHT"
|
row1.alignment = "RIGHT"
|
||||||
row1.operator("bim.export_cost_schedules", text="Export spreadsheet", icon="EXPORT").cost_schedule = cost_schedule["id"]
|
row1.operator("bim.export_cost_schedules", text="Export spreadsheet", icon="EXPORT").cost_schedule = (
|
||||||
row1.operator("bim.generate_cost_schedule_browser", text="Generate spreadsheet browsser", icon="URL").cost_schedule = cost_schedule["id"]
|
cost_schedule["id"]
|
||||||
|
)
|
||||||
|
row1.operator(
|
||||||
|
"bim.generate_cost_schedule_browser", text="Generate spreadsheet browsser", icon="URL"
|
||||||
|
).cost_schedule = cost_schedule["id"]
|
||||||
row2 = col.row(align=True)
|
row2 = col.row(align=True)
|
||||||
row2.alignment = "RIGHT"
|
row2.alignment = "RIGHT"
|
||||||
op = row2.operator("bim.select_cost_schedule_products", icon="RESTRICT_SELECT_OFF", text="Assigned")
|
op = row2.operator("bim.select_cost_schedule_products", icon="RESTRICT_SELECT_OFF", text="Assigned")
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ def register():
|
|||||||
|
|
||||||
workspace.load_custom_icons()
|
workspace.load_custom_icons()
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
if not bpy.app.background:
|
if not bpy.app.background:
|
||||||
bpy.utils.unregister_tool(workspace.WallTool)
|
bpy.utils.unregister_tool(workspace.WallTool)
|
||||||
@@ -231,7 +232,7 @@ def unregister():
|
|||||||
bpy.utils.unregister_tool(workspace.CableCarrierTool)
|
bpy.utils.unregister_tool(workspace.CableCarrierTool)
|
||||||
bpy.utils.unregister_tool(workspace.CableTool)
|
bpy.utils.unregister_tool(workspace.CableTool)
|
||||||
bpy.utils.unregister_tool(workspace.BimTool)
|
bpy.utils.unregister_tool(workspace.BimTool)
|
||||||
|
|
||||||
del bpy.types.Scene.BIMModelProperties
|
del bpy.types.Scene.BIMModelProperties
|
||||||
del bpy.types.Object.BIMArrayProperties
|
del bpy.types.Object.BIMArrayProperties
|
||||||
del bpy.types.Object.BIMStairProperties
|
del bpy.types.Object.BIMStairProperties
|
||||||
@@ -245,4 +246,4 @@ def unregister():
|
|||||||
bpy.types.VIEW3D_MT_mesh_add.remove(ui.add_mesh_object_menu)
|
bpy.types.VIEW3D_MT_mesh_add.remove(ui.add_mesh_object_menu)
|
||||||
bpy.types.VIEW3D_MT_add.remove(ui.add_menu)
|
bpy.types.VIEW3D_MT_add.remove(ui.add_menu)
|
||||||
|
|
||||||
workspace.unload_custom_icons()
|
workspace.unload_custom_icons()
|
||||||
|
|||||||
@@ -413,7 +413,9 @@ class PolylineDecorator:
|
|||||||
|
|
||||||
distance = (snap_vector - last_point).length
|
distance = (snap_vector - last_point).length
|
||||||
if distance > 0:
|
if distance > 0:
|
||||||
angle = tool.Cad.angle_3_vectors(second_to_last_point, last_point, snap_vector, new_angle=None, degrees=True)
|
angle = tool.Cad.angle_3_vectors(
|
||||||
|
second_to_last_point, last_point, snap_vector, new_angle=None, degrees=True
|
||||||
|
)
|
||||||
|
|
||||||
# Round angle to the nearest 0.05
|
# Round angle to the nearest 0.05
|
||||||
angle = round(angle / 0.05) * 0.05
|
angle = round(angle / 0.05) * 0.05
|
||||||
@@ -547,12 +549,17 @@ class PolylineDecorator:
|
|||||||
if context.scene.unit_settings.length_unit == "MILLIMETERS":
|
if context.scene.unit_settings.length_unit == "MILLIMETERS":
|
||||||
factor = 1000
|
factor = 1000
|
||||||
|
|
||||||
return format_distance(
|
return format_distance(value * factor, precision=precision, suppress_zero_inches=True, in_unit_length=True)
|
||||||
value * factor, precision=precision, suppress_zero_inches=True, in_unit_length=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def draw_input_panel(self, context):
|
def draw_input_panel(self, context):
|
||||||
texts = {"D": "Distance: ", "A": "Angle: ", "X": "X coord: ", "Y": "Y coord: ", "Z": "Z coord:", "AREA": "Area: "}
|
texts = {
|
||||||
|
"D": "Distance: ",
|
||||||
|
"A": "Angle: ",
|
||||||
|
"X": "X coord: ",
|
||||||
|
"Y": "Y coord: ",
|
||||||
|
"Z": "Z coord:",
|
||||||
|
"AREA": "Area: ",
|
||||||
|
}
|
||||||
|
|
||||||
self.addon_prefs = tool.Blender.get_addon_preferences()
|
self.addon_prefs = tool.Blender.get_addon_preferences()
|
||||||
self.font_id = 0
|
self.font_id = 0
|
||||||
@@ -687,7 +694,6 @@ class PolylineDecorator:
|
|||||||
for i in range(len(polyline_points) - 1):
|
for i in range(len(polyline_points) - 1):
|
||||||
polyline_edges.append([i, i + 1])
|
polyline_edges.append([i, i + 1])
|
||||||
|
|
||||||
|
|
||||||
# Line for angle axis snap
|
# Line for angle axis snap
|
||||||
if snap_prop.snap_type == "Axis":
|
if snap_prop.snap_type == "Axis":
|
||||||
self.line_shader.uniform_float("lineWidth", 0.75)
|
self.line_shader.uniform_float("lineWidth", 0.75)
|
||||||
@@ -728,4 +734,3 @@ class PolylineDecorator:
|
|||||||
self.draw_batch("POINTS", polyline_points, decorator_color_selected)
|
self.draw_batch("POINTS", polyline_points, decorator_color_selected)
|
||||||
if len(polyline_points) > 1:
|
if len(polyline_points) > 1:
|
||||||
self.draw_batch("LINES", polyline_points, decorator_color_selected, polyline_edges)
|
self.draw_batch("LINES", polyline_points, decorator_color_selected, polyline_edges)
|
||||||
|
|
||||||
|
|||||||
@@ -111,11 +111,13 @@ class PolylinePoint(PropertyGroup):
|
|||||||
y: bpy.props.FloatProperty(name="Y")
|
y: bpy.props.FloatProperty(name="Y")
|
||||||
z: bpy.props.FloatProperty(name="Z")
|
z: bpy.props.FloatProperty(name="Z")
|
||||||
|
|
||||||
|
|
||||||
class PolylineMeasurement(PropertyGroup):
|
class PolylineMeasurement(PropertyGroup):
|
||||||
dim: bpy.props.StringProperty(name="Dimension")
|
dim: bpy.props.StringProperty(name="Dimension")
|
||||||
angle: bpy.props.StringProperty(name="Angle")
|
angle: bpy.props.StringProperty(name="Angle")
|
||||||
position: bpy.props.FloatVectorProperty(name="Decorator Position", size=3)
|
position: bpy.props.FloatVectorProperty(name="Decorator Position", size=3)
|
||||||
|
|
||||||
|
|
||||||
class BIMModelProperties(PropertyGroup):
|
class BIMModelProperties(PropertyGroup):
|
||||||
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class)
|
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class)
|
||||||
relating_type_id: bpy.props.EnumProperty(
|
relating_type_id: bpy.props.EnumProperty(
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ class DrawPolylineWall(bpy.types.Operator):
|
|||||||
self.number_output = "".join(self.number_input)
|
self.number_output = "".join(self.number_input)
|
||||||
if self.input_type != "A":
|
if self.input_type != "A":
|
||||||
self.number_output = PolylineDecorator.format_input_panel_units(context, float(self.number_output))
|
self.number_output = PolylineDecorator.format_input_panel_units(context, float(self.number_output))
|
||||||
|
|
||||||
self.input_panel[self.input_type] = self.number_output
|
self.input_panel[self.input_type] = self.number_output
|
||||||
|
|
||||||
PolylineDecorator.set_input_panel(self.input_panel, self.input_type)
|
PolylineDecorator.set_input_panel(self.input_panel, self.input_type)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ from bonsai.bim.module.model.prop import get_ifc_class
|
|||||||
def check_display_mode():
|
def check_display_mode():
|
||||||
global display_mode
|
global display_mode
|
||||||
try:
|
try:
|
||||||
theme = bpy.context.preferences.themes['Default']
|
theme = bpy.context.preferences.themes["Default"]
|
||||||
text_color = theme.user_interface.wcol_menu_item.text
|
text_color = theme.user_interface.wcol_menu_item.text
|
||||||
background_color = theme.user_interface.wcol_menu_item.outline
|
background_color = theme.user_interface.wcol_menu_item.outline
|
||||||
print(f"text_color = {text_color}")
|
print(f"text_color = {text_color}")
|
||||||
@@ -50,12 +50,12 @@ def load_custom_icons():
|
|||||||
global custom_icon_previews
|
global custom_icon_previews
|
||||||
if display_mode is None:
|
if display_mode is None:
|
||||||
check_display_mode()
|
check_display_mode()
|
||||||
|
|
||||||
icons_dir = os.path.join(os.path.dirname(__file__), "..", "..", "data", "icons")
|
icons_dir = os.path.join(os.path.dirname(__file__), "..", "..", "data", "icons")
|
||||||
custom_icon_previews = bpy.utils.previews.new()
|
custom_icon_previews = bpy.utils.previews.new()
|
||||||
|
|
||||||
prefix = f"{display_mode}_"
|
prefix = f"{display_mode}_"
|
||||||
|
|
||||||
for entry in os.scandir(icons_dir):
|
for entry in os.scandir(icons_dir):
|
||||||
if entry.name.endswith(".png") and entry.name.startswith(prefix):
|
if entry.name.endswith(".png") and entry.name.startswith(prefix):
|
||||||
name = os.path.splitext(entry.name)[0].replace(prefix, "", 1)
|
name = os.path.splitext(entry.name)[0].replace(prefix, "", 1)
|
||||||
@@ -1181,6 +1181,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
else:
|
else:
|
||||||
bpy.ops.bim.show_openings()
|
bpy.ops.bim.show_openings()
|
||||||
|
|
||||||
|
|
||||||
custom_icon_previews = None
|
custom_icon_previews = None
|
||||||
display_mode = None
|
display_mode = None
|
||||||
|
|
||||||
@@ -1190,4 +1191,4 @@ MODIFIERS = {
|
|||||||
"A": ("EVENT_ALT", "OPTION" if sys.platform == "Darwin" else "ALT"),
|
"A": ("EVENT_ALT", "OPTION" if sys.platform == "Darwin" else "ALT"),
|
||||||
"C": ("EVENT_CTRL", "CTRL"),
|
"C": ("EVENT_CTRL", "CTRL"),
|
||||||
"S": ("EVENT_SHIFT", "⇧"),
|
"S": ("EVENT_SHIFT", "⇧"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2410,7 +2410,7 @@ class MeasureTool(bpy.types.Operator):
|
|||||||
self.number_output = "".join(self.number_input)
|
self.number_output = "".join(self.number_input)
|
||||||
if self.input_type != "A":
|
if self.input_type != "A":
|
||||||
self.number_output = PolylineDecorator.format_input_panel_units(context, float(self.number_output))
|
self.number_output = PolylineDecorator.format_input_panel_units(context, float(self.number_output))
|
||||||
|
|
||||||
self.input_panel[self.input_type] = self.number_output
|
self.input_panel[self.input_type] = self.number_output
|
||||||
|
|
||||||
PolylineDecorator.set_input_panel(self.input_panel, self.input_type)
|
PolylineDecorator.set_input_panel(self.input_panel, self.input_type)
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ class BIM_PT_colour_by_property(Panel):
|
|||||||
if props.max_mode == "MANUAL":
|
if props.max_mode == "MANUAL":
|
||||||
row.prop(props, "max_value", text="")
|
row.prop(props, "max_value", text="")
|
||||||
|
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.operator("bim.colour_by_property", icon="BRUSH_DATA")
|
row.operator("bim.colour_by_property", icon="BRUSH_DATA")
|
||||||
row.operator("bim.reset_object_colours")
|
row.operator("bim.reset_object_colours")
|
||||||
|
|||||||
@@ -87,9 +87,7 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
elif (container_obj := props.container_obj) and (container := tool.Ifc.get_entity(container_obj)):
|
elif (container_obj := props.container_obj) and (container := tool.Ifc.get_entity(container_obj)):
|
||||||
pass
|
pass
|
||||||
for element_obj in context.selected_objects:
|
for element_obj in context.selected_objects:
|
||||||
core.assign_container(
|
core.assign_container(tool.Ifc, tool.Collector, tool.Spatial, container=container, element_obj=element_obj)
|
||||||
tool.Ifc, tool.Collector, tool.Spatial, container=container, element_obj=element_obj
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingContainer(bpy.types.Operator, tool.Ifc.Operator):
|
class EnableEditingContainer(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
|||||||
@@ -402,4 +402,4 @@ def add_currency(ifc: tool.Ifc, cost: tool.Cost) -> ifcopenshell.entity_instance
|
|||||||
|
|
||||||
def generate_cost_schedule_browser(cost: tool.Cost, cost_schedule: ifcopenshell.entity_instance) -> bpy.types.Panel:
|
def generate_cost_schedule_browser(cost: tool.Cost, cost_schedule: ifcopenshell.entity_instance) -> bpy.types.Panel:
|
||||||
cost_schedule_data = cost.create_cost_schedule_json(cost_schedule)
|
cost_schedule_data = cost.create_cost_schedule_json(cost_schedule)
|
||||||
return cost.generate_cost_schedule_browser(cost_schedule_data)
|
return cost.generate_cost_schedule_browser(cost_schedule_data)
|
||||||
|
|||||||
@@ -102,10 +102,13 @@ class Cad:
|
|||||||
# Calculate the unsigned angle between the "d1" and "d2" vectors
|
# Calculate the unsigned angle between the "d1" and "d2" vectors
|
||||||
a = d1.angle(d2)
|
a = d1.angle(d2)
|
||||||
|
|
||||||
|
|
||||||
# Determine the sign of the angle based on the provided axis
|
# Determine the sign of the angle based on the provided axis
|
||||||
# If new_angle, determine the direction of the rotation
|
# If new_angle, determine the direction of the rotation
|
||||||
parameter = round(axis.z, 2) < 0 or (round(axis.y, 2) == 0 and round(axis.x < 0)) or (round(axis.x, 2) == 0 and round(axis.y < 0))
|
parameter = (
|
||||||
|
round(axis.z, 2) < 0
|
||||||
|
or (round(axis.y, 2) == 0 and round(axis.x < 0))
|
||||||
|
or (round(axis.x, 2) == 0 and round(axis.y < 0))
|
||||||
|
)
|
||||||
if new_angle is not None:
|
if new_angle is not None:
|
||||||
rot_mat = Matrix.Rotation(new_angle, 3, axis)
|
rot_mat = Matrix.Rotation(new_angle, 3, axis)
|
||||||
rot_vector = (d1 @ rot_mat) if parameter else (rot_mat @ d1)
|
rot_vector = (d1 @ rot_mat) if parameter else (rot_mat @ d1)
|
||||||
@@ -181,7 +184,7 @@ class Cad:
|
|||||||
"""
|
"""
|
||||||
Calculate the closest points on two line segments.
|
Calculate the closest points on two line segments.
|
||||||
Note: This function doesn't use intersect_line_line
|
Note: This function doesn't use intersect_line_line
|
||||||
|
|
||||||
> edge1: tuple of two vectors (v1, v2) representing the first segment
|
> edge1: tuple of two vectors (v1, v2) representing the first segment
|
||||||
> edge2: tuple of two vectors (v3, v4) representing the second segment
|
> edge2: tuple of two vectors (v3, v4) representing the second segment
|
||||||
< returns: tuple of two vectors (C1, C2) or (None, None) if lines are parallel
|
< returns: tuple of two vectors (C1, C2) or (None, None) if lines are parallel
|
||||||
@@ -199,19 +202,19 @@ class Cad:
|
|||||||
d2 = (P2_end - P2).normalized()
|
d2 = (P2_end - P2).normalized()
|
||||||
|
|
||||||
n = d1.cross(d2)
|
n = d1.cross(d2)
|
||||||
|
|
||||||
# if n is zero, lines are parallel
|
# if n is zero, lines are parallel
|
||||||
if n.length == 0:
|
if n.length == 0:
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
n2 = d2.cross(n)
|
n2 = d2.cross(n)
|
||||||
|
|
||||||
C1 = P1 + ((P2 - P1).dot(n2) / (d1.dot(n2))) * d1
|
C1 = P1 + ((P2 - P1).dot(n2) / (d1.dot(n2))) * d1
|
||||||
|
|
||||||
n1 = d1.cross(n)
|
n1 = d1.cross(n)
|
||||||
|
|
||||||
C2 = P2 + ((P1 - P2).dot(n1) / (d2.dot(n1))) * d2
|
C2 = P2 + ((P1 - P2).dot(n1) / (d2.dot(n1))) * d2
|
||||||
|
|
||||||
return C1, C2
|
return C1, C2
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -811,6 +811,7 @@ class Cost(bonsai.core.tool.Cost):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def create_cost_schedule_json(cls, cost_schedule: ifcopenshell.entity_instance) -> dict:
|
def create_cost_schedule_json(cls, cost_schedule: ifcopenshell.entity_instance) -> dict:
|
||||||
from bonsai.bim.module.cost.data import CostSchedulesData
|
from bonsai.bim.module.cost.data import CostSchedulesData
|
||||||
|
|
||||||
CostSchedulesData.load()
|
CostSchedulesData.load()
|
||||||
cost_items = CostSchedulesData.data["cost_items"]
|
cost_items = CostSchedulesData.data["cost_items"]
|
||||||
data = []
|
data = []
|
||||||
@@ -832,7 +833,7 @@ class Cost(bonsai.core.tool.Cost):
|
|||||||
return None
|
return None
|
||||||
for rel in cost_item.IsNestedBy or []:
|
for rel in cost_item.IsNestedBy or []:
|
||||||
for sub_cost_item in rel.RelatedObjects or []:
|
for sub_cost_item in rel.RelatedObjects or []:
|
||||||
cls.create_cost_item_json(sub_cost_item, cost_items,cost_item_data["is_nested_by"])
|
cls.create_cost_item_json(sub_cost_item, cost_items, cost_item_data["is_nested_by"])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_cost_item_sum(cls, cost_item: ifcopenshell.entity_instance) -> bool:
|
def is_cost_item_sum(cls, cost_item: ifcopenshell.entity_instance) -> bool:
|
||||||
@@ -856,4 +857,4 @@ class Cost(bonsai.core.tool.Cost):
|
|||||||
def generate_cost_schedule_browser(cls, cost_schedule_data: list[dict[str, Any]]) -> None:
|
def generate_cost_schedule_browser(cls, cost_schedule_data: list[dict[str, Any]]) -> None:
|
||||||
if not bpy.context.scene.WebProperties.is_connected:
|
if not bpy.context.scene.WebProperties.is_connected:
|
||||||
bpy.ops.bim.connect_websocket_server(page="costing")
|
bpy.ops.bim.connect_websocket_server(page="costing")
|
||||||
tool.Web.send_webui_data(data=cost_schedule_data, data_key="cost_items", event="cost_items")
|
tool.Web.send_webui_data(data=cost_schedule_data, data_key="cost_items", event="cost_items")
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class Raycast(bonsai.core.tool.Raycast):
|
|||||||
xmin, xmax, ymin, ymax = bbox
|
xmin, xmax, ymin, ymax = bbox
|
||||||
|
|
||||||
# extends bbox boundaries to improve snap
|
# extends bbox boundaries to improve snap
|
||||||
if offset:
|
if offset:
|
||||||
xmin -= offset
|
xmin -= offset
|
||||||
xmax += offset
|
xmax += offset
|
||||||
ymin -= offset
|
ymin -= offset
|
||||||
@@ -193,7 +193,9 @@ class Raycast(bonsai.core.tool.Raycast):
|
|||||||
loc = Vector((0, 0, 0))
|
loc = Vector((0, 0, 0))
|
||||||
|
|
||||||
polyline_data = bpy.context.scene.BIMModelProperties.polyline_point
|
polyline_data = bpy.context.scene.BIMModelProperties.polyline_point
|
||||||
polyline_data = polyline_data[: len(polyline_data) - 1] # It doesn't make sense to snap to the last point created
|
polyline_data = polyline_data[
|
||||||
|
: len(polyline_data) - 1
|
||||||
|
] # It doesn't make sense to snap to the last point created
|
||||||
polyline_points = []
|
polyline_points = []
|
||||||
for point_data in polyline_data:
|
for point_data in polyline_data:
|
||||||
point = Vector((point_data.x, point_data.y, point_data.z))
|
point = Vector((point_data.x, point_data.y, point_data.z))
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ class Snap(bonsai.core.tool.Snap):
|
|||||||
|
|
||||||
return snap_point
|
return snap_point
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def select_snap_point(cls, snap_points, hit, threshold):
|
def select_snap_point(cls, snap_points, hit, threshold):
|
||||||
shortest_distance = None
|
shortest_distance = None
|
||||||
@@ -168,7 +167,7 @@ class Snap(bonsai.core.tool.Snap):
|
|||||||
if len(polyline_data) > 2:
|
if len(polyline_data) > 2:
|
||||||
first_point = polyline_data[0]
|
first_point = polyline_data[0]
|
||||||
last_point = polyline_data[-1]
|
last_point = polyline_data[-1]
|
||||||
if not(first_point.x == last_point.x and first_point.y == last_point.y and first_point.z == last_point.z):
|
if not (first_point.x == last_point.x and first_point.y == last_point.y and first_point.z == last_point.z):
|
||||||
polyline_point = bpy.context.scene.BIMModelProperties.polyline_point.add()
|
polyline_point = bpy.context.scene.BIMModelProperties.polyline_point.add()
|
||||||
polyline_point.x = first_point.x
|
polyline_point.x = first_point.x
|
||||||
polyline_point.y = first_point.y
|
polyline_point.y = first_point.y
|
||||||
@@ -361,7 +360,6 @@ class Snap(bonsai.core.tool.Snap):
|
|||||||
best_hit = hit_world
|
best_hit = hit_world
|
||||||
best_face_index = face_index
|
best_face_index = face_index
|
||||||
|
|
||||||
|
|
||||||
if best_obj is not None:
|
if best_obj is not None:
|
||||||
return best_obj, best_hit, best_face_index
|
return best_obj, best_hit, best_face_index
|
||||||
|
|
||||||
|
|||||||
@@ -333,7 +333,6 @@ class Web(bonsai.core.tool.Web):
|
|||||||
bpy.context.view_layer.objects.active = obj
|
bpy.context.view_layer.objects.active = obj
|
||||||
obj.select_set(True)
|
obj.select_set(True)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def handle_cost_operator(cls, operator_data: dict) -> None:
|
def handle_cost_operator(cls, operator_data: dict) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -348,10 +347,11 @@ class Web(bonsai.core.tool.Web):
|
|||||||
cost_schedules = ifc_file.by_type("IfcCostSchedule")
|
cost_schedules = ifc_file.by_type("IfcCostSchedule")
|
||||||
cost_schedules_json = [cs.get_info(recursive=True) for cs in cost_schedules]
|
cost_schedules_json = [cs.get_info(recursive=True) for cs in cost_schedules]
|
||||||
currency = tool.Cost.currency()
|
currency = tool.Cost.currency()
|
||||||
cls.send_webui_data(data={
|
cls.send_webui_data(
|
||||||
"cost_schedules": cost_schedules_json,
|
data={"cost_schedules": cost_schedules_json, "currency": currency},
|
||||||
"currency": currency
|
data_key="cost_schedules",
|
||||||
}, data_key="cost_schedules", event="cost_schedules")
|
event="cost_schedules",
|
||||||
|
)
|
||||||
if operator_data["type"] == "loadCostSchedule":
|
if operator_data["type"] == "loadCostSchedule":
|
||||||
cost_schedule = ifc_file.by_id(operator_data["costScheduleId"])
|
cost_schedule = ifc_file.by_id(operator_data["costScheduleId"])
|
||||||
bonsai.core.cost.enable_editing_cost_items(tool.Cost, cost_schedule=cost_schedule)
|
bonsai.core.cost.enable_editing_cost_items(tool.Cost, cost_schedule=cost_schedule)
|
||||||
@@ -375,36 +375,28 @@ class Web(bonsai.core.tool.Web):
|
|||||||
cls.load_cost_schedule_web_ui(cost_schedule)
|
cls.load_cost_schedule_web_ui(cost_schedule)
|
||||||
if operator_data["type"] == "editCostItemName":
|
if operator_data["type"] == "editCostItemName":
|
||||||
cost_item = tool.Ifc.get().by_id(operator_data["costItemId"])
|
cost_item = tool.Ifc.get().by_id(operator_data["costItemId"])
|
||||||
tool.Ifc.run(
|
tool.Ifc.run("cost.edit_cost_item", cost_item=cost_item, attributes={"Name": operator_data["name"]})
|
||||||
"cost.edit_cost_item",
|
|
||||||
cost_item=cost_item,
|
|
||||||
attributes = {"Name": operator_data["name"]}
|
|
||||||
)
|
|
||||||
tool.Cost.load_cost_schedule_tree()
|
tool.Cost.load_cost_schedule_tree()
|
||||||
if operator_data["type"] == "enableEditingCostValues":
|
if operator_data["type"] == "enableEditingCostValues":
|
||||||
cost_item = tool.Ifc.get().by_id(operator_data["costItemId"])
|
cost_item = tool.Ifc.get().by_id(operator_data["costItemId"])
|
||||||
cost_values = ifcopenshell.util.cost.get_cost_values(cost_item)
|
cost_values = ifcopenshell.util.cost.get_cost_values(cost_item)
|
||||||
cls.send_webui_data(data={
|
cls.send_webui_data(
|
||||||
"cost_values": cost_values,
|
data={"cost_values": cost_values, "cost_item_id": operator_data["costItemId"]},
|
||||||
"cost_item_id": operator_data["costItemId"]
|
data_key="cost_values",
|
||||||
}, data_key="cost_values", event="cost_values")
|
event="cost_values",
|
||||||
|
)
|
||||||
if operator_data["type"] == "addCostValue":
|
if operator_data["type"] == "addCostValue":
|
||||||
value = ifcopenshell.api.cost.add_cost_value(
|
value = ifcopenshell.api.cost.add_cost_value(
|
||||||
ifc_file,
|
ifc_file,
|
||||||
parent=ifc_file.by_id(operator_data["costItemId"]),
|
parent=ifc_file.by_id(operator_data["costItemId"]),
|
||||||
)
|
)
|
||||||
cls.send_webui_data(
|
cls.send_webui_data(
|
||||||
data={
|
data={"cost_value_id": value.id(), "cost_item_id": operator_data["costItemId"]},
|
||||||
"cost_value_id" : value.id(),
|
data_key="cost_value",
|
||||||
"cost_item_id":operator_data["costItemId"]},
|
event="cost_value",
|
||||||
data_key="cost_value",
|
|
||||||
event="cost_value"
|
|
||||||
)
|
)
|
||||||
if operator_data["type"] == "deleteCostValue":
|
if operator_data["type"] == "deleteCostValue":
|
||||||
bpy.ops.bim.remove_cost_value(
|
bpy.ops.bim.remove_cost_value(parent=operator_data["costItemId"], cost_value=operator_data["costValueId"])
|
||||||
parent=operator_data["costItemId"],
|
|
||||||
cost_value=operator_data["costValueId"]
|
|
||||||
)
|
|
||||||
cost_item = ifc_file.by_id(operator_data["costItemId"])
|
cost_item = ifc_file.by_id(operator_data["costItemId"])
|
||||||
cost_schedule = tool.Cost.get_cost_schedule(cost_item=cost_item)
|
cost_schedule = tool.Cost.get_cost_schedule(cost_item=cost_item)
|
||||||
cls.load_cost_schedule_web_ui(cost_schedule)
|
cls.load_cost_schedule_web_ui(cost_schedule)
|
||||||
@@ -416,29 +408,19 @@ class Web(bonsai.core.tool.Web):
|
|||||||
print("editing cost value data", value_data)
|
print("editing cost value data", value_data)
|
||||||
value = ifc_file.by_id(value_data["id"])
|
value = ifc_file.by_id(value_data["id"])
|
||||||
if value_data["costType"] == "FIXED":
|
if value_data["costType"] == "FIXED":
|
||||||
attributes= {
|
attributes = {"AppliedValue": value_data["appliedValue"], "Category": None}
|
||||||
"AppliedValue": value_data["appliedValue"],
|
|
||||||
"Category": None
|
|
||||||
}
|
|
||||||
elif value_data["costType"] == "CATEGORY":
|
elif value_data["costType"] == "CATEGORY":
|
||||||
attributes= {
|
attributes = {
|
||||||
"AppliedValue": value_data["appliedValue"],
|
"AppliedValue": value_data["appliedValue"],
|
||||||
"Category": value_data["costCategory"],
|
"Category": value_data["costCategory"],
|
||||||
}
|
}
|
||||||
elif value_data["costType"] == "SUM":
|
elif value_data["costType"] == "SUM":
|
||||||
attributes= {
|
attributes = {"Category": "*"}
|
||||||
"Category": '*'
|
ifcopenshell.api.cost.edit_cost_value(file=ifc_file, cost_value=value, attributes=attributes)
|
||||||
}
|
|
||||||
ifcopenshell.api.cost.edit_cost_value(
|
|
||||||
file=ifc_file,
|
|
||||||
cost_value=value,
|
|
||||||
attributes= attributes
|
|
||||||
)
|
|
||||||
print(value.get_info())
|
print(value.get_info())
|
||||||
tool.Cost.load_cost_schedule_tree()
|
tool.Cost.load_cost_schedule_tree()
|
||||||
cls.load_cost_schedule_web_ui(cost_schedule)
|
cls.load_cost_schedule_web_ui(cost_schedule)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_cost_schedule_web_ui(cls, cost_schedule):
|
def load_cost_schedule_web_ui(cls, cost_schedule):
|
||||||
json_data = tool.Cost.create_cost_schedule_json(cost_schedule)
|
json_data = tool.Cost.create_cost_schedule_json(cost_schedule)
|
||||||
|
|||||||
@@ -10,98 +10,106 @@ import xml.etree.ElementTree as ET
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
SVG_FILE = os.path.join(SCRIPT_DIR, 'bonsai_icons.svg')
|
SVG_FILE = os.path.join(SCRIPT_DIR, "bonsai_icons.svg")
|
||||||
EXPORT_FOLDER = os.path.join(SCRIPT_DIR, '..', 'bonsai', 'bim', 'data', 'icons')
|
EXPORT_FOLDER = os.path.join(SCRIPT_DIR, "..", "bonsai", "bim", "data", "icons")
|
||||||
|
|
||||||
overwrite_all = False
|
overwrite_all = False
|
||||||
skip_all = False
|
skip_all = False
|
||||||
|
|
||||||
|
|
||||||
def dark_to_light(svg_content):
|
def dark_to_light(svg_content):
|
||||||
svg_content = re.sub(r'#ffffff', '#434343', svg_content, flags=re.IGNORECASE) # white to drak grey
|
svg_content = re.sub(r"#ffffff", "#434343", svg_content, flags=re.IGNORECASE) # white to drak grey
|
||||||
|
|
||||||
svg_content = re.sub(r'#00d27b', '#009d5c', svg_content, flags=re.IGNORECASE) # make green darker
|
svg_content = re.sub(r"#00d27b", "#009d5c", svg_content, flags=re.IGNORECASE) # make green darker
|
||||||
svg_content = re.sub(r'#009a5f', '#00663f', svg_content, flags=re.IGNORECASE) # make dark green darker
|
svg_content = re.sub(r"#009a5f", "#00663f", svg_content, flags=re.IGNORECASE) # make dark green darker
|
||||||
svg_content = re.sub(r'#75ffaf', '#3dff8f', svg_content, flags=re.IGNORECASE) # make light green darker
|
svg_content = re.sub(r"#75ffaf", "#3dff8f", svg_content, flags=re.IGNORECASE) # make light green darker
|
||||||
|
|
||||||
svg_content = re.sub(r'#cce3ff', '#3391ff', svg_content, flags=re.IGNORECASE) # make blue darker
|
svg_content = re.sub(r"#cce3ff", "#3391ff", svg_content, flags=re.IGNORECASE) # make blue darker
|
||||||
svg_content = re.sub(r'#4c9fff', '#005fcc', svg_content, flags=re.IGNORECASE) # make dark blue darker
|
svg_content = re.sub(r"#4c9fff", "#005fcc", svg_content, flags=re.IGNORECASE) # make dark blue darker
|
||||||
svg_content = re.sub(r'#c9e0ff', '#80b8ff', svg_content, flags=re.IGNORECASE) # make light blue darker
|
svg_content = re.sub(r"#c9e0ff", "#80b8ff", svg_content, flags=re.IGNORECASE) # make light blue darker
|
||||||
|
|
||||||
return svg_content
|
return svg_content
|
||||||
|
|
||||||
|
|
||||||
def prompt_overwrite(file_path, png_name):
|
def prompt_overwrite(file_path, png_name):
|
||||||
global overwrite_all, skip_all
|
global overwrite_all, skip_all
|
||||||
|
|
||||||
if skip_all and os.path.exists(file_path):
|
if skip_all and os.path.exists(file_path):
|
||||||
return 'n'
|
return "n"
|
||||||
|
|
||||||
if overwrite_all:
|
if overwrite_all:
|
||||||
return 'y'
|
return "y"
|
||||||
|
|
||||||
if os.path.exists(file_path):
|
if os.path.exists(file_path):
|
||||||
while True:
|
while True:
|
||||||
response = input(f"File '{png_name}' already exists.\nOverwrite? (Enter = yes, s = skip, y = yes all, n = no all): ").strip().lower()
|
response = (
|
||||||
if response in {'', 'y', 'n', 's'}:
|
input(
|
||||||
if response == 'y':
|
f"File '{png_name}' already exists.\nOverwrite? (Enter = yes, s = skip, y = yes all, n = no all): "
|
||||||
|
)
|
||||||
|
.strip()
|
||||||
|
.lower()
|
||||||
|
)
|
||||||
|
if response in {"", "y", "n", "s"}:
|
||||||
|
if response == "y":
|
||||||
overwrite_all = True
|
overwrite_all = True
|
||||||
elif response == 'n':
|
elif response == "n":
|
||||||
skip_all = True
|
skip_all = True
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
print("Invalid option. Please enter Enter, y, n, or s.")
|
print("Invalid option. Please enter Enter, y, n, or s.")
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def export_svg_group(group_content, group_label, mode, output_folder):
|
def export_svg_group(group_content, group_label, mode, output_folder):
|
||||||
temp_svg_file = os.path.join(output_folder, f'{group_label}_{mode}.svg')
|
temp_svg_file = os.path.join(output_folder, f"{group_label}_{mode}.svg")
|
||||||
svg_content = f"""<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
|
svg_content = f"""<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
width="31.999998" height="31.999998" viewBox="0 0 8.4666661 8.4666661">
|
width="31.999998" height="31.999998" viewBox="0 0 8.4666661 8.4666661">
|
||||||
{group_content}
|
{group_content}
|
||||||
</svg>"""
|
</svg>"""
|
||||||
|
|
||||||
with open(temp_svg_file, 'w') as file:
|
with open(temp_svg_file, "w") as file:
|
||||||
file.write(svg_content)
|
file.write(svg_content)
|
||||||
|
|
||||||
png_name = f'{mode}_{group_label}.png'
|
png_name = f"{mode}_{group_label}.png"
|
||||||
output_png_file = os.path.join(output_folder, png_name)
|
output_png_file = os.path.join(output_folder, png_name)
|
||||||
|
|
||||||
user_choice = prompt_overwrite(output_png_file, png_name)
|
user_choice = prompt_overwrite(output_png_file, png_name)
|
||||||
|
|
||||||
if user_choice in {'y', ''}:
|
|
||||||
subprocess.run(['inkscape', temp_svg_file, '--export-type=png', '--export-filename=' + output_png_file])
|
|
||||||
print(f'\033[32mExported PNG file: {output_png_file}\033[0m')
|
|
||||||
|
|
||||||
|
if user_choice in {"y", ""}:
|
||||||
elif user_choice == 'n':
|
subprocess.run(["inkscape", temp_svg_file, "--export-type=png", "--export-filename=" + output_png_file])
|
||||||
|
print(f"\033[32mExported PNG file: {output_png_file}\033[0m")
|
||||||
|
|
||||||
|
elif user_choice == "n":
|
||||||
print(f"Skipping {png_name}")
|
print(f"Skipping {png_name}")
|
||||||
|
|
||||||
elif user_choice == 's':
|
|
||||||
print(f'Skipped exporting {output_png_file}.')
|
|
||||||
|
|
||||||
os.remove(temp_svg_file)
|
|
||||||
|
|
||||||
|
elif user_choice == "s":
|
||||||
|
print(f"Skipped exporting {output_png_file}.")
|
||||||
|
|
||||||
|
os.remove(temp_svg_file)
|
||||||
|
|
||||||
|
|
||||||
def export_svg_groups_to_png(svg_file, output_folder):
|
def export_svg_groups_to_png(svg_file, output_folder):
|
||||||
tree = ET.parse(svg_file)
|
tree = ET.parse(svg_file)
|
||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
ns = {'svg': 'http://www.w3.org/2000/svg'}
|
ns = {"svg": "http://www.w3.org/2000/svg"}
|
||||||
|
|
||||||
for group in root.findall('.//svg:g', ns):
|
for group in root.findall(".//svg:g", ns):
|
||||||
group_label = group.get('{http://www.inkscape.org/namespaces/inkscape}label')
|
group_label = group.get("{http://www.inkscape.org/namespaces/inkscape}label")
|
||||||
if not group_label:
|
if not group_label:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
style = group.get('style', '')
|
style = group.get("style", "")
|
||||||
if 'display:none' in style:
|
if "display:none" in style:
|
||||||
style = style.replace('display:none', 'display:inline')
|
style = style.replace("display:none", "display:inline")
|
||||||
elif 'display' not in style:
|
elif "display" not in style:
|
||||||
style += ';display:inline'
|
style += ";display:inline"
|
||||||
group.set('style', style)
|
group.set("style", style)
|
||||||
|
|
||||||
group_content = ET.tostring(group, encoding='unicode', method='xml')
|
group_content = ET.tostring(group, encoding="unicode", method="xml")
|
||||||
export_svg_group(group_content, group_label, 'dm', output_folder)
|
export_svg_group(group_content, group_label, "dm", output_folder)
|
||||||
light_mode_svg = dark_to_light(group_content)
|
light_mode_svg = dark_to_light(group_content)
|
||||||
export_svg_group(light_mode_svg, group_label, 'lm', output_folder)
|
export_svg_group(light_mode_svg, group_label, "lm", output_folder)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
os.makedirs(EXPORT_FOLDER, exist_ok=True)
|
os.makedirs(EXPORT_FOLDER, exist_ok=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user