Skip to content

Commit

Permalink
fix(create): Update straight skeleton component based on refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswmackey authored and Chris Mackey committed Jun 28, 2024
1 parent e0da64b commit b4d9b94
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 77 deletions.
12 changes: 6 additions & 6 deletions honeybee_grasshopper_core/json/HB_Straight_Skeleton.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
{
"version": "1.8.0",
"version": "1.8.1",
"nickname": "Skeleton",
"outputs": [
[
{
"access": "None",
"name": "polyskel",
"name": "skeleton",
"description": "A list of line segments that represent the straight skeleton of\nthe input _floor_geo. This will be output from the component no matter\nwhat the input _floor_geo is.",
"type": null,
"default": null
},
{
"access": "None",
"name": "perim_poly",
"description": "A list of breps representing the perimeter polygons of the input\n_floor_geo. This will only be ouput if an offset_ is input and the\nstraight skeleton is not self-intersecting.",
"description": "A list of breps representing the perimeter polygons of the input\n_floor_geo. This will only be ouput if an offset_ is input.",
"type": null,
"default": null
},
{
"access": "None",
"name": "core_poly",
"description": "A list of breps representing the core polygons of the input\n_floor_geo. This will only be ouput if an offset_ is input and the\nstraight skeleton is not self-intersecting, and the offset is not\nso great as to eliminate the core.",
"description": "A list of breps representing the core polygons of the input\n_floor_geo. This will only be ouput if an offset_ is input and the offset\nis not so great as to eliminate the core.",
"type": null,
"default": null
}
Expand All @@ -43,8 +43,8 @@
}
],
"subcategory": "0 :: Create",
"code": "\ntry: # import the core ladybug_geometry dependencies\n from ladybug_geometry.geometry2d.line import LineSegment2D\n from ladybug_geometry.geometry2d.polygon import Polygon2D\n from ladybug_geometry.geometry3d.pointvector import Point3D\n from ladybug_geometry.geometry3d.face import Face3D\nexcept ImportError as e:\n raise ImportError('\\nFailed to import ladybug_geometry:\\n\\t{}'.format(e))\n\ntry: # import the core ladybug_geometry dependencies\n from ladybug_geometry_polyskel.polyskel import skeleton_as_edge_list\n from ladybug_geometry_polyskel.polysplit import perimeter_core_subpolygons\nexcept ImportError as e:\n raise ImportError('\\nFailed to import ladybug_geometry:\\n\\t{}'.format(e))\n\ntry: # import the ladybug_{{cad}} dependencies\n from ladybug_{{cad}}.config import tolerance\n from ladybug_{{cad}}.togeometry import to_face3d\n from ladybug_{{cad}}.fromgeometry import from_face3d, from_linesegment2d\n from ladybug_{{cad}}.{{plugin}} import all_required_inputs, list_to_data_tree\nexcept ImportError as e:\n raise ImportError('\\nFailed to import ladybug_{{cad}}:\\n\\t{}'.format(e))\n\n\ndef polygon_to_brep(polygon, z_height):\n \"\"\"Convert a ladybug Polygon2D or list of polygon2D into {{Cad}} breps.\"\"\"\n if isinstance(polygon, list): # face with holes\n verts = []\n for poly in polygon:\n verts.append([Point3D(pt.x, pt.y, z_height) for pt in poly])\n return from_face3d(Face3D(verts[0], holes=verts[1:]))\n else:\n verts = [Point3D(pt.x, pt.y, z_height) for pt in polygon]\n return from_face3d(Face3D(verts))\n\n\nif all_required_inputs(ghenv.Component):\n # first extract the straight skeleton from the geometry\n polyskel, boundaries, hole_polygons = [], [], []\n for face in to_face3d(_floor_geo):\n # convert the input geometry into Polygon2D for straight skeleton analysis\n boundary = Polygon2D.from_array([(pt.x, pt.y) for pt in face.boundary])\n if boundary.is_clockwise:\n boundary = boundary.reverse()\n holes, z_height = None, face[0].z\n if face.has_holes:\n holes = []\n for hole in face.holes:\n h_poly = Polygon2D.from_array([(pt.x, pt.y) for pt in hole])\n if not h_poly.is_clockwise:\n h_poly = h_poly.reverse()\n holes.append(h_poly)\n boundaries.append(boundary)\n hole_polygons.append(holes)\n # compute the skeleton and convert to line segments\n skel_lines = skeleton_as_edge_list(boundary, holes, tolerance)\n skel_lines_rh = [from_linesegment2d(LineSegment2D.from_array(line), z_height)\n for line in skel_lines]\n polyskel.append(skel_lines_rh)\n\n # try to compute core/perimeter polygons if an offset_ is input\n if offset_:\n perim_poly, core_poly = [], []\n for bound, holes in zip(boundaries, hole_polygons):\n try:\n perim, core = perimeter_core_subpolygons(\n bound, offset_, holes, tolerance)\n perim_poly.append([polygon_to_brep(p, z_height) for p in perim])\n if holes is None or len(holes) == 0:\n core_poly.append([polygon_to_brep(p, z_height) for p in core])\n else:\n core_poly.append([polygon_to_brep(core, z_height)])\n except (RuntimeError, TypeError) as e:\n print(e)\n perim_poly.append(None)\n core_poly.append(None)\n\n # convert outputs to data trees\n polyskel = list_to_data_tree(polyskel)\n perim_poly = list_to_data_tree(perim_poly)\n core_poly = list_to_data_tree(core_poly)\n",
"code": "\ntry: # import the core ladybug_geometry dependencies\n from ladybug_geometry.geometry3d import LineSegment3D\nexcept ImportError as e:\n raise ImportError('\\nFailed to import ladybug_geometry:\\n\\t{}'.format(e))\n\ntry: # import the core ladybug_geometry dependencies\n from ladybug_geometry_polyskel.polyskel import skeleton_as_edge_list\n from ladybug_geometry_polyskel.polysplit import perimeter_core_subfaces_and_skeleton\nexcept ImportError as e:\n raise ImportError('\\nFailed to import ladybug_geometry:\\n\\t{}'.format(e))\n\ntry: # import the ladybug_{{cad}} dependencies\n from ladybug_{{cad}}.config import tolerance\n from ladybug_{{cad}}.togeometry import to_face3d\n from ladybug_{{cad}}.fromgeometry import from_face3d, from_linesegment3d\n from ladybug_{{cad}}.{{plugin}} import all_required_inputs, list_to_data_tree\nexcept ImportError as e:\n raise ImportError('\\nFailed to import ladybug_{{cad}}:\\n\\t{}'.format(e))\n\n\nif all_required_inputs(ghenv.Component):\n # extract the straight skeleton and sub-faces from the geometry\n skeleton, perim_poly, core_poly = [], [], []\n for face in to_face3d(_floor_geo):\n if offset_ is not None and offset_ > 0:\n skel, perim, core = perimeter_core_subfaces_and_skeleton(\n face, offset_, tolerance)\n skeleton.append([from_linesegment3d(lin) for lin in skel])\n perim_poly.append([from_face3d(p) for p in perim])\n core_poly.append([from_face3d(c) for c in core])\n else:\n skel_2d = skeleton_as_edge_list(\n face.boundary_polygon2d, face.hole_polygon2d,\n tolerance, intersect=True)\n skel_3d = []\n for seg in skel_2d:\n verts_3d = tuple(face.plane.xy_to_xyz(pt) for pt in seg.vertices)\n skel_3d.append(LineSegment3D.from_end_points(*verts_3d))\n skeleton.append([from_linesegment3d(lin) for lin in skel_3d])\n\n # convert outputs to data trees\n skeleton = list_to_data_tree(skeleton)\n perim_poly = list_to_data_tree(perim_poly)\n core_poly = list_to_data_tree(core_poly)\n",
"category": "Honeybee",
"name": "HB Straight Skeleton",
"description": "Get the straight skeleton of any horizontal planar geometry.\n_\nThis is can also be used to generate core/perimeter sub-polygons if an offset is\ninput AND the straight skeleton is not self-intersecting. In the event of a\nself-intersecting straight skeleton, the output line segments can still be used\nto assist with the manual creation of core/perimeter offsets.\n_\nThis component uses a modified version of the the polyskel package\n(https://github.com/Botffy/polyskel) by Armin Scipiades (aka. @Bottfy),\nwhich is, itself, a Python implementation of the straight skeleton\nalgorithm as described by Felkel and Obdrzalek in their 1998 conference paper\nStraight skeleton implementation\n(https://github.com/Botffy/polyskel/blob/master/doc/StraightSkeletonImplementation.pdf).\n-"
"description": "Get the straight skeleton and core/perimeter sub-faces for any planar geometry.\n_\nThis component uses a modified version of the the polyskel package\n(https://github.com/Botffy/polyskel) by Armin Scipiades (aka. @Bottfy),\nwhich is, itself, a Python implementation of the straight skeleton\nalgorithm as described by Felkel and Obdrzalek in their 1998 conference paper\nStraight skeleton implementation\n(https://github.com/Botffy/polyskel/blob/master/doc/StraightSkeletonImplementation.pdf).\n-"
}
99 changes: 28 additions & 71 deletions honeybee_grasshopper_core/src/HB Straight Skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,14 @@
# @license AGPL-3.0-or-later <https://spdx.org/licenses/AGPL-3.0-or-later>

