#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