Hello
you can try a variant using Parallel LINQ (System.Linq can be use in IronPython)
I had to relaunch Revit 2021 during the tests
# ACPV Python v.1.0
# Coded by:
### IMPORTS ###
# Clr and Sys
import clr
import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
# Import Protogeometry
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import Dynamo Core Nodes
clr.AddReference('DSCoreNodes')
import DSCore
# Import Time
import time
# Import System
import System
from System import Array
from System.Collections.Generic import *
# Import Parallel
from System.Threading.Tasks import *
clr.AddReference("System.Core")
import System
clr.ImportExtensions(System.Linq)
### DEFINITIONS ###
zVect = Vector.ByCoordinates(0,0,1)
def Flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(Flatten(el))
else:
result.append(el)
return result
def CrossProduct(vectA, vectB):
a=[vectA.X , vectA.Y , vectA.Z]
b=[vectB.X , vectB.Y , vectB.Z]
c = [a[1]*b[2] - a[2]*b[1],
a[2]*b[0] - a[0]*b[2],
a[0]*b[1] - a[1]*b[0]]
return Vector.ByCoordinates(c[0],c[1],c[2])
def SkyAccessAnalysis(point, surface, solids, angleRange= 180, angleStep= 2, maxDist= 300000):
# Make vectors by surface and point
n = surface.NormalAtPoint(point)
u = CrossProduct(n, Vector.ByCoordinates(0,0,1))
v = CrossProduct(n, u)
# Project normal to horizontal plane
nHor = Vector.ByCoordinates(n.X, n.Y, 0)
nHor= nHor.Scale(1/nHor.Length)
# Angle between surface and horizon
vertAngle = int(nHor.AngleWithVector(n) + 90)
# Make angle ranges to check
horRange = range(-angleRange/2, angleRange/2, step = angleStep)
vertRange = range(0, vertAngle, step = angleStep)
# Move slightly the point to avoid clash with itself
point = point.Translate(direction = nHor, distance = 10)
# Calculate max sky access score
skyValue = len(horRange) * len(vertRange)
# Make horizontal slice surface for following tests
bRevolveLine = Line.ByStartPointDirectionLength(point, nHor.Rotate(zVect, -angleRange/2), maxDist)
bSurfTest = Surface.ByRevolve(bRevolveLine, point, zVect, 0, angleRange)
# Make a sphere wedge and check if it does intersect surrounding buildings.
# If the solid passes the test, the analysis is concluded with maximum score.
solidTest = Solid.ByRevolve(PolyCurve.ByJoinedCurves(bSurfTest.PerimeterCurves()), point, u, 0, vertAngle)
if not Geometry.DoesIntersect(solidTest, solids):
solidTest.Dispose()
bSurfTest.Dispose()
bRevolveLine.Dispose()
return skyValue
else:
# make vertical slice for following tests
aRevolveLine = Line.ByStartPointDirectionLength(point, nHor, maxDist)
aSurfTest = Surface.ByRevolve(aRevolveLine, point, u, 0, vertAngle)
# Alpha angles test. If the slice passes the test, remove the angle from following analysis.
for alpha in horRange:
current_aSurfTest = aSurfTest.Rotate(origin = point, axis = zVect, degrees = alpha)
if not Geometry.DoesIntersect(current_aSurfTest, solids):
horRange.Remove(alpha)
current_aSurfTest.Dispose()
# Beta angles test. If the slice passes the test, remove the angle from following analysis.
for beta in vertRange:
current_bSurfTest = bSurfTest.Rotate(origin = point, axis = u, degrees = beta)
if not Geometry.DoesIntersect(current_bSurfTest, solids):
vertRange.Remove(beta)
current_bSurfTest.Dispose()
# Final test: check clashes between rays and surrounding builidings.
# Every clash subtracts one point to the final score.
for alpha in horRange:
aVector = nHor.Rotate(axis = u, degrees =alpha)
for beta in vertRange:
bVector = aVector.Rotate(axis = u, degrees =beta)
currentRay = Line.ByStartPointDirectionLength(point, bVector, maxDist)
if currentRay.DoesIntersect(solids):
skyValue -= 1
currentRay.Dispose()
solidTest.Dispose()
aRevolveLine.Dispose()
aSurfTest.Dispose()
bSurfTest.Dispose()
bRevolveLine.Dispose()
return skyValue
### INPUTS ###
parallel = IN[0]
multiproc = IN[1]
points = [Flatten(lst) for lst in IN[2]]
surfaces = IN[3]
aStep = IN[4]
aRange = IN[5]
buildings =Solid.ByUnion(IN[6])
### CODE ###
# Start Run-time
start = time.time()
values = []
if parallel:
values =[]
for surf,pts in zip(surfaces,points):
threadResult = pts.AsParallel().Select(lambda pt: SkyAccessAnalysis(pt, surface = surf, solids = buildings, angleRange = aRange, angleStep = aStep)).ToList()
values.append(threadResult)
else:
for surf,pts in zip(surfaces,points):
values.append([SkyAccessAnalysis(pt, surf, buildings, angleRange = aRange, angleStep = aStep) for pt in pts])
# Calculate Run-time
time = ("%s s" % (time.time()-start))
### OUTPUT ###
OUT = values, time