"""
Get the straight skeleton of any horizontal planar geometry.
_
This is can also be used to generate core/perimeter sub-polygons if an offset is
input AND the straight skeleton is not self-intersecting. In the event of a
self-intersecting straight skeleton, the output line segments can still be used
to assist with the manual creation of core/perimeter offsets.
Get the straight skeleton and core/perimeter sub-faces for any planar geometry.
_
This component uses a modified version of the the polyskel package
(https://github.com/Botffy/polyskel) by Armin Scipiades (aka. @Bottfy),
which is, itself, a Python implementation of the straight skeleton
algorithm as described by Felkel and Obdrzalek in their 1998 conference paper
Straight skeleton implementation
(https://github.com/Botffy/polyskel/blob/master/doc/StraightSkeletonImplementation.pdf).
-
Args:
Expand All @@ -33,102 +27,65 @@
self-intersecting, perim_poly and core_poly will be ouput.
Returns:
polyskel: A list of line segments that represent the straight skeleton of
report: Reports, errors, warnings, etc.
skeleton: A list of line segments that represent the straight skeleton of
the input _floor_geo. This will be output from the component no matter
what the input _floor_geo is.
perim_poly: A list of breps representing the perimeter polygons of the input
_floor_geo. This will only be ouput if an offset_ is input and the
straight skeleton is not self-intersecting.
_floor_geo. This will only be ouput if an offset_ is input.
core_poly: A list of breps representing the core polygons of the input
_floor_geo. This will only be ouput if an offset_ is input and the
straight skeleton is not self-intersecting, and the offset is not
so great as to eliminate the core.
_floor_geo. This will only be ouput if an offset_ is input and the offset
is not so great as to eliminate the core.
"""

