Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # -*- coding: utf-8 -*-
- """
- Rhino 8 Python Script: Optimized Shadow Vectorizer with Enhanced Solid Generation
- Now uses Rhino's built-in sun for easier sun direction control
- Handles complex geometry and ensures shadow solids are created for all shadow types
- """
- import rhinoscriptsyntax as rs
- import Rhino
- import scriptcontext as sc
- import Rhino.Geometry as rg
- import math
- import time
- def OptimizedShadowVectorizer():
- """
- Main function with performance optimizations and enhanced solid generation
- """
- # Get user input
- caster_ids = rs.GetObjects("Select objects to cast shadows",
- rs.filter.surface | rs.filter.polysurface | rs.filter.mesh,
- preselect=True)
- if not caster_ids:
- print("No shadow casting objects selected.")
- return
- receiver_ids = rs.GetObjects("Select surfaces to receive shadows",
- rs.filter.surface | rs.filter.polysurface | rs.filter.mesh,
- preselect=True)
- if not receiver_ids:
- print("No receiving surfaces selected.")
- return
- sun_vector = GetSunVector()
- if not sun_vector:
- return
- # Add quality option for complex geometry
- quality = rs.GetString("Mesh quality (Draft for complex objects)", "Standard",
- ["Draft", "Standard", "High"])
- # Add corner preservation option
- preserve_corners = rs.GetString("Preserve sharp corners?", "Yes", ["Yes", "No"])
- self_shadow = rs.GetString("Include self-shadowing? (May be slow for complex objects)",
- "No", ["Yes", "No"])
- # Add option for solid generation
- create_solids = rs.GetString("Create shadow solids?", "Yes", ["Yes", "No"])
- # Performance monitoring
- start_time = time.time()
- rs.EnableRedraw(False)
- try:
- print("\nPreparing geometry with {} quality...".format(quality))
- # Convert objects to meshes with adaptive quality
- caster_data = []
- for i, cid in enumerate(caster_ids):
- print(" Converting object {}/{}...".format(i+1, len(caster_ids)))
- mesh = ConvertToMeshOptimized(cid, quality)
- if mesh:
- # Estimate complexity and warn user
- complexity = mesh.Faces.Count * mesh.TopologyEdges.Count
- if complexity > 1000000:
- print(" WARNING: Object has {} faces - consider using Draft quality".format(
- mesh.Faces.Count))
- caster_data.append((cid, mesh))
- # Allow escape for very complex objects
- if time.time() - start_time > 5:
- rs.EnableRedraw(True)
- if not rs.GetString("Processing is taking long. Continue?", "Yes", ["Yes", "No"]) == "Yes":
- return
- rs.EnableRedraw(False)
- if not caster_data:
- print("Error: Could not convert any casting objects to meshes.")
- return
- # Prepare receivers
- receiver_breps = [rs.coercebrep(rid) for rid in receiver_ids if rs.coercebrep(rid)]
- if not receiver_breps:
- print("Error: No valid receiver surfaces found.")
- return
- # Process shadows with progress tracking
- all_shadow_curves = []
- external_shadow_groups = [] # Track external shadows separately for solids
- inter_shadow_groups = [] # Track inter-object shadows separately
- self_shadow_groups = [] # Track self shadows separately
- total_objects = len(caster_data)
- for i, (caster_id, caster_mesh) in enumerate(caster_data):
- print("\nProcessing Object {} of {}".format(i + 1, total_objects))
- # Update viewport periodically for feedback
- if i % 2 == 0:
- rs.Redraw()
- rs.Prompt("Processing shadows: {}/{}".format(i+1, total_objects))
- # Generate external shadows (always do this - it's usually fast)
- if receiver_breps:
- print(" Generating external shadows...")
- external_shadows = GenerateOptimizedShadows(caster_mesh, receiver_breps,
- sun_vector, quality, preserve_corners)
- if external_shadows:
- all_shadow_curves.extend(external_shadows)
- external_shadow_groups.append(external_shadows)
- print(" -> Found {} curves".format(len(external_shadows)))
- # Inter-object shadows (skip for single objects)
- if len(caster_data) > 1:
- print(" Generating inter-object shadows...")
- other_receivers = []
- for j, (other_id, other_mesh) in enumerate(caster_data):
- if i != j:
- other_brep = rg.Brep.CreateFromMesh(other_mesh, True)
- if other_brep:
- other_receivers.append(other_brep)
- if other_receivers:
- inter_shadows = GenerateOptimizedShadows(caster_mesh, other_receivers,
- sun_vector, quality, preserve_corners)
- if inter_shadows:
- all_shadow_curves.extend(inter_shadows)
- inter_shadow_groups.append(inter_shadows)
- print(" -> Found {} curves".format(len(inter_shadows)))
- # Self-shadows only if requested (expensive for complex geometry)
- if self_shadow == "Yes":
- print(" Analyzing self-shadows (this may take time)...")
- # Use simplified method for complex meshes
- if caster_mesh.Faces.Count > 5000:
- print(" Using simplified method for complex geometry...")
- self_shadows = GenerateSimplifiedSelfShadows(caster_id, caster_mesh, sun_vector)
- else:
- self_shadows = GenerateOptimizedSelfShadows(caster_id, caster_mesh, sun_vector)
- if self_shadows:
- all_shadow_curves.extend(self_shadows)
- self_shadow_groups.append(self_shadows)
- print(" -> Found {} self-shadow curves".format(len(self_shadows)))
- # Final processing
- if all_shadow_curves:
- print("\nFinalizing {} shadow curves...".format(len(all_shadow_curves)))
- # Process curves based on quantity
- if len(all_shadow_curves) > 100:
- print(" Large dataset detected - using fast processing...")
- final_curves = FastProcessShadowCurves(all_shadow_curves)
- else:
- final_curves = ProcessShadowCurvesOptimized(all_shadow_curves)
- OrganizeOutput(final_curves, "Shadow_Outlines", (64, 64, 64))
- # Create shadow solids if requested
- if create_solids == "Yes":
- print("\nCreating shadow solids...")
- all_shadow_surfaces = []
- # Create surfaces from main shadow curves
- if len(final_curves) < 200: # Increased threshold for solid creation
- shadow_surfaces = CreateEnhancedShadowSurfaces(final_curves)
- if shadow_surfaces:
- all_shadow_surfaces.extend(shadow_surfaces)
- print(" Created {} main shadow surfaces".format(len(shadow_surfaces)))
- else:
- # Process in batches for large curve sets
- batch_size = 50
- for batch_start in range(0, len(final_curves), batch_size):
- batch_end = min(batch_start + batch_size, len(final_curves))
- batch_curves = final_curves[batch_start:batch_end]
- batch_surfaces = CreateEnhancedShadowSurfaces(batch_curves)
- if batch_surfaces:
- all_shadow_surfaces.extend(batch_surfaces)
- print(" Created {} shadow surfaces in batches".format(len(all_shadow_surfaces)))
- # Try to create surfaces from individual shadow groups if main process didn't yield results
- if not all_shadow_surfaces:
- print(" Attempting to create solids from shadow groups...")
- # Process external shadows
- for shadow_group in external_shadow_groups:
- surfaces = TryCreateSurfacesFromGroup(shadow_group)
- if surfaces:
- all_shadow_surfaces.extend(surfaces)
- # Process inter-object shadows
- for shadow_group in inter_shadow_groups:
- surfaces = TryCreateSurfacesFromGroup(shadow_group)
- if surfaces:
- all_shadow_surfaces.extend(surfaces)
- # Process self shadows
- for shadow_group in self_shadow_groups:
- surfaces = TryCreateSurfacesFromGroup(shadow_group)
- if surfaces:
- all_shadow_surfaces.extend(surfaces)
- if all_shadow_surfaces:
- OrganizeOutput(all_shadow_surfaces, "Shadow_Solids", (128, 128, 128))
- print("Total shadow surfaces created: {}".format(len(all_shadow_surfaces)))
- else:
- print("No closed curves found for creating shadow solids.")
- elapsed = time.time() - start_time
- print("\nCOMPLETE in {:.1f} seconds: {} final curves created".format(
- elapsed, len(final_curves)))
- else:
- print("\nNo shadows were created.")
- except Exception as e:
- print("Error: {}".format(e))
- import traceback
- traceback.print_exc()
- finally:
- rs.EnableRedraw(True)
- rs.Prompt("")
- def ConvertToMeshOptimized(obj_id, quality="Standard"):
- """
- Converts objects to mesh with adaptive quality settings
- Quality levels are calibrated for performance vs accuracy
- """
- if rs.IsMesh(obj_id):
- mesh = rs.coercemesh(obj_id)
- else:
- brep = rs.coercebrep(obj_id)
- if not brep:
- return None
- # Get object bounding box to scale parameters appropriately
- bbox = brep.GetBoundingBox(True)
- obj_size = bbox.Diagonal.Length
- params = rg.MeshingParameters()
- if quality == "Draft":
- # Fast settings for complex objects
- params.Tolerance = sc.doc.ModelAbsoluteTolerance * 5
- params.MaximumEdgeLength = obj_size * 0.1 # Adaptive to object size
- params.MinimumEdgeLength = obj_size * 0.01
- params.GridAspectRatio = 0
- params.RefineGrid = False
- params.SimplePlanes = True
- params.GridAngle = math.radians(30) # Coarser angle
- elif quality == "High":
- # High quality for final output
- params.Tolerance = sc.doc.ModelAbsoluteTolerance * 0.5
- params.MaximumEdgeLength = obj_size * 0.02
- params.MinimumEdgeLength = sc.doc.ModelAbsoluteTolerance
- params.GridAspectRatio = 0
- params.RefineGrid = True
- params.SimplePlanes = False
- params.GridAngle = math.radians(15)
- else: # Standard
- # Balanced settings
- params.Tolerance = sc.doc.ModelAbsoluteTolerance
- params.MaximumEdgeLength = obj_size * 0.05
- params.MinimumEdgeLength = obj_size * 0.005
- params.GridAspectRatio = 0
- params.RefineGrid = True
- params.SimplePlanes = False
- params.GridAngle = math.radians(20)
- meshes = rg.Mesh.CreateFromBrep(brep, params)
- if not meshes:
- return None
- mesh = rg.Mesh()
- for m in meshes:
- if m:
- mesh.Append(m)
- # Optimize mesh
- mesh.Compact()
- mesh.Weld(math.radians(22.5))
- mesh.Normals.ComputeNormals()
- mesh.FaceNormals.ComputeFaceNormals()
- mesh.UnifyNormals()
- # Reduce if still too complex
- if quality == "Draft" and mesh.Faces.Count > 10000:
- mesh.Reduce(10000, False, 10, False)
- print(" Reduced mesh to {} faces for performance".format(mesh.Faces.Count))
- return mesh
- def GenerateOptimizedShadows(mesh, receiver_breps, sun_vector, quality, preserve_corners="Yes"):
- """
- Generates shadows with quality-based optimization and optional corner preservation
- """
- if not receiver_breps:
- return []
- projected_ids = []
- # Get mesh silhouette
- view_point = rg.Point3d.Origin - (sun_vector * 10000)
- view_plane = rg.Plane(view_point, sun_vector)
- outline_polylines = mesh.GetOutlines(view_plane)
- if not outline_polylines:
- return []
- # Prepare curves for projection - with corner preservation option
- curves_to_project = []
- for polyline in outline_polylines:
- if polyline and polyline.Count > 2:
- # Convert to polyline curve to preserve sharp corners
- temp_curve = rg.Polyline(list(polyline)).ToNurbsCurve()
- if temp_curve:
- # Decision based on user preference and quality setting
- if preserve_corners == "No":
- # Original behavior - rebuild curves for smoothness
- if quality == "Draft":
- rebuild_pts = min(20, polyline.Count // 3)
- elif quality == "High":
- rebuild_pts = max(50, polyline.Count // 2)
- else:
- rebuild_pts = max(30, polyline.Count // 3)
- rebuilt_curve = temp_curve.Rebuild(rebuild_pts, 3, True)
- if rebuilt_curve:
- curves_to_project.append(rebuilt_curve)
- else:
- curves_to_project.append(temp_curve)
- else:
- # Preserve corners - only simplify if extremely complex
- if quality == "Draft" and polyline.Count > 100:
- # Very light simplification for performance
- rebuild_pts = max(50, polyline.Count // 2)
- rebuilt_curve = temp_curve.Rebuild(rebuild_pts, 3, True)
- if rebuilt_curve:
- curves_to_project.append(rebuilt_curve)
- else:
- curves_to_project.append(temp_curve)
- else:
- # Keep original curve to preserve all corners
- curves_to_project.append(temp_curve)
- if not curves_to_project:
- return []
- # Project in batches for better memory management
- batch_size = 50
- for i in range(0, len(curves_to_project), batch_size):
- batch = curves_to_project[i:i+batch_size]
- try:
- projected = rg.Curve.ProjectToBrep(
- batch, receiver_breps, sun_vector,
- sc.doc.ModelAbsoluteTolerance * (5 if quality == "Draft" else 1)
- )
- if projected:
- for proj_curve in projected:
- if (proj_curve and proj_curve.IsValid and
- proj_curve.GetLength() > sc.doc.ModelAbsoluteTolerance * 10):
- curve_id = sc.doc.Objects.AddCurve(proj_curve)
- if curve_id:
- projected_ids.append(curve_id)
- except Exception as e:
- print(" Warning: Batch projection failed: {}".format(e))
- continue
- return projected_ids
- def GenerateSimplifiedSelfShadows(obj_id, mesh, sun_vector):
- """
- Simplified self-shadow method for complex geometry
- Uses sampling instead of checking every edge
- """
- shadow_curves = []
- # Create brep for projection target
- mesh_brep = rg.Brep.CreateFromMesh(mesh, True) if rs.IsMesh(obj_id) else rs.coercebrep(obj_id)
- if not mesh_brep:
- return []
- # Sample edges instead of checking all
- edge_count = mesh.TopologyEdges.Count
- sample_rate = max(1, edge_count // 500) # Check at most 500 edges
- curves_to_project = []
- for edge_idx in range(0, edge_count, sample_rate):
- try:
- face_indices = mesh.TopologyEdges.GetConnectedFaces(edge_idx)
- if len(face_indices) == 2:
- f1_normal = rg.Vector3d(mesh.FaceNormals[face_indices[0]])
- f2_normal = rg.Vector3d(mesh.FaceNormals[face_indices[1]])
- dot1 = f1_normal * sun_vector
- dot2 = f2_normal * sun_vector
- # Check if this is a terminator edge
- if (dot1 > 0.1 and dot2 <= -0.1) or (dot1 <= -0.1 and dot2 > 0.1):
- edge_curve = mesh.TopologyEdges.EdgeLine(edge_idx).ToNurbsCurve()
- if edge_curve:
- curves_to_project.append(edge_curve)
- # Limit number of curves to project
- if len(curves_to_project) >= 100:
- break
- except Exception:
- continue
- if not curves_to_project:
- return []
- # Project and filter
- try:
- projected = rg.Curve.ProjectToBrep(
- curves_to_project, [mesh_brep], sun_vector,
- sc.doc.ModelAbsoluteTolerance * 2
- )
- if projected:
- for proj_curve in projected:
- if proj_curve and proj_curve.IsValid:
- # Quick distance check
- if proj_curve.GetLength() > sc.doc.ModelAbsoluteTolerance * 20:
- curve_id = sc.doc.Objects.AddCurve(proj_curve)
- if curve_id:
- shadow_curves.append(curve_id)
- except Exception as e:
- print(" Self-shadow projection error: {}".format(e))
- return shadow_curves
- def GenerateOptimizedSelfShadows(obj_id, mesh, sun_vector):
- """
- Standard self-shadow generation with performance improvements
- """
- shadow_curves = []
- mesh_brep = rg.Brep.CreateFromMesh(mesh, True) if rs.IsMesh(obj_id) else rs.coercebrep(obj_id)
- if not mesh_brep:
- return []
- curves_to_project = []
- if mesh.FaceNormals.Count == 0:
- mesh.FaceNormals.ComputeFaceNormals()
- # Pre-compute face visibility to sun
- face_visibility = []
- for i in range(mesh.FaceNormals.Count):
- dot = rg.Vector3d(mesh.FaceNormals[i]) * sun_vector
- face_visibility.append(dot > 0)
- # Only check edges between visible and non-visible faces
- for edge_idx in range(mesh.TopologyEdges.Count):
- try:
- face_indices = mesh.TopologyEdges.GetConnectedFaces(edge_idx)
- if len(face_indices) == 2:
- if face_visibility[face_indices[0]] != face_visibility[face_indices[1]]:
- edge_curve = mesh.TopologyEdges.EdgeLine(edge_idx).ToNurbsCurve()
- if edge_curve:
- curves_to_project.append(edge_curve)
- except Exception:
- continue
- if not curves_to_project:
- return []
- # Project in smaller batches
- batch_size = 20
- for i in range(0, len(curves_to_project), batch_size):
- batch = curves_to_project[i:i+batch_size]
- try:
- projected = rg.Curve.ProjectToBrep(
- batch, [mesh_brep], sun_vector, sc.doc.ModelAbsoluteTolerance
- )
- if projected:
- for proj_curve in projected:
- if not (proj_curve and proj_curve.IsValid):
- continue
- # Find corresponding original curve
- proj_mid = proj_curve.PointAt(proj_curve.Domain.Mid)
- min_dist = float('inf')
- original_curve = None
- for crv in batch:
- dist = proj_mid.DistanceTo(crv.PointAt(crv.Domain.Mid))
- if dist < min_dist:
- min_dist = dist
- original_curve = crv
- if original_curve:
- dist = proj_curve.PointAtStart.DistanceTo(original_curve.PointAtStart)
- if dist > sc.doc.ModelAbsoluteTolerance * 5:
- curve_id = sc.doc.Objects.AddCurve(proj_curve)
- if curve_id:
- shadow_curves.append(curve_id)
- except Exception:
- continue
- return shadow_curves
- def FastProcessShadowCurves(curve_ids):
- """
- Fast processing for large numbers of curves
- """
- if not curve_ids:
- return []
- # Simple join without extensive cleanup
- tolerance = sc.doc.ModelAbsoluteTolerance * 10
- joined = rs.JoinCurves(curve_ids, delete_input=True, tolerance=tolerance)
- if not joined:
- return curve_ids
- # Quick filter by length
- min_length = sc.doc.ModelAbsoluteTolerance * 50
- valid_curves = []
- for cid in joined:
- if rs.IsCurve(cid) and rs.CurveLength(cid) > min_length:
- valid_curves.append(cid)
- else:
- rs.DeleteObject(cid)
- return valid_curves
- def ProcessShadowCurvesOptimized(curve_ids):
- """
- Standard processing with optimization
- """
- if not curve_ids:
- return []
- # Remove duplicates first
- unique_curves = FilterQuickDuplicates(curve_ids)
- # Join curves
- joined = rs.JoinCurves(unique_curves, delete_input=True,
- tolerance=sc.doc.ModelAbsoluteTolerance*5)
- valid_curves = joined if joined else unique_curves
- # Filter by length
- min_length = sc.doc.ModelAbsoluteTolerance * 20
- final_curves = []
- for cid in valid_curves:
- if rs.IsCurve(cid) and rs.CurveLength(cid) > min_length:
- final_curves.append(cid)
- else:
- rs.DeleteObject(cid)
- return final_curves
- def FilterQuickDuplicates(curve_ids):
- """
- Quick duplicate removal using spatial hashing
- """
- if len(curve_ids) < 2:
- return curve_ids
- tolerance = sc.doc.ModelAbsoluteTolerance * 5
- unique = []
- midpoints_seen = set()
- for cid in curve_ids:
- curve = rs.coercecurve(cid)
- if curve:
- mid = curve.PointAtNormalizedLength(0.5)
- # Create spatial hash
- hash_key = (
- round(mid.X / tolerance),
- round(mid.Y / tolerance),
- round(mid.Z / tolerance),
- round(curve.GetLength() / tolerance)
- )
- if hash_key not in midpoints_seen:
- midpoints_seen.add(hash_key)
- unique.append(cid)
- else:
- rs.DeleteObject(cid)
- return unique
- def CreateEnhancedShadowSurfaces(curve_ids):
- """
- Enhanced version that creates planar surfaces from closed shadow curves
- with better handling of complex cases
- """
- if not curve_ids:
- return []
- surfaces = []
- # Separate closed and open curves
- closed_curves = []
- open_curves = []
- for cid in curve_ids:
- if rs.IsCurveClosed(cid):
- if rs.IsCurvePlanar(cid):
- closed_curves.append(cid)
- else:
- open_curves.append(cid)
- # Try to close open curves if they're nearly closed
- for open_curve_id in open_curves:
- curve = rs.coercecurve(open_curve_id)
- if curve:
- gap = curve.PointAtStart.DistanceTo(curve.PointAtEnd)
- if gap < sc.doc.ModelAbsoluteTolerance * 50:
- # Try to close the curve
- line = rg.Line(curve.PointAtEnd, curve.PointAtStart)
- closing_segment = line.ToNurbsCurve()
- joined = rg.Curve.JoinCurves([curve, closing_segment],
- sc.doc.ModelAbsoluteTolerance * 10)
- if joined and len(joined) > 0:
- closed_id = sc.doc.Objects.AddCurve(joined[0])
- if closed_id and rs.IsCurveClosed(closed_id):
- closed_curves.append(closed_id)
- if not closed_curves:
- return []
- # Try different methods to create surfaces
- # Method 1: Boolean union and then create surfaces
- try:
- booleaned = rs.CurveBooleanUnion(closed_curves)
- if booleaned:
- for curve_id in booleaned:
- if rs.IsCurveClosed(curve_id) and rs.IsCurvePlanar(curve_id):
- srf = rs.AddPlanarSrf(curve_id)
- if srf:
- if isinstance(srf, list):
- surfaces.extend(srf)
- else:
- surfaces.append(srf)
- except Exception as e:
- print(" Boolean union method failed: {}".format(e))
- # Method 2: If method 1 didn't work, try direct surface creation
- if not surfaces:
- for curve_id in closed_curves:
- try:
- if rs.IsCurveClosed(curve_id) and rs.IsCurvePlanar(curve_id):
- srf = rs.AddPlanarSrf(curve_id)
- if srf:
- if isinstance(srf, list):
- surfaces.extend(srf)
- else:
- surfaces.append(srf)
- except Exception:
- continue
- return surfaces
- def TryCreateSurfacesFromGroup(curve_ids):
- """
- Attempts to create surfaces from a group of shadow curves
- """
- if not curve_ids:
- return []
- surfaces = []
- # First try to join curves in the group
- joined = rs.JoinCurves(curve_ids, delete_input=False,
- tolerance=sc.doc.ModelAbsoluteTolerance * 10)
- if joined:
- for curve_id in joined:
- if rs.IsCurveClosed(curve_id) and rs.IsCurvePlanar(curve_id):
- try:
- srf = rs.AddPlanarSrf(curve_id)
- if srf:
- if isinstance(srf, list):
- surfaces.extend(srf)
- else:
- surfaces.append(srf)
- except Exception:
- pass
- return surfaces
- def GetSunVector():
- """
- Gets sun direction vector from Rhino's built-in sun settings
- Falls back to manual input if sun is not enabled
- """
- # Try to get Rhino's sun direction
- sun = sc.doc.Lights.Sun
- if sun.Enabled:
- # Get the sun vector (direction light travels)
- sun_vector = sun.Vector
- print("Using Rhino sun settings:")
- print(" Azimuth: {:.1f}°".format(sun.Azimuth))
- print(" Altitude: {:.1f}°".format(sun.Altitude))
- # Verify it's a valid vector
- if sun_vector and sun_vector.Length > 0:
- sun_vector.Unitize()
- return sun_vector
- else:
- print("Warning: Sun vector is invalid, using fallback method")
- else:
- print("Rhino sun is not enabled. Please enable it in the Sun panel,")
- print("or choose a manual method.")
- # Fallback to manual input
- choice = rs.GetString("Sun direction method", "Default",
- ["Manual", "Default", "Vertical", "Angle", "EnableSun"])
- if choice == "EnableSun":
- print("Please enable the sun in Rhino's Sun panel (Panels > Sun)")
- print("Then run this script again.")
- return None
- vec = None
- if choice == "Manual":
- pt1 = rs.GetPoint("Click sun position (origin of ray)")
- if not pt1:
- return None
- pt2 = rs.GetPoint("Click target point (defines direction)", base_point=pt1)
- if not pt2:
- return None
- vec = pt2 - pt1
- elif choice == "Vertical":
- vec = rg.Vector3d(0, 0, -1)
- elif choice == "Angle":
- alt = rs.GetReal("Sun altitude (0-90 degrees)", 45, 0, 90)
- azi = rs.GetReal("Sun azimuth (0-360, 0=N)", 135, 0, 360)
- if alt is None or azi is None:
- return None
- alt_rad = math.radians(90 - alt)
- azi_rad = math.radians(azi)
- x = math.sin(alt_rad) * math.sin(azi_rad)
- y = math.sin(alt_rad) * math.cos(azi_rad)
- z = -math.cos(alt_rad)
- vec = rg.Vector3d(x, y, z)
- else: # Default
- vec = rg.Vector3d(1, 1, -1)
- if vec:
- vec.Unitize()
- return vec
- def OrganizeOutput(object_ids, layer_name, layer_color):
- """
- Organizes objects onto designated layer
- """
- if not object_ids:
- return
- if not rs.IsLayer(layer_name):
- rs.AddLayer(layer_name, layer_color)
- rs.ObjectLayer(object_ids, layer_name)
- # Main execution
- if __name__ == "__main__":
- print("\n" + "="*50)
- print(" OPTIMIZED SHADOW VECTORIZER WITH RHINO SUN")
- print(" Uses Rhino's built-in sun for easy control")
- print("="*50)
- OptimizedShadowVectorizer()
Advertisement
Add Comment
Please, Sign In to add comment