﻿Option Explicit
'Script written by Joshua Draper
'Script version Friday, October 09, 2009
'
'This script creates a 2d drawing of a metal "perforated panel" from an image and exports 
'text files of xy coordinates for use in Solid works
'

Call bitmapPerf()
Sub bitmapPerf()
	Dim border
	Dim x, y, xWidth, yHeight
	Dim lumSimple, lumAngle, arrPoint, arrObjects
	Dim i
	Dim radius, dblRadius, CircleNormal, CirclePlane, thisCircle, thisLayer
	Dim Radii(3), fileName(2), arrPoints0(), arrPoints1(), arrPoints2()
	Dim j,k,m
	Dim layer(3)
	
	'Instantiate the RhPicture Object
	Dim RhPicture : Set RhPicture = Rhino.GetPlugInObject("RhPicture")
	If IsNull(RhPicture) Then Exit Sub
	
	'Load an arbitrary image
	If Not RhPicture.LoadImage() Then 
		Call Rhino.Print("Image not loaded")
		Exit Sub
	End If
	
	'Recommend that you use a pixelated image that is as big as the number of fabricated pixels you end of using.	
	xWidth = RhPicture.Width()
	yHeight = RhPicture.Height()
	
	'Checks to see if the image is 12x24 pixels
	'You can try any sized image but this popup will remind you if the image is not that size
	If xWidth <> 12 Or yHeight <> 24 Then
		Call Rhino.MessageBox ("Please use a 12x24 pixel image for this assignment. You can try a different sized image but not for the assignment." ,0)	
	End If
	
	ReDim arrObjects (xWidth*(yHeight-2))
	
	'layer names
	layer(0)= "1/8 circles"
	layer(1)= "1/4 circles"
	layer(2)= "1/2 circles"
	layer(3)= "border"
	
	'checks to see if the layers already exist. If they don't, it makes them.
	For i=0 To 3 
		If IsLayer (layer(i)) Then
			Rhino.Print layer(i) & "is already made"
		Else Rhino.AddLayer (layer(i))		End If		
	Next
	
	
	'draw the border and put it in its layer
	Dim RectCorners(4)
	RectCorners(0)= Array(xWidth/2, yHeight/2, 0)
	RectCorners(1)= Array(xWidth/2, -yHeight/2, 0)
	RectCorners(2)= Array(-xWidth/2, -yHeight/2, 0)
	RectCorners(3)= Array(-xWidth/2, yHeight/2, 0)
	RectCorners(4)= Array(xWidth/2, yHeight/2, 0)

	Rhino.AddPolyline RectCorners
	Rhino.CurrentLayer (layer(3))
	border = Rhino.FirstObject
	thisLayer = Rhino.CurrentLayer
	Call Rhino.ObjectLayer (border, thisLayer)
	 	
	'the different endmill dimensions: 1/8", 1/4" and 1/2"
	Radii(0)= 0
	Radii(1)= (.125)/2 
	Radii(2)= (.25)/2 
	Radii(3)= (.5)/2
	
	'filenames
	fileName(0) = "1-8.txt"
	fileName(1) = "1-4.txt"
	fileName(2) = "1-2.txt"
	
	'the counters 
	i = 0
	j = 0
	k = 0
	m = 0
	
	'the main loop that: 
	'1: gets the luminance value of Each pixel
	'2: sorts the luminance by ranges And assigns the appropriate circle size
	'3: draws, places the circles And puts In the correct layer
	'4: counts the operations done out of the total
	
	Call Rhino.EnableRedraw(False)
	For x = 0 To xWidth-1	
		'elimates the top and bottom rows by limiting y
		For y = 1 To yHeight-2 
			'set the circle hole to sit on the same grid as the image. no resizing. compare to assignment 1 script
			arrPoint = Array((x+.5)-(xWidth/2), (y+.5)- (yHeight/2),0)
						'Get the luminance of pixels. values range from 0 to 1			
			'constrains luminace to  1/8, 1/4 or 1/2in diameter endmills. 
			'colors below .25 luminance are not drilled	
			lumSimple = RhPicture.Luminance(x,abs(y-(yHeight-1)))
	
			If lumSimple >= 0 And lumSimple < .25 Then  
				Radius = Radii(0)				
			ElseIf lumSimple >= .25 And lumSimple < .5 Then 
				Radius = Radii(1)
				ReDim Preserve arrPoints0(j)
				arrPoints0(j)= arrPoint
				j =  j+1
				Rhino.CurrentLayer (layer(0))
			ElseIf lumSimple >= .5 And lumSimple < .75 Then 
				Radius = Radii(2)
				ReDim Preserve arrPoints1(k)
				arrPoints1(k)= arrPoint
				k =  k+1
				Rhino.CurrentLayer (layer(1))
			ElseIf lumSimple >= .75 And lumSimple <= 1 Then 
				Radius = Radii(3)
				ReDim Preserve arrPoints2(m)
				arrPoints2(m)= arrPoint
				m =  m+1
				Rhino.CurrentLayer (layer(2))		
			End If
			
			'Uncomment the below line to see the order that the script places the circles
			'Rhino.AddTextDot i, arrPoint
			
			'draw a circle proportional to luminosity
			CircleNormal = Rhino.PointSubtract(arrPoint, Array(arrPoint(0), arrPoint(1), arrPoint(2)+1 ))
			CirclePlane = Rhino.PlaneFromNormal(arrPoint, CircleNormal)
			Call Rhino.AddCircle (CirclePlane, Radius)
			'put the circle in the right layer
			thisCircle = Rhino.FirstObject
			thisLayer = Rhino.CurrentLayer
			Call Rhino.ObjectLayer (thisCircle, thisLayer)	  					
			
			'update the counter 	
			Rhino.StatusBarMessage i+1 & "/" & xWidth * (yHeight-2)
			
			'increment the counter
			i = i+1

	Next
	Next

	Call Rhino.EnableRedraw(True)	
		
	'Call export text file function
	Call ExportTextFile (arrPoints0, fileName(0))	
	Call ExportTextFile (arrPoints1, fileName(1))	
	Call ExportTextFile (arrPoints2, fileName(2))
	
	'pure the file of unused layers
	Rhino.CurrentLayer (layer(0))
	Rhino.Command "-Purge Layers=Yes _Enter"
	
	'count the number of each type of circle and the total amount
	'try to keep the total number of circles around 150 or so
	'this will save time in the lab
	Rhino.Print "1/8 circles = " & Ubound(arrPoints0)		
	Rhino.Print "1/4 circles = " & Ubound(arrPoints1)	
	Rhino.Print "1/2 circles = " & Ubound(arrPoints2)
	Rhino.Print "total circles = " & Ubound(arrPoints0) + Ubound(arrPoints0) + Ubound(arrPoints2)

