#Script written by Luis Quinones
#Seeker Smart Search Algorithm
#Script Copywritten by complicitMatter.com
#www.complicitMatter.com
#www.computationalMatter.com
import rhinoscriptsyntax as rs
import math
import random
from System.Drawing import Color
import sys
import random
import scriptcontext
class myLOCATOR:
def __init__(self,txtcoord,ptCoords,pts,init,coord,colorThresh,colorSet):
self.txtPt = txtcoord
self.ptIDS = pts
self.ptCOORDS = ptCoords
self.current = init
self.pos = coord
self.cTHRESH = colorThresh
self.dTHRESH = 12
self.colors = colorSet
self.CASEA = False
self.CASEB = False
self.CASEC = False
self.CASED = False
self.tempList = []
self.tempColorList = []
self.creationHistory = []
self.waveTwoThreshCOUNT = 6
self.searchPASSES = []
def search(self):
#ALL THE ACTION
cCHECKDARK = [x for x in self.tempColorList if x < self.cTHRESH] #CHECK THE LIST FOR VALUES THAT ARE SMALLER THAN COLOR THRESHOLD
if len(cCHECKDARK) > 0 and len(cCHECKDARK) != len(self.tempColorList) and all(k > self.cTHRESH for k in self.tempColorList) and closestColor > self.cTHRESH:
print "AT LEAST ONE DARK ONE"
self.CASEA = True #MEANS THERE IS AT LEAST ONE DARK ONE IN THE MIX
if len(cCHECKDARK) == len(self.tempColorList):
print "ALL DARK ONES"
self.CASEB = True #MEANS THEY ARE ALL DARK
txtE = rs.AddText("CASE-B",[self.txtPt[0],self.txtPt[1],self.txtPt[2]-6],0.5)
cCHECKLIGHT = [m for m in self.tempColorList if m >= self.cTHRESH]
if len(cCHECKLIGHT) > 0 and len(cCHECKLIGHT) != len(self.tempColorList) and len(cCHECKDARK) > 0 :
print "AT LEAST ONE LIGHT ONE IN MIX OF DARK"
self.CASEC = True #THERES AT LEAST ONE BRIGHT VALUE IN THE MIX OF DARK ONES
txtE = rs.AddText("CASE-C",[self.txtPt[0],self.txtPt[1],self.txtPt[2]-6],0.5)
elif len(cCHECKLIGHT) == len(self.tempColorList):
print "ALL LIGHT ONES"
print "LIGHTPTS = " + str(len(cCHECKLIGHT))
print "DARK PTS = " + str(len(cCHECKDARK))
self.CASED = True #THEYRE ALL BRIGHT
txtE = rs.AddText("CASE-D",[self.txtPt[0],self.txtPt[1],self.txtPt[2]-6],0.5)
return [cCHECKDARK,cCHECKLIGHT]
def closestFriends(self,nearPOINTS,nearDIST,nearPOINTCOLOR,currentWAVEONEPT,count):
closestDUDES = []
closestDUDESDIST = []
closestDUDESCOLOR = []
sortList = nearDIST[:] #make a duplicate list
sortList.sort() #sort the distances to get the first 3 which are closest
sum = 0
for i in range(0,self.waveTwoThreshCOUNT): #loop through how many neighborgs you want
nearIndex = nearDIST.index(sortList[i]) #get index
#print nearIndex
closestDUDES.append(nearPOINTS[nearIndex]) #store the closest 3 points and dist and color
closestDUDESCOLOR.append(nearPOINTCOLOR[nearIndex])
closestDUDESDIST.append(nearDIST[nearIndex])
sum = sum + nearPOINTCOLOR[nearIndex]
average = closestDUDESCOLOR
waveTWOCOLORAVE = sum/self.waveTwoThreshCOUNT
for j in range(len(closestDUDES)):
circ2 = rs.AddCircle(closestDUDES[j],2)
rs.ObjectLayer(circ2,"wave2")
self.creationHistory.append(circ2)
closestNeighborghIND = rs.PointArrayClosestPoint(closestDUDES,currentWAVEONEPT)
closestDude = closestDUDES[closestNeighborghIND]
circ = rs.AddCircle(closestDude,0.5)
rs.ObjectLayer(circ,"clos")
self.creationHistory.append(circ)
dot = rs.AddTextDot(count,closestDude)
rs.ObjectLayer(circ,"CLOSE")
self.creationHistory.append(dot)
del sortList[:]
return [closestDUDES,waveTWOCOLORAVE,closestDude]
def decisionMaker(self):
rs.EnableRedraw(False)
#if theyre all white
#get closest points within another threshold - 5 UNITS
nearPOINTS = [] #LIST OF WAVE 2 POINTS
nearDIST = [] #LIST OF DISTANCE FROM WAVE 1 PTS TO WAVE 2 POINTS
nearPOINTCOLOR = [] #LIST OF WAVE 2 COLORS
tempOUTPTS = self.ptCOORDS
tempOUTCOL = self.colors
averageCOLORSET = [] #LIST OF CLOSEST WAVE 2 COLOR AVERAGE
closestNEIGHPOS = [] #LIST OF Closest WAVE 2 PTS TO EACH WAVE 1 PT
nextPosHolder = [] #HOLDS LIST OF WAVE 1 POSITIONS WAITING FOR WAVE 2 OUTPUT
closestSOLO = [] #CLOSEST WAVE 2 PT TO WAVE PT
stopper = []
#ONLY USE IF YOU WANT TO REMOVE ALL WAVE 1 POINTS FROM WAVE 2 - otherwise just remove current Wave 1 Point from Wave 2
#-----------------------------------------------------------------------------------------------------------------------
#for x in range(len(self.tempList)): #loop through the 1st wave points
#loc = self.ptCOORDS.index(self.tempList[x]) #get the index of 1st wave to remove from 2nd wave
#tempOUTPTS.remove(self.ptCOORDS[loc])
#tempOUTCOL.remove(self.colors[loc])
#-----------------------------------------------------------------------------------------------------------------------
for i in range(len(self.tempList)): #loop through everypoint against each point in wave 1
if scriptcontext.escape_test(False):
print "ESC pressed "
break
#RESET LISTS
dotStopper = stopper[:]
dotStopperHELP = nearDIST[:]
stopper = []
nearPOINTS = []
nearDIST = []
nearPOINTCOLOR = []
for j in range(len(tempOUTPTS)):
checkDist = rs.Distance(tempOUTPTS[j],self.tempList[i]) #check dist if dist within 2nd wave thresh and current isnt me and z is smaller and mine and if wave1 current does not match wave2 current then store it
#if tempOUTPTS[j] != self.tempList[i] and tempOUTPTS[j] != self.pos and tempOUTPTS[j][2] >= self.tempList[i][2] : #THIS DOES NOT ALLOW LOOKING BACK
if tempOUTPTS[j] != self.tempList[i] and tempOUTPTS[j] != self.pos: #THIS ALLOWS LOOKING BACK SEARCHING PREV HISTORY
if dotStopper == dotStopperHELP:
dot = rs.AddTextDot("WAVE 2 - " + str(tempOUTCOL[j]),tempOUTPTS[j])
rs.ObjectLayer(dot,"DOTS_DARK")
self.creationHistory.append(dot)
nearPOINTS.append(tempOUTPTS[j]) #store 2nd wave points
nearDIST.append(checkDist) #store 2nd wave dist
nearPOINTCOLOR.append(tempOUTCOL[j]) #store 2nd wave colors
stopper.append("0")
#print "THIS MANY OUTTER POINTS - " + str(len(nearPOINTS))
newCirc = rs.AddCircle(self.tempList[i],1)
rs.ObjectLayer(newCirc,"wave1")
self.creationHistory.append(newCirc)
output = self.closestFriends(nearPOINTS,nearDIST,nearPOINTCOLOR,self.tempList[i],i) #CALL CLOSEST FRIENDS FUNCTION
averageCOLORSET.append(output[1]) #STORE LIST OF RETURNED COLOR AVERAGES FROM WAVE 2
closestNEIGHPOS.append(output[0]) #STORE ARRAY OF RETURNED PT POS FROM WAVE 2
nextPosHolder.append(self.tempList[i]) #STORE WAVE 1 PTS TO FIND INDEX FOR NEXT POS
closestSOLO.append(output[2]) #STORE CLOSEST SINGLE POS FROM WAVE 2
#COUNTERS
#-----------------------------------------------------------------------------------------------------------------------
txtA = rs.AddText(str(len(output[0])),self.txtPt,0.5)
self.creationHistory.append(txtA)
txtB = rs.AddText(str(len(self.searchPASSES)+1),[self.txtPt[0],self.txtPt[1],self.txtPt[2]-1],0.5)
self.creationHistory.append(txtB)
txtC = rs.AddText(str(self.waveTwoThreshCOUNT),[self.txtPt[0],self.txtPt[1],self.txtPt[2]-2],0.5)
self.creationHistory.append(txtC)
txtE = rs.AddText(str(self.dTHRESH),[self.txtPt[0],self.txtPt[1],self.txtPt[2]-5],0.5)
self.creationHistory.append(txtE)
#-----------------------------------------------------------------------------------------------------------------------
rs.EnableRedraw(True)
for x in range(len(output[0])):
#sampletest = rs.AddTextDot(str(averageCOLORSET),closestNEIGHPOS[0][x])
#rs.TextDotHeight(sampletest,20)
refLine = rs.AddLine(output[0][x],self.tempList[i])
rs.ObjectLayer(refLine,"w1w2_Conn")
self.creationHistory.append(refLine)
refLinemid = rs.CurveMidPoint(refLine)
newDot2 = rs.AddTextDot(x,refLinemid)
rs.ObjectLayer(newDot2,"w1w2_Conn")
self.creationHistory.append(newDot2)
print "THAT COUNT MAAAAN = " + str(len(nextPosHolder))
txtD = rs.AddText(str(len(nearPOINTS)),[self.txtPt[0],self.txtPt[1],self.txtPt[2]-3],0.5)
rs.DeleteObject(txtD)
self.creationHistory.append(txtD)
copy = nearPOINTS
print "NextPHOLD = " + str(nextPosHolder)
print "P1 = " + str(nextPosHolder[1])
print "Average Color = " + str(averageCOLORSET)
low = min(averageCOLORSET) #GET THE MIN VALUE FROM THE NETWORK COLORS
high = max(averageCOLORSET) #GET THE MAX VALUE FROM THE NETWORK COLORS
print "Low Value = " + str(low)
lowIndex = averageCOLORSET.index(low) #GET THE POS ON LIST WHERE THE LOWEST VALUE IS
print "Index = " + str(lowIndex)
lowCount = averageCOLORSET.count(low)
if low == high: #IF LOW AND HIGH VALUE ARE THE SAME IE 255 ALL WHITE / EITHER CHOOSE RANDOMLY FROM WAVE 1 OR CHOOSE CLOSEST FROM WAVE 1
self.searchPASSES.append("0")
print "LOW = HIGH"
deleted = rs.DeleteObjects(self.creationHistory)
print "# ITEMS IN LIST = " + str(len(self.creationHistory))
print "# of DELETED Objects = " + str(deleted)
self.creationHistory = []
#nextPosInd = rs.PointArrayClosestPoint(self.tempList,self.pos)
nextPos = False
self.waveTwoThreshCOUNT = self.waveTwoThreshCOUNT + 1
#self.dTHRESH = self.dTHRESH+4
return nextPos
else:
self.waveTwoThreshCOUNT = 6
nextPos = nextPosHolder[lowIndex] #NEXT POSITION BASED ON THE WAVES RESULTS
txtD = rs.AddText(str(len(copy)),[self.txtPt[0],self.txtPt[1],self.txtPt[2]-3],0.5)
print "FINAL POS = " + str(nextPos)
return nextPos
def execution(self,lightCOLORCOUNT):
if self.CASEB == True: #IF THEY ARE ALL DARK THEN JUST FIND CLOSEST DARK VALUE
closestIndex = rs.PointArrayClosestPoint(self.tempList,self.pos)
closestVert = self.tempList[closestIndex]
closestColor = self.tempColorList[closestIndex]
line = rs.AddLine(self.pos,closestVert)
self.creationHistory.append(line)
elif self.CASEC == True: #IF THERE ARE ANY LIGHT ONES IN THE LIST
newTempList = self.tempList #MAKE A DUP LIST OF VERTS
#print len(newTempList)
newTempCOLOR = self.tempColorList #MAKE A DUP LIST OF COLORS
counter = len(lightCOLORCOUNT) #GET THE NUMBER OF LIGHT VALUES IN LIST
if len(lightCOLORCOUNT)>0:
for p in range(0,counter): #LOOP THROUGH ALL THE BRIGHT COLORS
loc = self.tempColorList.index(lightCOLORCOUNT[p]) #GET THE INDEX OF THE DUP LIST WHERE THE BRIGHT VALUE IS
#print loc
newdot = rs.AddTextDot("OUT",self.tempList[loc])
self.creationHistory.append(newdot)
newTempList.remove(self.tempList[loc]) #REMOVE THE POINT WHERE THE BRIGHT VALUE IS
newTempCOLOR.remove(self.tempColorList[loc]) #REMOVE THE COLORVALUE FROM LIST
closestIndex = rs.PointArrayClosestPoint(newTempList,self.pos) #GET THE NEW CLOSEST INDEX WITHIN THE REMAINING DARK VALUES
closestVert = newTempList[closestIndex] #CLOSEST POINT
closestColor = newTempCOLOR[closestIndex] #CLOSEST COLOR
newLine = rs.AddLine(self.pos,closestVert)
self.creationHistory.append(newLine)
elif self.CASED == True: #IF THERE ARE ONLY LIGHT ONES IN THE LIST
print "SEARCHING!"
output = self.decisionMaker() #FUNCTION TO DECIDE WHAT TO DO
print "outPut = " + str(output)
if output != False:
nextPosLine = rs.AddLine(self.pos,output)
rs.ObjectLayer(nextPosLine,"bigDaddy")
self.creationHistory.append(nextPosLine)
else:
return output
#DIAGRAMING ONLY
#-----------------------------------------------------------------------------------------------------------------------
self.creationHistory.append(nextPosLine)
#deleted = rs.DeleteObjects(self.creationHistory)
finalDot = rs.AddTextDot("NEXT POSITION",output)
rs.TextDotHeight(finalDot,15)
finalCirc = rs.AddCircle(output,1.5)
rs.ObjectLayer(finalCirc,"bigDaddy")
rs.SelectObject(finalDot)
rs.SelectObject(finalCirc)
rs.EnableRedraw(False)
print len(self.creationHistory)
for f in range(len(self.creationHistory)):
rs.ObjectLayer(self.creationHistory[f],"end")
rs.EnableRedraw(True)
#-----------------------------------------------------------------------------------------------------------------------
def infoGrab(self):
self.tempList = []
self.tempColorList = []
for i in range(len(self.ptCOORDS)): #loop through and store coordinates and check distance
dist = rs.Distance(self.ptCOORDS[i],self.pos)
if dist <= self.dTHRESH and self.ptCOORDS[i] != self.pos and self.pos[2] <= self.ptCOORDS[i][2]: #if distance is withint thresh and i am not myself put those values on a separate list
self.tempList.append(self.ptCOORDS[i])
self.tempColorList.append(self.colors[i])
#locLine = rs.AddLine(self.pos,self.ptCOORDS[i])
#rs.ObjectLayer(locLine,"locLine")
for j in range(len(self.tempList)): #Visualization ONLY
dot = rs.AddTextDot(str(self.tempColorList[j]),self.tempList[j])
rs.ObjectLayer(dot,"cVAL")
#rs.ObjectColor(dot,[self.tempColorList[j],self.tempColorList[j],self.tempColorList[j]])
self.creationHistory.append(dot)
results = self.search() #CALL THE SEARCH FUNCTION
checkPt = self.execution(results[1]) #CALL THE EXECUTE FUNCTION
print "TOTAL SEARCH PASSES UNTIL FOUND MATCH = " + str(len(self.searchPASSES))
#print [self.CASEA,self.CASEB,self.CASEC,self.CASED]
if checkPt == False:
print "GOING AT IT AGAIN"
return checkPt
def main():
pts = rs.GetObjects("POINTS",rs.filter.point)
init = rs.GetObject("POINT",rs.filter.point)
coord = rs.PointCoordinates(init)
textPt = rs.GetObject("txtPt",rs.filter.point)
txtcoord = rs.PointCoordinates(textPt)
colorThresh = 200
txtE = rs.AddText(str(colorThresh),[txtcoord[0],txtcoord[1],txtcoord[2]-4],0.5)
ptCoords = []
colorSet = []
for x in range(len(pts)):
coords = rs.PointCoordinates(pts[x])
ptCoords.append(coords)
color = rs.ObjectColor(pts[x])
colorR = rs.ColorRedValue(color)
colorSet.append(colorR)
rs.HideObject(textPt)
loc = myLOCATOR(txtcoord,ptCoords,pts,init,coord,colorThresh,colorSet)
info = loc.infoGrab()
print info
while info == False:
info = loc.infoGrab()
if scriptcontext.escape_test(False):
print "ESC pressed "
break
main()
Update