mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 17:57:02 +00:00
Bundle bpypolyskel so that users can start playing with the hipped roof generator
This commit is contained in:
@@ -655,6 +655,13 @@ endif
|
|||||||
cd dist/working/ && cp -r pkg_resources ../blenderbim/libs/site/packages/
|
cd dist/working/ && cp -r pkg_resources ../blenderbim/libs/site/packages/
|
||||||
rm -rf dist/working
|
rm -rf dist/working
|
||||||
|
|
||||||
|
# Required for hipped roof generation
|
||||||
|
mkdir dist/working
|
||||||
|
cd dist/working && wget https://github.com/prochitecture/bpypolyskel/archive/refs/heads/master.zip
|
||||||
|
cd dist/working && unzip master.zip
|
||||||
|
cp -r dist/working/bpypolyskel-master/bpypolyskel dist/blenderbim/libs/site/packages/
|
||||||
|
rm -rf dist/working
|
||||||
|
|
||||||
cd dist/blenderbim && $(SED) "s/999999/$(VERSION)/" __init__.py
|
cd dist/blenderbim && $(SED) "s/999999/$(VERSION)/" __init__.py
|
||||||
cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
|
cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
|
||||||
rm -rf dist/blenderbim
|
rm -rf dist/blenderbim
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from . import (
|
|||||||
array,
|
array,
|
||||||
product,
|
product,
|
||||||
wall,
|
wall,
|
||||||
|
roof,
|
||||||
slab,
|
slab,
|
||||||
space,
|
space,
|
||||||
stair,
|
stair,
|
||||||
@@ -48,7 +49,6 @@ classes = (
|
|||||||
product.AddEmptyType,
|
product.AddEmptyType,
|
||||||
product.AlignProduct,
|
product.AlignProduct,
|
||||||
product.ChangeTypePage,
|
product.ChangeTypePage,
|
||||||
product.GenerateHippedRoof,
|
|
||||||
product.LoadTypeThumbnails,
|
product.LoadTypeThumbnails,
|
||||||
workspace.Hotkey,
|
workspace.Hotkey,
|
||||||
wall.AlignWall,
|
wall.AlignWall,
|
||||||
@@ -77,6 +77,7 @@ classes = (
|
|||||||
profile.ExtendProfile,
|
profile.ExtendProfile,
|
||||||
profile.RecalculateProfile,
|
profile.RecalculateProfile,
|
||||||
profile.Rotate90,
|
profile.Rotate90,
|
||||||
|
roof.GenerateHippedRoof,
|
||||||
slab.DisableEditingExtrusionProfile,
|
slab.DisableEditingExtrusionProfile,
|
||||||
slab.DisableEditingSketchExtrusionProfile,
|
slab.DisableEditingSketchExtrusionProfile,
|
||||||
slab.EditExtrusionProfile,
|
slab.EditExtrusionProfile,
|
||||||
|
|||||||
@@ -516,93 +516,3 @@ def ensure_material_unassigned(usecase_path, ifc_file, settings):
|
|||||||
obj.active_material_index = i - total_removed
|
obj.active_material_index = i - total_removed
|
||||||
bpy.ops.object.material_slot_remove({"object": obj})
|
bpy.ops.object.material_slot_remove({"object": obj})
|
||||||
total_removed += 1
|
total_removed += 1
|
||||||
|
|
||||||
|
|
||||||
class GenerateHippedRoof(bpy.types.Operator, tool.Ifc.Operator):
|
|
||||||
bl_idname = "bim.generate_hipped_roof"
|
|
||||||
bl_label = "Generate Hipped Roof"
|
|
||||||
bl_options = {"REGISTER"}
|
|
||||||
mode: bpy.props.StringProperty(default="ANGLE")
|
|
||||||
height: bpy.props.FloatProperty(default=1)
|
|
||||||
angle: bpy.props.FloatProperty(default=10)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
|
||||||
import bmesh
|
|
||||||
import shapely
|
|
||||||
from math import tan, radians
|
|
||||||
from bpypolyskel import bpypolyskel
|
|
||||||
|
|
||||||
obj = bpy.context.active_object
|
|
||||||
if not obj:
|
|
||||||
return
|
|
||||||
|
|
||||||
boundary_lines = []
|
|
||||||
|
|
||||||
for edge in obj.data.edges:
|
|
||||||
boundary_lines.append(
|
|
||||||
shapely.LineString([obj.data.vertices[edge.vertices[0]].co, obj.data.vertices[edge.vertices[1]].co])
|
|
||||||
)
|
|
||||||
|
|
||||||
unioned_boundaries = shapely.union_all(shapely.GeometryCollection(boundary_lines))
|
|
||||||
closed_polygons = shapely.polygonize(unioned_boundaries.geoms)
|
|
||||||
|
|
||||||
roof_polygon = None
|
|
||||||
biggest_area = 0
|
|
||||||
for polygon in closed_polygons.geoms:
|
|
||||||
area = polygon.area
|
|
||||||
if area > biggest_area:
|
|
||||||
roof_polygon = polygon
|
|
||||||
biggest_area = area
|
|
||||||
|
|
||||||
roof_polygon = shapely.force_3d(roof_polygon)
|
|
||||||
|
|
||||||
if not shapely.is_ccw(roof_polygon):
|
|
||||||
roof_polygon = roof_polygon.reverse()
|
|
||||||
|
|
||||||
# Define vertices for the base footprint of the building at height 0.0
|
|
||||||
# counterclockwise order
|
|
||||||
verts = [Vector(v) for v in roof_polygon.exterior.coords[0:-1]]
|
|
||||||
total_exterior_verts = len(verts)
|
|
||||||
next_index = total_exterior_verts
|
|
||||||
|
|
||||||
inner_loops = None
|
|
||||||
for interior in roof_polygon.interiors:
|
|
||||||
if inner_loops is None:
|
|
||||||
inner_loops = []
|
|
||||||
loop = interior.coords[0:-1]
|
|
||||||
total_verts = len(loop)
|
|
||||||
verts.extend([Vector(v) for v in loop])
|
|
||||||
inner_loops.append((next_index, total_verts))
|
|
||||||
next_index += total_verts
|
|
||||||
|
|
||||||
unit_vectors = None # we have no unit vectors, let them computed by polygonize()
|
|
||||||
start_exterior_index = 0
|
|
||||||
|
|
||||||
faces = []
|
|
||||||
|
|
||||||
if self.mode == "HEIGHT":
|
|
||||||
height = self.height
|
|
||||||
angle = 0.0
|
|
||||||
else:
|
|
||||||
angle = tan(radians(round(self.angle, 4)))
|
|
||||||
height = 0.0
|
|
||||||
|
|
||||||
faces = bpypolyskel.polygonize(
|
|
||||||
verts, start_exterior_index, total_exterior_verts, inner_loops, height, angle, faces, unit_vectors
|
|
||||||
)
|
|
||||||
|
|
||||||
edges = []
|
|
||||||
mesh = bpy.data.meshes.new(name="Building_with_Roof")
|
|
||||||
mesh.from_pydata(verts, edges, faces)
|
|
||||||
|
|
||||||
bm = bmesh.new()
|
|
||||||
bm.from_mesh(mesh)
|
|
||||||
|
|
||||||
extrusion = bmesh.ops.extrude_face_region(bm, geom=bm.faces)
|
|
||||||
extruded_verts = [g for g in extrusion["geom"] if isinstance(g, bmesh.types.BMVert)]
|
|
||||||
bmesh.ops.translate(bm, vec=[0.0, 0.0, 0.1], verts=extruded_verts)
|
|
||||||
|
|
||||||
bm.to_mesh(mesh)
|
|
||||||
bm.free()
|
|
||||||
|
|
||||||
obj.data = mesh
|
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import bmesh
|
||||||
|
import shapely
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
from math import tan, radians
|
||||||
|
from mathutils import Vector, Matrix
|
||||||
|
from bpypolyskel import bpypolyskel
|
||||||
|
|
||||||
|
|
||||||
|
class GenerateHippedRoof(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.generate_hipped_roof"
|
||||||
|
bl_label = "Generate Hipped Roof"
|
||||||
|
bl_options = {"REGISTER"}
|
||||||
|
mode: bpy.props.StringProperty(default="ANGLE")
|
||||||
|
height: bpy.props.FloatProperty(default=1)
|
||||||
|
angle: bpy.props.FloatProperty(default=10)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
obj = bpy.context.active_object
|
||||||
|
if not obj:
|
||||||
|
return
|
||||||
|
|
||||||
|
boundary_lines = []
|
||||||
|
|
||||||
|
for edge in obj.data.edges:
|
||||||
|
boundary_lines.append(
|
||||||
|
shapely.LineString([obj.data.vertices[edge.vertices[0]].co, obj.data.vertices[edge.vertices[1]].co])
|
||||||
|
)
|
||||||
|
|
||||||
|
unioned_boundaries = shapely.union_all(shapely.GeometryCollection(boundary_lines))
|
||||||
|
closed_polygons = shapely.polygonize(unioned_boundaries.geoms)
|
||||||
|
|
||||||
|
roof_polygon = None
|
||||||
|
biggest_area = 0
|
||||||
|
for polygon in closed_polygons.geoms:
|
||||||
|
area = polygon.area
|
||||||
|
if area > biggest_area:
|
||||||
|
roof_polygon = polygon
|
||||||
|
biggest_area = area
|
||||||
|
|
||||||
|
roof_polygon = shapely.force_3d(roof_polygon)
|
||||||
|
|
||||||
|
if not shapely.is_ccw(roof_polygon):
|
||||||
|
roof_polygon = roof_polygon.reverse()
|
||||||
|
|
||||||
|
# Define vertices for the base footprint of the building at height 0.0
|
||||||
|
# counterclockwise order
|
||||||
|
verts = [Vector(v) for v in roof_polygon.exterior.coords[0:-1]]
|
||||||
|
total_exterior_verts = len(verts)
|
||||||
|
next_index = total_exterior_verts
|
||||||
|
|
||||||
|
inner_loops = None
|
||||||
|
for interior in roof_polygon.interiors:
|
||||||
|
if inner_loops is None:
|
||||||
|
inner_loops = []
|
||||||
|
loop = interior.coords[0:-1]
|
||||||
|
total_verts = len(loop)
|
||||||
|
verts.extend([Vector(v) for v in loop])
|
||||||
|
inner_loops.append((next_index, total_verts))
|
||||||
|
next_index += total_verts
|
||||||
|
|
||||||
|
unit_vectors = None # we have no unit vectors, let them computed by polygonize()
|
||||||
|
start_exterior_index = 0
|
||||||
|
|
||||||
|
faces = []
|
||||||
|
|
||||||
|
if self.mode == "HEIGHT":
|
||||||
|
height = self.height
|
||||||
|
angle = 0.0
|
||||||
|
else:
|
||||||
|
angle = tan(radians(round(self.angle, 4)))
|
||||||
|
height = 0.0
|
||||||
|
|
||||||
|
faces = bpypolyskel.polygonize(
|
||||||
|
verts, start_exterior_index, total_exterior_verts, inner_loops, height, angle, faces, unit_vectors
|
||||||
|
)
|
||||||
|
|
||||||
|
edges = []
|
||||||
|
mesh = bpy.data.meshes.new(name="Building_with_Roof")
|
||||||
|
mesh.from_pydata(verts, edges, faces)
|
||||||
|
|
||||||
|
bm = bmesh.new()
|
||||||
|
bm.from_mesh(mesh)
|
||||||
|
|
||||||
|
extrusion = bmesh.ops.extrude_face_region(bm, geom=bm.faces)
|
||||||
|
extruded_verts = [g for g in extrusion["geom"] if isinstance(g, bmesh.types.BMVert)]
|
||||||
|
bmesh.ops.translate(bm, vec=[0.0, 0.0, 0.1], verts=extruded_verts)
|
||||||
|
|
||||||
|
bm.to_mesh(mesh)
|
||||||
|
bm.free()
|
||||||
|
|
||||||
|
obj.data = mesh
|
||||||
Reference in New Issue
Block a user