cfox04

properties/portal.py

Sep 13th, 2022 (edited)
726
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.42 KB | None | 0 0
  1. import numpy
  2. from ..properties.mlo import PortalProperties
  3.  
  4. class PortalCreatorHelper:
  5.     @classmethod
  6.     def poll(cls, context):
  7.         return get_selected_archetype(context) is not None and (context.active_object and context.active_object.mode == "EDIT")
  8.    
  9.     @staticmethod
  10.     def sort_2d_coords_winding(coords: list[tuple[float, float]]):
  11.         """Sort 4 2D points in a winding order."""
  12.         # Thank you Pranav! https://stackoverflow.com/a/70624269/11903486
  13.         np_coords = numpy.array(np_coords)
  14.         centroid = numpy.sum(np_coords, axis=0) / np_coords.shape[0]
  15.         vector_from_centroid = np_coords - centroid
  16.         vector_angle = numpy.arctan2(
  17.             vector_from_centroid[:, 1], vector_from_centroid[:, 0])
  18.         # Find the indices that give a sorted vector_angle array
  19.         sort_order = list(numpy.argsort(-vector_angle))
  20.  
  21.         # Apply sort_order to original pts array.
  22.         return [coords[i] for i in sort_order]
  23.  
  24.     @staticmethod
  25.     def is_coplanar(points: list[tuple[float, float, float]]):
  26.         """Check if 4 3D points lie on the same plane."""
  27.         leg1 = points[1] - points[0]
  28.         leg2 = points[2] - points[0]
  29.         leg3 = points[3] - points[0]
  30.  
  31.         return leg3.dot(leg1.cross(leg2)) == 0
  32.    
  33.     @staticmethod
  34.     def get_screen_coords(coords_3d: list[tuple[float, float, float]]) -> list[tuple[float, float]]:
  35.         """Get 2D screen coords of the provided 3d coords."""
  36.         region = bpy.context.region
  37.         region_3d = bpy.context.space_data.region_3d
  38.  
  39.         corners2d = []
  40.         for corner in coords_3d:
  41.             corners2d.append(location_3d_to_region_2d(
  42.                 region, region_3d, corner))
  43.        
  44.         return corners2d
  45.    
  46.     def get_selected_portal_verts(self, context):
  47.         selected_verts = []
  48.  
  49.         for obj in context.objects_in_mode:
  50.             selected_verts.extend(get_selected_vertices(obj))
  51.        
  52.         return selected_verts
  53.    
  54.     def selected_archetype_has_asset(self, context):
  55.         selected_archetype = get_selected_archetype(context)
  56.  
  57.         if not selected_archetype.asset:
  58.             self.message("You must select an asset.")
  59.             return False
  60.    
  61.     def set_portal_corners_to_selected_verts(self, context, portal: PortalProperties, offset: tuple[float, float, float]):
  62.         """Set portal corners to selected verts in winding order."""
  63.         selected_verts = self.get_selected_portal_verts(context)
  64.  
  65.         if len(selected_verts) != 4:
  66.             self.message("You must select exactly 4 vertices.")
  67.             return False
  68.        
  69.         if not PortalCreatorHelper.is_coplanar(selected_verts):
  70.             self.warning(
  71.                 "Selection of points are not coplanar. This may cause issues with the portal.")
  72.  
  73.         screen_coords = PortalCreatorHelper.get_screen_coords(selected_verts)
  74.         screen_coords = PortalCreatorHelper.sort_2d_coords_winding(screen_coords)
  75.  
  76.         portal.corner1 = screen_coords[2] - offset
  77.         portal.corner2 = screen_coords[1] - offset
  78.         portal.corner3 = screen_coords[0] - offset
  79.         portal.corner4 = screen_coords[3] - offset
  80.  
  81.         return True
  82.  
  83. class SOLLUMZ_OT_create_portal_from_selection(PortalCreatorHelper, SOLLUMZ_OT_base, bpy.types.Operator):
  84.     """Create a portal from selected verts"""
  85.     bl_idname = "sollumz.createportalfromselection"
  86.     bl_label = "Create Portal From Verts"
  87.  
  88.     def run(self, context):
  89.         if not self.selected_archetype_has_asset():
  90.             return False
  91.  
  92.         selected_archetype = get_selected_archetype(context)
  93.  
  94.         portal_offset = selected_archetype.asset.location
  95.         new_portal = selected_archetype.new_portal()
  96.  
  97.         return self.set_portal_corners_to_selected_verts(context, new_portal, portal_offset)
  98.  
  99. class SOLLUMZ_OT_update_portal_from_selection(PortalCreatorHelper, SOLLUMZ_OT_base, bpy.types.Operator):
  100.     """Update a portal from selected verts"""
  101.     bl_idname = "sollumz.updateportalfromselection"
  102.     bl_label = "Update Portal From Verts"
  103.  
  104.     def run(self, context):
  105.         if not self.selected_archetype_has_asset():
  106.             return False
  107.  
  108.         selected_archetype = get_selected_archetype(context)
  109.         selected_portal = get_selected_portal(context)
  110.  
  111.         portal_offset = selected_archetype.asset.location
  112.  
  113.         return self.set_portal_corners_to_selected_verts(context, selected_portal, portal_offset)
Advertisement
Add Comment
Please, Sign In to add comment