ghenv.Component.Name = 'HB Straight Skeleton'
ghenv.Component.NickName = 'Skeleton'
ghenv.Component.Message = '1.8.0'
ghenv.Component.Message = '1.8.1'
ghenv.Component.Category = 'Honeybee'
ghenv.Component.SubCategory = '0 :: Create'
ghenv.Component.AdditionalHelpFromDocStrings = '0'

try: # import the core ladybug_geometry dependencies
from ladybug_geometry.geometry2d.line import LineSegment2D
from ladybug_geometry.geometry2d.polygon import Polygon2D
from ladybug_geometry.geometry3d.pointvector import Point3D
from ladybug_geometry.geometry3d.face import Face3D
from ladybug_geometry.geometry3d import LineSegment3D
except ImportError as e:
raise ImportError('\nFailed to import ladybug_geometry:\n\t{}'.format(e))

try: # import the core ladybug_geometry dependencies
from ladybug_geometry_polyskel.polyskel import skeleton_as_edge_list
from ladybug_geometry_polyskel.polysplit import perimeter_core_subpolygons
from ladybug_geometry_polyskel.polysplit import perimeter_core_subfaces_and_skeleton
except ImportError as e:
raise ImportError('\nFailed to import ladybug_geometry:\n\t{}'.format(e))