End Sub


Function ExportTextFile (arrPoints, fileName)
	
	Dim	strFilter, strFileName, objFSO, objStream
	Dim strObject, arrPoint, strPoint
	Dim whiteSpace, strDelimiter
	
	' User-definable file filters
	strFilter = "Text File (*.txt)|*.txt|All Files (*.*)|*.*||"
	
	' User-definable prefixes
	whiteSpace = ""

	' User-definable delimiter(s)
	strDelimiter = ","
	
	' Parameters for Save window
	strFileName = Rhino.SaveFileName("Save Perforation Coordinates As", strFilter,, fileName)
	If IsNull(strFileName) Then Exit Function

	' Get the file system object
	Set objFSO = CreateObject("Scripting.FileSystemObject")
	On Error Resume Next

	' Get a new text file
	Set objStream = objFSO.CreateTextFile(strFileName, True)

	If Err Then
		MsgBox Err.Description
		Exit Function
	End If

	'create each line in the text file
	If IsArray(arrPoints) Then
		For Each arrPoint In arrPoints
			strPoint = whiteSpace & CStr(arrPoint(0)) & whiteSpace & strDelimiter & whiteSpace & CStr(arrPoint(1))
			' Write the coordinate to the file
			objStream.WriteLine(strPoint)

		Next
	End If

	objStream.Close
End Function