PDA

View Full Version : Interactive bitmaps


MatanH
06-04-2008, 02:30 PM
Here are some Toys that I have writen in the last few days,
just to improve my skilles :D. The basic idea is based on Bobo's tutorial
about the basic maxScript renderer combined with some of my ideas about
a joystick gui.

If you have any ideas of other cool stuff that we can do with this simple
engen, you are wellcom to post them here.

I would also like to here any ideas about how to improve the engen and make it faster.

Cheers :buttrock:

Edit:
(04.07.2008) Added New code on page 2 (http://forums.cgsociety.org/showthread.php?f=98&t=639039&page=2&pp=15) - Spline.
(05.07.2008) Added new feature to Spline demo - 'Bezier / Bezier Corner' Handles.
(06.07.2008) Improved 'Draw Dot' function makes it possible to control spline thickness.
http://img371.imageshack.us/img371/1990/bitmaptest10rg4.jpg

(03.07.2008) Added New code on page 2 (http://forums.cgsociety.org/showthread.php?f=98&t=639039&page=2&pp=15) - Bezier Curve with the Draw Edge technique.
http://img70.imageshack.us/img70/7307/bitmaptest8jc5.jpg

(03.07.2008) Added New code on page 2 (http://forums.cgsociety.org/showthread.php?f=98&t=639039&page=2&pp=15) - Draw Edge.
http://img67.imageshack.us/img67/3986/bitmaptest7ve6.jpg

(16.06.2008) Added New code on page 2 (http://forums.cgsociety.org/showthread.php?f=98&t=639039&page=2&pp=15) - Bezier Curve.
http://img355.imageshack.us/img355/7579/test06hz6.jpg

MatanH
06-04-2008, 02:34 PM
Test #1:
http://img440.imageshack.us/img440/233/bitmaptest01ja4.jpg

try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 1"
(
-- Local Variable Declerations
------------------------------------------

local dim = 100
local jsPos = [dim/2,dim/2]
local mousePressed = false

-- User Interface
------------------------------------------

bitmap bmGraph "" width:dim height:dim
spinner spRadius "Radius:" range:[0.1,1000,10] align:#center fieldwidth:40
spinner spPower "Power:" range:[0,10,10] align:#center fieldwidth:40 scale:0.01

-- Functions
------------------------------------------

fn mainFunc x y =
(
local dist = distance jsPos [x,y]
if dist > spRadius.value do dist = spRadius.value
dist ^ spPower.value / spRadius.value ^ spPower.value
)

fn updateGraph =
(
local newBitmap = bitmap dim dim color:white
for y = 1 to dim - 1 do (
local pixelArr = #()
for x = 1 to dim - 1 do (
local pixelColor = white
case of (
default: (pixelColor *= mainFunc x y)
(y == dim/2): (pixelColor *= if mainFunc x y > 0.7 then 0.7 else mainFunc x y)
(x == dim/2): (pixelColor *= if mainFunc x y > 0.7 then 0.7 else mainFunc x y)
) -- end case
append pixelArr pixelColor
) -- end x loop
setPixels newBitmap [1,y] pixelArr
) -- end y loop
bmGraph.bitmap = newBitmap
) -- end updateGraph fn

fn updateJS pos force:false =
(
if mousePressed or force do (
jsPos = pos - bmGraph.pos
updateGraph()
)
)

fn openDialog =
(
createDialog bitmapTest width:(dim + 10)
)

fn init =
(
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on spRadius changed val do updateGraph()
on spPower changed val do updateGraph()

on bitmapTest mousemove pos do updateJS pos
on bitmapTest lbuttondown pos do mousePressed = true
on bitmapTest lbuttonup pos do mousePressed = false
on bitmapTest rbuttonup pos do updateJS ([dim/2,dim/2] + bmGraph.pos) force:true

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()


Hold down left mouse button and drag around inside the bitmap to move the circle

MatanH
06-04-2008, 02:38 PM
Test #2:
http://img296.imageshack.us/img296/5777/bitmaptest02jn4.jpg

try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 2"
(
-- Local Variable Declerations
------------------------------------------

local dim = 100
local jsPos = [dim/2,dim/2]
local mousePressed = false
local color1 = black
local color2 = green
local color3 = white
local color4

-- User Interface
------------------------------------------

bitmap bmGraph "" width:dim height:dim

-- Functions
------------------------------------------

fn mainFunc x y =
(
x -= dim / 2
y = dim / 2 - y

local a = jsPos.x - dim / 2
local b = dim / 2 - jsPos.y

local f = (b / (1 + ((x / a) ^ 2)))

if y == f then color4 = color3 else color4 = color2

if b >= 0 then (
case of (
(f < y): 1
(y / f < 0): 1
default: (1 - y / f)
)
) else (
case of (
(f > y): 1
(y / f < 0): 1
default: (1 - y / f)
)
)
)

fn updateGraph =
(
local newBitmap = bitmap dim dim color:color1
for y = 1 to dim do (
local pixelArr = #()
for x = 1 to dim - 1 do (
local pixelColor
case of (
default: (pixelColor = color1 * (mainFunc x y) + color4 * (1 - (mainFunc x y)))
(y == dim/2): (pixelColor = white * 0.5)
(x == dim/2): (pixelColor = white * 0.5)
) -- end case
append pixelArr pixelColor
) -- end x loop
setPixels newBitmap [1,y] pixelArr
) -- end y loop
bmGraph.bitmap = newBitmap
) -- end updateGraph fn

fn updateJS pos force:false =
(
if mousePressed or force do (
jsPos = pos - bmGraph.pos
updateGraph()
)
)

fn openDialog =
(
createDialog bitmapTest width:(dim + 10) height:(dim + 10)
)

fn init =
(
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on bitmapTest mousemove pos do updateJS pos
on bitmapTest lbuttondown pos do mousePressed = true
on bitmapTest lbuttonup pos do mousePressed = false
on bitmapTest rbuttonup pos do updateJS ([dim/2,dim/2] + bmGraph.pos) force:true

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()


Hold down left mouse button and drag inside the bitmap to see the graph update

MatanH
06-04-2008, 02:43 PM
Test #3:
http://img512.imageshack.us/img512/3631/bitmaptest03ev6.jpg

try destroyDialog sphereTest catch ()
rollout sphereTest "Sphere Test"
(
-- Local Variable Declerations
------------------------------------------

local dim = 100
local jsPos = [dim/2,dim/2]
local mousePressed = false

-- User Interface
------------------------------------------

bitmap bmGraph "" width:dim height:dim
spinner spRadius "Radius:" range:[0,1000,40] align:#right fieldWidth:40
spinner spZ "Z:" range:[-(dim/2),(dim/2),10] align:#right fieldWidth:40
spinner spMult "Multiply:" range:[0,10,1] align:#right fieldWidth:40
spinner spSteps "Steps:" range:[1,6,1] align:#right fieldWidth:40 type:#integer

-- Functions
------------------------------------------

fn mainFunc x y =
(
local dist = distance [dim/2,dim/2] [x,y]
local z = spRadius.value ^ 2 - dist ^ 2
z = if z < 0.0 then 0.0 else sqrt z
local v1 = [dim/2,dim/2,0] - [jsPos.x,jsPos.y,spZ.value]
local v2 = [dim/2,dim/2,0] - [x,y,z]
local exp = dot (normalize v1) (normalize v2) * spMult.value
if exp < 0.0 then exp = 0.0
if exp > 1.0 then exp = 1.0
if dist < spRadius.value - 2 then exp else (
if dist > spRadius.value + 2 then 1.0 else (
local val = 0.0
for a = 1 to spSteps.value do (
for b = 1 to spSteps.value do (
dist = distance [dim/2,dim/2] [x + (1.0 / a) - 0.5 , y + (1.0 / b) - 0.5]
val += (if dist <= spRadius.value then exp else 1.0) / (spSteps.value ^ 2)
)
)
val
)
)
)

fn updateGraph =
(
local newBitmap = bitmap dim dim color:white
for y = 1 to dim - 1 do (
local pixelArr = #()
for x = 1 to dim - 1 do (
local pixelColor = white
case of (
default: (pixelColor *= mainFunc x y)
(y == jsPos.y): (pixelColor = red)
(x == jsPos.x): (pixelColor = red)
) -- end case
append pixelArr pixelColor
) -- end x loop
setPixels newBitmap [1,y] pixelArr
) -- end y loop
bmGraph.bitmap = newBitmap
) -- end updateGraph fn

fn updateJS pos force:false =
(
if mousePressed or force do (
jsPos = pos - bmGraph.pos
updateGraph()
)
)

fn openDialog =
(
createDialog sphereTest width:(dim + 10)
)

fn init =
(
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on spRadius changed val do updateGraph()
on spZ changed val do updateGraph()
on spMult changed val do updateGraph()
on spSteps changed val do updateGraph()

on sphereTest mousemove pos do updateJS pos
on sphereTest lbuttondown pos do mousePressed = true
on sphereTest lbuttonup pos do mousePressed = false
on sphereTest rbuttonup pos do updateJS ([dim/2,dim/2] + bmGraph.pos) force:true

on sphereTest open do init()
on sphereTest close do done()

) -- end of rollout

sphereTest.openDialog()


Hold down left mouse button and drag around inside the bitmap to light the sphere
from other angles.

MatanH
06-04-2008, 02:45 PM
Test #4:
http://img171.imageshack.us/img171/73/bitmaptest04ys9.jpg

try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 4"
(
-- Local Variable Declerations
------------------------------------------

local dim = 100
local randArr = #()
local colorArr = #()
local lastPt = 0
local mousePressed = false

-- User Interface
------------------------------------------

bitmap bmGraph "" width:dim height:dim
spinner spNumPts "Num Pts:" range:[1,100,5] type:#integer align:#right fieldwidth:40
spinner spRadius "Radius:" range:[0,10,2.5] align:#right fieldwidth:40
spinner spLines "Lines:" range:[0,50,0] align:#right fieldwidth:40

-- Functions
------------------------------------------

fn mainFunc x y =
(
local dist1 = 999999
local dist2 = undefined
local n = 0
for i = 1 to randArr.count do (
local newDist = distance [x,y] randArr[i]
if newDist <= dist1 do (
dist2 = dist1
dist1 = newDist
n = i
)
)
if dist2 != undefined and abs (dist1 - dist2) < spLines.value then black else (
if dist1 > spRadius.value then colorArr[n] else red
)
)

fn updateGraph =
(
local newBitmap = bitmap dim dim color:white
for y = 1 to dim do (
local pixelArr = #()
for x = 1 to dim - 1 do (
local pixelColor = mainFunc x y
append pixelArr pixelColor
) -- end x loop
setPixels newBitmap [1,y] pixelArr
) -- end y loop
bmGraph.bitmap = newBitmap
) -- end updateGraph fn

fn initRand =
(
randArr = #()
colorArr = #()
for i = 1 to spNumPts.value do (
append randArr [random 0 dim,random 0 dim]
append colorArr (random (color 50 50 50) (color 200 200 200))
)
updateGraph()
)

fn getPt pos =
(
pos = pos - bmGraph.pos
local lastDist = 999999
lastPt = 0
for i = 1 to randArr.count do (
local newDist = distance [pos.x,pos.y] randArr[i]
if newDist < lastDist do (
lastDist = newDist
lastPt = i
)
)
mousePressed = true
)

fn updatePt pos =
(
pos = pos - bmGraph.pos
if mousePressed and lastPt > 0 then (
randArr[lastPt] = pos
updateGraph()
)
)

fn resizeDialog pos =
(
local oldDim = dim
dim = if bitmapTest.width < bitmapTest.height then bitmapTest.width - 20 else bitmapTest.height - 20
bmGraph.width = dim
bmGraph.height = dim
for i = 1 to randArr.count do (
randArr[i] *= dim / oldDim
)
updateGraph()
spLines.pos = [spLines.pos.x,pos.y - 20]
spRadius.pos = [spRadius.pos.x,spLines.pos.y - 20]
spNumPts.pos = [spNumPts.pos.x,spRadius.pos.y - 20]
)

fn openDialog =
(
createDialog bitmapTest width:(dim + 20) style:#(#style_titlebar, #style_border, #style_sysmenu,#style_resizing)
)

fn init =
(
initRand()
)


fn done =
(
-- cleanup code
gc light:true
)


-- Event Handlers
------------------------------------------

on spRadius changed val do updateGraph()
on spLines changed val do updateGraph()
on spNumPts changed val do initRand()

on bitmapTest lbuttondown pos do getPt pos
on bitmapTest lbuttonup pos do mousePressed = false
on bitmapTest mousemove pos do updatePt pos
on bitmapTest resized pos do resizeDialog pos

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()


Hold down left mouse button and drag around inside the bitmap to see what happens..

MatanH
06-04-2008, 02:47 PM
Test #5:
http://img171.imageshack.us/img171/1994/bitmaptest05rh1.jpg

try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 5"
(
-- Local Variable Declerations
------------------------------------------

local dim = 100.0
local jsPos = [dim / 2 , dim / 2]
local mousePressed = false

-- User Interface
------------------------------------------

bitmap bmGraph "" width:dim height:dim
spinner spGrid "Grid:" range:[0,20,8] align:#right fieldwidth:40
spinner spRadius "Radius:" range:[-100,100,15] align:#right fieldwidth:40
spinner spMulti "Multiply:" range:[-100,100,1] align:#right fieldwidth:40
spinner spAspect "Aspect:" range:[0,1,0.3] align:#right fieldwidth:40 scale:0.01

-- Functions
------------------------------------------

fn mainFunc x y =
(
fn modFunc i x y =
(
local p = [x,y] - [dim,dim] / 2 - ([x,y] - jsPos) / (1 + ((length ([x,y] - jsPos)) / spRadius.value) ^ spMulti.value)
local m = mod (abs(p[i])) (dim / spGrid.value)
m >= ((dim / spGrid.value) * (1 - spAspect.value) / 2) and m < ((dim / spGrid.value) * (1 + spAspect.value) / 2)
) -- end fn

if distance jsPos [x,y] < 2.5 then (
red
) else (
if modFunc 1 x y then (
white
) else (
if modFunc 2 x y then (
white
) else (
black
) -- end y
) -- end x
) -- end Red
)

fn updateGraph =
(
local newBitmap = bitmap dim dim color:white
for y = 1 to dim do (
local pixelArr = #()
for x = 1 to dim - 1 do (
local pixelColor = mainFunc x y
append pixelArr pixelColor
) -- end x loop
setPixels newBitmap [1,y] pixelArr
) -- end y loop
bmGraph.bitmap = newBitmap
) -- end updateGraph fn

fn updateJS pos =
(
if mousePressed do (
jsPos = pos - bmGraph.pos
updateGraph()
)
)

fn openDialog =
(
createDialog bitmapTest width:(dim + 20) style:#(#style_titlebar, #style_border, #style_sysmenu,#style_resizing)
)

fn init =
(
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on spRadius changed val do updateGraph()
on spAspect changed val do updateGraph()
on spGrid changed val do updateGraph()
on spMulti changed val do updateGraph()

on bitmapTest lbuttondown pos do mousePressed = true
on bitmapTest lbuttonup pos do mousePressed = false
on bitmapTest mousemove pos do updateJS pos

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()


You know what to do..

martinB
06-10-2008, 09:58 AM
Nice, thanks for posting!

I especially like the delaunay demo and the bell curve graph thing.

-- MartinB

MatanH
06-10-2008, 10:41 AM
Finally a coment :cry:!
Thanks Martin :thumbsup:

davestewart
06-10-2008, 11:08 AM
Hey, that's really cool!

Maybe next time post a small screenshot that links directly to the script. I think I'd be more likely to play then.

:D

MatanH
06-10-2008, 11:11 AM
Thanks davestewart,
I think I'll do that...

Polimeno
06-11-2008, 12:55 AM
seems a really nice tool man !

donīt think iīm messing around,
i just couldnīt understand it....

please,
tell me more of some situations your tool can be usefull.

erilaz
06-11-2008, 12:58 AM
These are really sweet. Thanks for sharing Matan! It's great to see more scripters coming out of the woodwork! :)

PEN
06-11-2008, 01:03 AM
Nice work Matan, I haven't tried it all but are they subject to the same flashing that I was getting in the demo that I set up some time ago?

PEN
06-11-2008, 01:36 AM
Now that is interesting, you are using bitMaps and not imgTags and it isn't flashing. That is very cool as I'm still working for a client in Max 8 and need a UI with this sort of setup and I was going to live with the flashing of the imgtag. I would what the difference between the two is.

PEN
06-11-2008, 01:44 AM
Ah I see the difference, You are having to use the createDialog event handlers instead of the bitMaps which you can do with imgTag. I still wonder ahy imgTag is slower to draw?

MatanH
06-11-2008, 07:22 AM
Wow,
How meny replies!

Paul - Yes I saw your imageTag joystick, I even comment you about the last
(psychedelic) test. I think the difference here is not between the image tag and
bitmap. I think your flashing problem comes from the timer.
I use the 'on mouse move' event handler instead.

RNThead - I started looking into this tool to find a solution for graphic representation
of 2 dimensional controllers, and carried away a bit into searching some other cool
stuff that can be done by changing the main function in it.. :D

j-man
06-12-2008, 01:33 PM
Hi Matan,

These are really cool! keep up the good work!

Josh.

MatanH
06-16-2008, 01:57 PM
Test #6:
http://img355.imageshack.us/img355/7579/test06hz6.jpg


try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 6"
(
-- Local Variable Declerations
------------------------------------------

local width = 70
local height = width
local boarder = 20

local bgColor = white
local stripedLinesColor = bgColor / 2
local graphColor = blue
local bgMap

-- User Interface
------------------------------------------

bitmap bmGraph "" width:(width * 2) height:(height + 2 * boarder)
spinner spMax "Max:" range:[-10,10,1] align:#left offset:[-10,0] fieldwidth:35 scale:0.01
spinner spMin "Min:" range:[-10,10,0] align:#right offset:[10,-22] fieldwidth:35 scale:0.01
spinner spPrec "precision:" range:[0.0001,0.1,0.0004] align:#center fieldwidth:40 scale:0.0002

-- Functions
------------------------------------------

fn createBGMap =
(
bgMap = bitmap bmGraph.width bmGraph.height color:bgColor

-- Draw Horizontal striped lines:
local linePixels = #()
for x = 0 to (bmGraph.width - 1) do (
append linePixels (if mod x 10 > 5 then stripedLinesColor else bgColor)
)
setPixels bgMap [0,boarder] linePixels
setPixels bgMap [0,boarder + height] linePixels

-- Draw Vertical striped lines:
for y = 0 to (bmGraph.height - 1) do (
if mod y 10 > 5 then (
setPixels bgMap [width,y] #(stripedLinesColor)
)
)
)

fn updateGraph =
(
-- Draw Bezier Curve:
local newMap = copy bgMap
local P0 = [0,height + boarder]
local P1 = [width / 3,boarder + height * (1 - spMin.value)]
local P2 = [width * 2 / 3,boarder + height * (1 - spMax.value)]
local P3 = [width,boarder]

local lastPt = [0,0]
for t = 0.0 to 1.0 by spPrec.value do (
local Pt = (1-t) ^ 3 * P0 + 3 * (1-t) ^ 2 * t * P1 + 3 * (1-t) * t ^ 2 * P2 + t ^ 3 * P3
for i = 1 to 2 do (
Pt[i] = if Pt[i] - (floor Pt[i]) > 0.5 then ceil Pt[i] else floor Pt[i]
)
if Pt != lastPt then (
lastPt = Pt
setPixels newMap Pt #(graphColor)
setPixels newMap [2 * width - Pt.x,Pt.y] #(graphColor)
)
)
bmGraph.bitmap = newMap
) -- end updateGraph fn

fn openDialog =
(
createDialog bitmapTest width:((width + 5) * 2) style:#(#style_titlebar, #style_border, #style_sysmenu,#style_resizing)
)

fn init =
(
createBGMap()
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on spPrec changed val do updateGraph()
on spMax changed val do updateGraph()
on spMin changed val do updateGraph()

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()

thatoneguy
06-16-2008, 07:30 PM
I'm starting to feel like casandra here but I'll say it again:

Bitmaps don't flash. IMGTags do. So sayeth the Lord.

:D

http://forums.cgsociety.org/showpost.php?p=5106919&postcount=40

http://forums.cgsociety.org/showpost.php?p=5027812&postcount=22

labbejason
06-16-2008, 08:31 PM
Wow these are great! Thanks for sharing.

Kramsurfer
06-16-2008, 09:47 PM
Cool little UI thingys. I can think of an immediate use for two of them as ui improvements here at focus.... thanks so much for sharing.... I think I'll impliment test number five as a control for our network render file pathing... and see if anyone can find their renders... ha ha...

MatanH
06-16-2008, 10:10 PM
...I think I'll impliment test number five as a control for our network render file pathing... and see if anyone can find their renders... ha ha...

I am always in favor of making animators or other crew members go crazy because of
my script and tools just for fun. But I am not sure I understood exactly how are you
planing to use test 5 for whatever you said you would.. :curious:

By the way, I would be glad to hear how and where did you implement these babies.

Thanks for the comments!

Kramsurfer
06-17-2008, 04:56 AM
Well.. I was thinking each grid opening could represent a path on the network... and of course the user would have no idea where it is, but could get there through this ui element... ha ha ha....( evil laugh ) Really, Either of the curves would look nice as soft selection ui elements..

f97ao
06-17-2008, 07:55 AM
This is awesome. Great job!

i love playing with bitmaps. So much fun and can really help illustrating scenarios. How fast are bitmaps generally for you guys to manipulate. Where do you guys begin to see the limitations? I haven't really tried to push the limit with bitmaps.

/Andreas

phoelix
06-17-2008, 01:53 PM
nice!, didn't know exactly how the softselection work, now i know thanks to you. A bezier line with both tangent points manipulated by the pinch and bubble values respectively

MatanH
07-03-2008, 01:08 PM
Test #7:
http://img67.imageshack.us/img67/3986/bitmaptest7ve6.jpg


try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 7"
(
-- Local Variable Declerations
------------------------------------------

local dim = 200

local bgMap
local mousePressed = false

local bgColor = white
local p1Color = red
local p2Color = green
local p3Color = blue

local pt1 = [10,dim - 10]
local pt2 = [dim / 2,10]
local pt3 = [dim - 10,dim - 10]
local jsPos = [0,0]

-- User Interface
------------------------------------------

bitmap bmGraph "" width:dim height:dim
spinner spSubD "SubD:" range:[1,100,6] type:#integer align:#center fieldWidth:30

-- Functions
------------------------------------------

fn createBGMap =
(
bgMap = bitmap bmGraph.width bmGraph.height color:bgColor
)

fn lineLineIntersect pA pB pC pD =
(
pA = [pA.x,pA.y,0]
pB = [pB.x,pB.y,0]
pC = [pC.x,pC.y,0]
pD = [pD.x,pD.y,0]

local a = pB - pA
local b = pD - pC
local c = pC - pA
local cross1 = cross a b
local cross2 = cross c b
local n = pA + (a * ((dot cross2 cross1) / ((length cross1) ^ 2)))
[n.x,n.y]
)

fn getSteps p1 p2 =
(
struct s_neighbor (
pos,
dist
)

local neighborsPos = #([-1,-1],[0,-1],[1,-1],[-1,0],[1,0],[-1,1],[0,1],[1,1])
local neighbors = #()

for p in neighborsPos do (
local newNeighbor = s_neighbor p (distance p2 (p1 + p))
append neighbors newNeighbor
)

fn sortFn v1 v2 =
(
if v1.dist > v2.dist then 1
else if v1.dist < v2.dist then -1
else 0
)

qsort neighbors sortFn
#(neighbors[1].pos,neighbors[2].pos)
)

fn getStep p1 p2 pt steps =
(
local crossPt = lineLineIntersect p1 p2 (pt + steps[1]) (pt + steps[2])
local dist1 = distance crossPt (pt + steps[1])

if dist1 < 0.5 then (
pt + steps[1]
) else (
pt + steps[2]
)
)

fn drawEdge p1 p2 c1 c2 bMap =
(
setPixels bMap p1 #(c1)
setPixels bMap p2 #(c2)

local newPt = p1
local steps = getSteps p1 p2
local cnt = 0

while newPt != p2 and cnt < dim * 2 do (
newPt = getStep p1 p2 newPt steps
local dist1 = distance p1 newPt
local dist2 = distance p2 newPt
local newColor = c1 * dist2 / (dist1 + dist2) + c2 * dist1 / (dist1 + dist2)
setPixels bMap newPt #(newColor)
cnt += 1
)

bMap
)

fn updateGraph =
(
local newMap = copy bgMap
local subD = spSubD.value + 1

newMap = drawEdge pt1 pt2 p1color p2color newMap
newMap = drawEdge pt1 pt3 p1color p3color newMap
newMap = drawEdge pt2 pt3 p2color p3color newMap

fn round val =
(
if val - (floor val) > 0.5 then (
ceil val
) else (
floor val
)
)

for i = 1.0 to subD - 1.0 do (
local rat = i / subD
local pt = pt3 + (pt2 - pt3) * rat
pt = [round pt.x,round pt.y]
newMap = drawEdge pt1 pt p1color (p2color * rat + p3color * (1 - rat)) newMap
)

for i = 1.0 to subD - 1.0 do (
local rat = i / subD
local pt = pt3 + (pt1 - pt3) * rat
pt = [round pt.x,round pt.y]
newMap = drawEdge pt2 pt p2color (p1color * rat + p3color * (1 - rat)) newMap
)

for i = 1.0 to subD - 1.0 do (
local rat = i / subD
local pt = pt2 + (pt1 - pt2) * rat
pt = [round pt.x,round pt.y]
newMap = drawEdge pt3 pt p3color (p1color * rat + p2color * (1 - rat)) newMap
)

bmGraph.bitmap = newMap
) -- end updateGraph fn

fn updateJS pos =
(
if mousePressed do (
jsPos = pos - bmGraph.pos

if jsPos.x >= 0 and jsPos.x <= dim then (
if jsPos.y >= 0 and jsPos.y <= dim then (
if distance jsPos pt1 < distance jsPos pt2 and distance jsPos pt1 < distance jsPos pt3 then (
pt1 = jsPos
) else (
if distance jsPos pt2 < distance jsPos pt3 then (
pt2 = jsPos
) else (
pt3 = jsPos
)
)

updateGraph()
)
)
)
)

fn openDialog =
(
createDialog bitmapTest width:(dim + 10) style:#(#style_titlebar, #style_border, #style_sysmenu,#style_resizing)
)

fn init =
(
createBGMap()
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on bitmapTest lbuttondown pos do mousePressed = true
on bitmapTest lbuttonup pos do mousePressed = false
on bitmapTest mousemove pos do updateJS pos

on spSubD changed val do updateGraph()

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()


For a while I was curious about how to draw a line between to point in a bitmap, the quickest way. Yesterday I got an idea. This is the first demo using the new technique.
The basic idea is to test the neighbor pixels of the pixel located on one end of the line and pick the two pixels that are closest to the other end. Than all you need to do is to progress along the line by moving from neighbor to neighbor and checking which neighbor should be next until you reach the other end.

prettyPixel (http://forums.cgsociety.org/member.php?u=144262) - thanks for that wonderful thread:
http://forums.cgsociety.org/showthread.php?f=98&t=295257
I used the Line-Line Intersection function to determine which neighbor to pick.

I would also like to thank Dave (Opeth) for helping me to develop the idea.

MatanH
07-03-2008, 03:11 PM
Test #8:
http://img70.imageshack.us/img70/7307/bitmaptest8jc5.jpg


try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 6"
(
-- Local Variable Declerations
------------------------------------------

local width = 200
local height = 200
local boarder = 20

local bgColor = white
local p1Color = red
local p2Color = green
local p3Color = blue

local stripedLinesColor = bgColor / 2
local graphColor = blue
local bgMap
local mousePressed = false
local jsPos = [0,0]

-- User Interface
------------------------------------------

bitmap bmGraph "" width:(width * 2) height:(height + 2 * boarder)
spinner spMax "Max:" range:[-10,10,1] align:#left offset:[-10,0] fieldwidth:35 scale:0.01
spinner spMin "Min:" range:[-10,10,0] align:#right offset:[10,-22] fieldwidth:35 scale:0.01
spinner spPrec "precision:" range:[0.01,1,0.5] align:#center fieldwidth:40 scale:0.01

-- Functions
------------------------------------------

fn createBGMap =
(
bgMap = bitmap bmGraph.width bmGraph.height color:bgColor

-- Draw Horizontal striped lines:
local linePixels = #()
for x = 0 to (bmGraph.width - 1) do (
append linePixels (if mod x 10 > 5 then stripedLinesColor else bgColor)
)
setPixels bgMap [0,boarder] linePixels
setPixels bgMap [0,boarder + height] linePixels

-- Draw Vertical striped lines:
for y = 0 to (bmGraph.height - 1) do (
if mod y 10 > 5 then (
setPixels bgMap [width,y] #(stripedLinesColor)
)
)
)

fn lineLineIntersect pA pB pC pD =
(
pA = [pA.x,pA.y,0]
pB = [pB.x,pB.y,0]
pC = [pC.x,pC.y,0]
pD = [pD.x,pD.y,0]

local a = pB - pA
local b = pD - pC
local c = pC - pA
local cross1 = cross a b
local cross2 = cross c b
local n = pA + (a * ((dot cross2 cross1) / ((length cross1) ^ 2)))
[n.x,n.y]
)

fn getSteps p1 p2 =
(
struct s_neighbor (
pos,
dist
)

local neighborsPos = #([-1,-1],[0,-1],[1,-1],[-1,0],[1,0],[-1,1],[0,1],[1,1])
local neighbors = #()

for p in neighborsPos do (
local newNeighbor = s_neighbor p (distance p2 (p1 + p))
append neighbors newNeighbor
)

fn sortFn v1 v2 =
(
if v1.dist > v2.dist then 1
else if v1.dist < v2.dist then -1
else 0
)

qsort neighbors sortFn
#(neighbors[1].pos,neighbors[2].pos)
)

fn getStep p1 p2 pt steps =
(
local crossPt = lineLineIntersect p1 p2 (pt + steps[1]) (pt + steps[2])
local dist1 = distance crossPt (pt + steps[1])

if dist1 < 0.5 then (
pt + steps[1]
) else (
pt + steps[2]
)
)

fn drawEdge p1 p2 bMap =
(
local newPt = p1
local steps = getSteps p1 p2
local cnt = 0

while newPt != p2 and cnt < 200 do (
newPt = getStep p1 p2 newPt steps
setPixels bMap newPt #(graphColor)
cnt += 1
)

bMap
)

fn updateGraph =
(
-- Draw Bezier Curve:
local newMap = copy bgMap
local P0 = [0,height + boarder]
local P1 = [width / 3,boarder + height * (1 - spMin.value)]
local P2 = [width * 2 / 3,boarder + height * (1 - spMax.value)]
local P3 = [width,boarder]

local lastPt = [0,0]
for t = 0.0 to 1.0 by spPrec.value do (
local Pt = (1-t) ^ 3 * P0 + 3 * (1-t) ^ 2 * t * P1 + 3 * (1-t) * t ^ 2 * P2 + t ^ 3 * P3
for i = 1 to 2 do (
Pt[i] = if Pt[i] - (floor Pt[i]) > 0.5 then ceil Pt[i] else floor Pt[i]
)
if Pt != lastPt then (
newMap = drawEdge lastPt Pt newMap
newMap = drawEdge [2 * width - lastPt.x,lastPt.y] [2 * width - Pt.x,Pt.y] newMap
lastPt = Pt
)
)
newMap = drawEdge [width,boarder] lastPt newMap
newMap = drawEdge [width,boarder] [2 * width - lastPt.x,lastPt.y] newMap
bmGraph.bitmap = newMap
) -- end updateGraph fn

fn openDialog =
(
createDialog bitmapTest width:((width + 5) * 2) style:#(#style_titlebar, #style_border, #style_sysmenu,#style_resizing)
)

fn init =
(
createBGMap()
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on spPrec changed val do updateGraph()
on spMax changed val do updateGraph()
on spMin changed val do updateGraph()

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()


A Bezier Curve with the Draw Edge Function.

MatanH
07-04-2008, 04:13 PM
Test #9:
http://img509.imageshack.us/img509/1162/bitmaptest9qx1.jpg


try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 9"
(
-- Local Variable Declerations
------------------------------------------

local dim = 200
local knotRad = 2.4

local bgMap
local mousePressed = false
local lastKnotInd = [0,0]

local bgColor = white
local knotColor = red
local knotVecColor = green
local lineColor = blue

local knotsArr = #()
local jsPos = [0,0]

-- User Interface
------------------------------------------

bitmap bmGraph "" width:dim height:dim
radioButtons rbMode "" labels:#("Draw","Edit") align:#center
radioButtons rbBezierMode "" labels:#("Bezier","Bezier Corner") align:#center
checkBox cbHideKnots "Hide Knots" align:#center
spinner spSteps "Steps:" range:[1,20,6] type:#integer align:#center fieldWidth:30
button bnClear "Clear" width:100

-- Functions
------------------------------------------

fn createBGMap =
(
bgMap = bitmap bmGraph.width bmGraph.height color:bgColor
)

fn round val =
(
if val - (floor val) < 0.5 then floor val else ceil val
)

fn lineLineIntersect pA pB pC pD =
(
pA = [pA.x,pA.y,0]
pB = [pB.x,pB.y,0]
pC = [pC.x,pC.y,0]
pD = [pD.x,pD.y,0]

local a = pB - pA
local b = pD - pC
local c = pC - pA
local cross1 = cross a b
local cross2 = cross c b
local n = pA + (a * ((dot cross2 cross1) / ((length cross1) ^ 2)))
[n.x,n.y]
)

fn getSteps p1 p2 =
(
struct s_neighbor (
pos,
dist
)

local neighborsPos = #([-1,-1],[0,-1],[1,-1],[-1,0],[1,0],[-1,1],[0,1],[1,1])
local neighbors = #()

for p in neighborsPos do (
local newNeighbor = s_neighbor p (distance p2 (p1 + p))
append neighbors newNeighbor
)

fn sortFn v1 v2 =
(
if v1.dist > v2.dist then 1
else if v1.dist < v2.dist then -1
else 0
)

qsort neighbors sortFn
#(neighbors[1].pos,neighbors[2].pos)
)

fn getStep p1 p2 pt steps =
(
local crossPt = lineLineIntersect p1 p2 (pt + steps[1]) (pt + steps[2])
local dist1 = distance crossPt (pt + steps[1])

if dist1 < 0.5 then (
pt + steps[1]
) else (
pt + steps[2]
)
)

fn drawDot pos rad bMap color =
(
for y = 0 to dim - 1 where y >= pos.y - rad and y <= pos.y + rad do (
for x = 0 to dim - 1 where distance pos [x,y] <= rad do (
setPixels bMap [x,y] #(color)
)
)
)

fn drawEdge p1 p2 color bMap =
(
local newPt = p1
local steps = getSteps p1 p2
local cnt = 0

setPixels bMap newPt #(color)

while newPt != p2 and cnt < dim * 2 do (
newPt = getStep p1 p2 newPt steps
setPixels bMap newPt #(color)
cnt += 1
)

bMap
)

fn drawKnots bmap =
(
if not cbHideKnots.state and knotsArr.count > 0 then (
for k = 1 to knotsArr.count do (
drawDot knotsArr[k][1] knotRad bmap knotVecColor
drawDot knotsArr[k][2] knotRad bmap knotColor
drawDot knotsArr[k][3] knotRad bmap knotVecColor
)
if mousePressed and rbMode.state == 2 then (
drawDot knotsArr[lastKnotInd.x][lastKnotInd.y] (knotRad * 1.5) bmap orange
)
)
bmap
)

fn updateGraph =
(
local newMap = copy bgMap

if knotsArr.count > 0 then (
for k = 1 to knotsArr.count do (
if knotsArr.count > 1 and k < knotsArr.count then (
local P0 = knotsArr[k][2]
local P1 = knotsArr[k][3]
local P2 = knotsArr[k + 1][1]
local P3 = knotsArr[k + 1][2]
local Pt0 = P0
for t = 0.0 to 1.0 by 1.0 / spSteps.value do (
local Pt = (1-t) ^ 3 * P0 + 3 * (1-t) ^ 2 * t * P1 + 3 * (1-t) * t ^ 2 * P2 + t ^ 3 * P3
Pt = [round Pt.x,round Pt.y]
newMap = drawEdge Pt0 Pt lineColor newMap
Pt0 = Pt
)
)
if not cbHideKnots.state then (
newMap = drawEdge knotsArr[k][1] knotsArr[k][2] knotVecColor newMap
newMap = drawEdge knotsArr[k][2] knotsArr[k][3] knotVecColor newMap
)
)
)

newMap = drawKnots newMap

bmGraph.bitmap = newMap
) -- end updateGraph fn

fn mPressed pos =
(
mousePressed = true
if rbMode.state == 1 then (
local newKnot = #()
append newKnot (pos - bmGraph.pos - [10,0])
append newKnot (pos - bmGraph.pos)
append newKnot (pos - bmGraph.pos + [10,0])
append knotsArr newKnot
updateGraph()
) else (
if knotsArr.count > 0 then (
local lastDist = dim * 2
for k = 1 to knotsArr.count do (
for i = 1 to 3 do (
local newDist = distance (pos - bmGraph.pos) knotsArr[k][i]
if newDist < lastDist then (
lastDist = newDist
lastKnotInd = [k,i]
)
)
)
)
)
)

fn updateJS pos =
(
if mousePressed do (
jsPos = pos - bmGraph.pos

if rbMode.state == 1 then (
knotsArr[knotsArr.count][2] = jsPos
knotsArr[knotsArr.count][1] = jsPos - [10,0]
knotsArr[knotsArr.count][3] = jsPos + [10,0]
) else (
if lastKnotInd.y == 2 then (
local oldPos = knotsArr[lastKnotInd.x][lastKnotInd.y]
knotsArr[lastKnotInd.x][1] += jsPos - oldPos
knotsArr[lastKnotInd.x][3] += jsPos - oldPos
) else (
if rbBezierMode.state == 1 then (
local otherHandleIndex = 4 - lastKnotInd.y
local otherHandleDist = distance knotsArr[lastKnotInd.x][2] knotsArr[lastKnotInd.x][otherHandleIndex]
local dir = normalize (jsPos - knotsArr[lastKnotInd.x][2])
local otherHandlePos = knotsArr[lastKnotInd.x][2] - dir * otherHandleDist
knotsArr[lastKnotInd.x][otherHandleIndex] = [round otherHandlePos.x,round otherHandlePos.y]
)
)
knotsArr[lastKnotInd.x][lastKnotInd.y] = jsPos
)
)

updateGraph()
)

fn clearVP =
(
knotsArr = #()
updateGraph()
rbMode.state = 1
)

fn openDialog =
(
createDialog bitmapTest width:(dim + 10) style:#(#style_titlebar, #style_border, #style_sysmenu,#style_resizing)
)

fn init =
(
createBGMap()
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on bitmapTest lbuttondown pos do mPressed pos
on bitmapTest lbuttonup pos do mousePressed = false
on bitmapTest mousemove pos do updateJS pos

on bnClear pressed do clearVP()
on cbHideKnots changed state do updateGraph()
on spSteps changed val do updateGraph()

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()


Draw a Spline using the bezier function and draw edge technique.
Edit (05.07.2008) - Added Bezier / Bezier Corner Handles radio button.

PEN
07-04-2008, 06:22 PM
Fantastic!

MatanH
07-06-2008, 03:05 PM
Test #10:
http://img371.imageshack.us/img371/1990/bitmaptest10rg4.jpg


try destroyDialog bitmapTest catch ()
rollout bitmapTest "Bitmap test 9"
(
-- Local Variable Declerations
------------------------------------------

local dim = 200
local knotRad = 2.4

local bgMap, newMap
local mousePressed = false
local lastKnotInd = [0,0]
local knotsArr = #()
local jsPos = [0,0]

local bgColor = white
local knotColor = red
local knotVecColor = green
local lineColor = blue

-- User Interface
------------------------------------------

bitmap bmGraph "" width:dim height:dim
radioButtons rbMode "" labels:#("Draw","Edit") align:#center
radioButtons rbBezierMode "" labels:#("Bezier","Bezier Corner") align:#center
spinner spThickness "Thickness:" range:[0.1,10,0.3] align:#center scale:0.1 fieldWidth:40
checkBox cbHideKnots "Hide Knots" align:#center
spinner spSteps "Steps:" range:[1,20,6] type:#integer align:#center fieldWidth:30
button bnClear "Clear" width:100

-- Functions
------------------------------------------

fn createBGMap =
(
bgMap = bitmap bmGraph.width bmGraph.height color:bgColor
)

fn round val =
(
if val - (floor val) < 0.5 then floor val else ceil val
)

fn lineLineIntersect pA pB pC pD =
(
pA = [pA.x,pA.y,0]
pB = [pB.x,pB.y,0]
pC = [pC.x,pC.y,0]
pD = [pD.x,pD.y,0]

local a = pB - pA
local b = pD - pC
local c = pC - pA
local cross1 = cross a b
local cross2 = cross c b
local n = pA + (a * ((dot cross2 cross1) / ((length cross1) ^ 2)))
[n.x,n.y]
)

fn getSteps p1 p2 =
(
struct s_neighbor (
pos,
dist
)

local neighborsPos = #([-1,-1],[0,-1],[1,-1],[-1,0],[1,0],[-1,1],[0,1],[1,1])
local neighbors = #()

for p in neighborsPos do (
local newNeighbor = s_neighbor p (distance p2 (p1 + p))
append neighbors newNeighbor
)

fn sortFn v1 v2 =
(
if v1.dist > v2.dist then 1
else if v1.dist < v2.dist then -1
else 0
)

qsort neighbors sortFn
#(neighbors[1].pos,neighbors[2].pos)
)

fn getStep p1 p2 pt steps =
(
local crossPt = lineLineIntersect p1 p2 (pt + steps[1]) (pt + steps[2])
local dist1 = distance crossPt (pt + steps[1])

if dist1 < 0.5 then (
pt + steps[1]
) else (
pt + steps[2]
)
)

fn drawDot pos rad color =
(
for y = 0 to rad do (
local colorArr = #()
for x = 0 to rad do (
local dist = sqrt (x ^ 2 + y ^ 2)
if dist <= rad then (
append colorArr color
insertItem color colorArr 1
)
)
setPixels newMap (pos - [colorArr.count / 2,y]) colorArr
setPixels newMap (pos - [colorArr.count / 2,- y]) colorArr
)
)

fn drawEdge p1 p2 color rad =
(
local newPt = p1
local steps = getSteps p1 p2
local cnt = 0

while newPt != p2 and cnt < dim * 2 do (
newPt = getStep p1 p2 newPt steps
drawDot newPt rad color
cnt += 1
)
)

fn drawKnots =
(
if not cbHideKnots.state and knotsArr.count > 0 then (
for k = 1 to knotsArr.count do (
drawDot knotsArr[k][1] knotRad knotVecColor
drawDot knotsArr[k][2] knotRad knotColor
drawDot knotsArr[k][3] knotRad knotVecColor
)
if mousePressed and rbMode.state == 2 then (
drawDot knotsArr[lastKnotInd.x][lastKnotInd.y] (knotRad * 1.5) orange
)
)
)

fn updateGraph =
(
newMap = copy bgMap

if knotsArr.count > 0 then (
for k = 1 to knotsArr.count do (
if knotsArr.count > 1 and k < knotsArr.count then (
local P0 = knotsArr[k][2]
local P1 = knotsArr[k][3]
local P2 = knotsArr[k + 1][1]
local P3 = knotsArr[k + 1][2]
local Pt0 = P0
for t = 0.0 to 1.0 by 1.0 / spSteps.value do (
local Pt = (1-t) ^ 3 * P0 + 3 * (1-t) ^ 2 * t * P1 + 3 * (1-t) * t ^ 2 * P2 + t ^ 3 * P3
Pt = [round Pt.x,round Pt.y]
local newRad = spThickness.value
drawEdge Pt0 Pt lineColor newRad
Pt0 = Pt
)
)
if not cbHideKnots.state then (
drawEdge knotsArr[k][1] knotsArr[k][2] knotVecColor 0.3
drawEdge knotsArr[k][2] knotsArr[k][3] knotVecColor 0.3
)
)
)

drawKnots()

bmGraph.bitmap = newMap
) -- end updateGraph fn

fn mPressed pos =
(
mousePressed = true
if rbMode.state == 1 then (
local newKnot = #()
append newKnot (pos - bmGraph.pos - [10,0])
append newKnot (pos - bmGraph.pos)
append newKnot (pos - bmGraph.pos + [10,0])
append knotsArr newKnot
updateGraph()
) else (
if knotsArr.count > 0 then (
local lastDist = dim * 2
for k = 1 to knotsArr.count do (
for i = 1 to 3 do (
local newDist = distance (pos - bmGraph.pos) knotsArr[k][i]
if newDist < lastDist then (
lastDist = newDist
lastKnotInd = [k,i]
)
)
)
)
)
)

fn updateJS pos =
(
if mousePressed do (
jsPos = pos - bmGraph.pos

if rbMode.state == 1 then (
knotsArr[knotsArr.count][2] = jsPos
knotsArr[knotsArr.count][1] = jsPos - [10,0]
knotsArr[knotsArr.count][3] = jsPos + [10,0]
) else (
if lastKnotInd.y == 2 then (
local oldPos = knotsArr[lastKnotInd.x][lastKnotInd.y]
knotsArr[lastKnotInd.x][1] += jsPos - oldPos
knotsArr[lastKnotInd.x][3] += jsPos - oldPos
) else (
if rbBezierMode.state == 1 then (
local otherHandleIndex = 4 - lastKnotInd.y
local otherHandleDist = distance knotsArr[lastKnotInd.x][2] knotsArr[lastKnotInd.x][otherHandleIndex]
local dir = normalize (jsPos - knotsArr[lastKnotInd.x][2])
local otherHandlePos = knotsArr[lastKnotInd.x][2] - dir * otherHandleDist
knotsArr[lastKnotInd.x][otherHandleIndex] = [round otherHandlePos.x,round otherHandlePos.y]
)
)
knotsArr[lastKnotInd.x][lastKnotInd.y] = jsPos
)
updateGraph()
)
)

fn clearVP =
(
knotsArr = #()
updateGraph()
rbMode.state = 1
)

fn openDialog =
(
createDialog bitmapTest width:(dim + 10) style:#(#style_titlebar, #style_border, #style_sysmenu,#style_resizing)
)

fn init =
(
createBGMap()
updateGraph()
)

fn done =
(
-- cleanup code
gc light:true
)

-- Event Handlers
------------------------------------------

on bitmapTest lbuttondown pos do mPressed pos
on bitmapTest lbuttonup pos do (
mousePressed = false
updateGraph()
)
on bitmapTest mousemove pos do updateJS pos

on bnClear pressed do clearVP()
on spThickness changed val do updateGraph()
on spPower changed val do updateGraph()
on cbHideKnots changed state do updateGraph()
on spSteps changed val do updateGraph()

on bitmapTest open do init()
on bitmapTest close do done()

) -- end of rollout

bitmapTest.openDialog()


An improved version of the 'Draw Dot' function.
Using this technique I was able to set the spline thickness as well.

kamel47
07-06-2008, 10:52 PM
TzMtN,

They are brilliant. Thank you very much to share them with us. I really like test #4. It is a Voronoy theory (Georgy Voronoy). A lot of the contemporary architecture is base on that theory.

Thanks

CGTalk Moderation
07-06-2008, 10:52 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.