try: # import the ladybug_rhino dependencies
from ladybug_rhino.config import tolerance
from ladybug_rhino.togeometry import to_face3d
from ladybug_rhino.fromgeometry import from_face3d, from_linesegment2d
from ladybug_rhino.fromgeometry import from_face3d, from_linesegment3d
from ladybug_rhino.grasshopper import all_required_inputs, list_to_data_tree
except ImportError as e:
raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))


def polygon_to_brep(polygon, z_height):
"""Convert a ladybug Polygon2D or list of polygon2D into Rhino breps."""
if isinstance(polygon, list): # face with holes
verts = []
for poly in polygon:
verts.append([Point3D(pt.x, pt.y, z_height) for pt in poly])
return from_face3d(Face3D(verts[0], holes=verts[1:]))
else:
verts = [Point3D(pt.x, pt.y, z_height) for pt in polygon]
return from_face3d(Face3D(verts))


if all_required_inputs(ghenv.Component):
# first extract the straight skeleton from the geometry
polyskel, boundaries, hole_polygons = [], [], []
# extract the straight skeleton and sub-faces from the geometry
skeleton, perim_poly, core_poly = [], [], []
for face in to_face3d(_floor_geo):
# convert the input geometry into Polygon2D for straight skeleton analysis
boundary = Polygon2D.from_array([(pt.x, pt.y) for pt in face.boundary])
if boundary.is_clockwise:
boundary = boundary.reverse()
holes, z_height = None, face[0].z
if face.has_holes:
holes = []
for hole in face.holes:
h_poly = Polygon2D.from_array([(pt.x, pt.y) for pt in hole])
if not h_poly.is_clockwise:
h_poly = h_poly.reverse()
holes.append(h_poly)
boundaries.append(boundary)
hole_polygons.append(holes)
# compute the skeleton and convert to line segments
skel_lines = skeleton_as_edge_list(boundary, holes, tolerance)
skel_lines_rh = [from_linesegment2d(LineSegment2D.from_array(line), z_height)
for line in skel_lines]
polyskel.append(skel_lines_rh)

# try to compute core/perimeter polygons if an offset_ is input
if offset_:
perim_poly, core_poly = [], []
for bound, holes in zip(boundaries, hole_polygons):
try:
perim, core = perimeter_core_subpolygons(
bound, offset_, holes, tolerance)
perim_poly.append([polygon_to_brep(p, z_height) for p in perim])
if holes is None or len(holes) == 0:
core_poly.append([polygon_to_brep(p, z_height) for p in core])
else:
core_poly.append([polygon_to_brep(core, z_height)])
except (RuntimeError, TypeError) as e:
print(e)
perim_poly.append(None)
core_poly.append(None)
if offset_ is not None and offset_ > 0:
skel, perim, core = perimeter_core_subfaces_and_skeleton(
face, offset_, tolerance)
skeleton.append([from_linesegment3d(lin) for lin in skel])
perim_poly.append([from_face3d(p) for p in perim])
core_poly.append([from_face3d(c) for c in core])
else:
skel_2d = skeleton_as_edge_list(
face.boundary_polygon2d, face.hole_polygon2d,
tolerance, intersect=True)
skel_3d = []
for seg in skel_2d:
verts_3d = tuple(face.plane.xy_to_xyz(pt) for pt in seg.vertices)
skel_3d.append(LineSegment3D.from_end_points(*verts_3d))
skeleton.append([from_linesegment3d(lin) for lin in skel_3d])

# convert outputs to data trees
polyskel = list_to_data_tree(polyskel)
skeleton = list_to_data_tree(skeleton)
perim_poly = list_to_data_tree(perim_poly)
core_poly = list_to_data_tree(core_poly)
Binary file modified honeybee_grasshopper_core/user_objects/HB Straight Skeleton.ghuser
Binary file not shown.

0 comments on commit b4d9b94

Please sign in to comment.