Implementation of a physics based Wordcloud. For the word count I used a Luna script (because it can ask the user for an input string, where one can use paste), resulting in a table in the data tab. Words are laid out next to each other until the screen is full. Then the physics engine is turned on to let gravity do its thing. Tapping on a word allows you to drag it to another position. Tapping anywhere else flips the gravity direction.
The most difficult part was how to get the outline of the words. Also, the setup is so computationally intensive that it needs to be done outside of the setup.
-- Wordcloud
-- Herwig Van Marck
-- Use this function to perform your initial setup
function setup()
print("Wordcloud\
Tap on a word to move it\
Tap anywhere else to flip gravity")
iparameter("showOutlines",0,1,0)
wall=physics.body(CHAIN,true,vec2(0,0),vec2(WIDTH,0),vec2(WIDTH,HEIGHT),vec2(0,HEIGHT))
wcl=WordCloud(tbl)
end
function touched(touch)
if wcl:touched(touch)==false then
if (touch.state==BEGAN) then
physics.gravity(-physics.gravity())
end
end
end
function drawObj(body)
pushMatrix()
translate(body.x, body.y)
rotate(body.angle)
if body.type == STATIC then
stroke(255,255,255,255)
elseif body.type == DYNAMIC then
stroke(150,255,150,255)
elseif body.type == KINEMATIC then
stroke(150,150,255,255)
end
if body.shapeType == POLYGON then
strokeWidth(5.0)
local points = body.points
for j = 1,#points do
a = points[j]
b = points[(j % #points)+1]
line(a.x, a.y, b.x, b.y)
end
elseif body.shapeType == CHAIN or body.shapeType == EDGE then
strokeWidth(5.0)
local points = body.points
local range = #points - 1
if (true) then
range = #points
end
for j = 1, range do
a = points[j]
b = points[j % #points +1]
line(a.x, a.y, b.x, b.y)
end
elseif body.shapeType == CIRCLE then
strokeWidth(5.0)
line(0,0,body.radius-3,0)
strokeWidth(2.5)
ellipse(0,0,body.radius*2)
end
popMatrix()
end
function draw()
background(0, 0, 0, 255)
wcl:draw()
drawObj(wall)
end
tbl={}
tbl["codea"]=5
tbl["anything"]=1
tbl["lets"]=1
tbl["create"]=1
tbl["games"]=1
tbl["simulations"]=1
tbl["any"]=1
tbl["idea"]=1
tbl["have"]=1
tbl["turn"]=1
tbl["thoughts"]=1
tbl["into"]=1
tbl["interactive"]=1
tbl["creations"]=1
tbl["make"]=2
tbl["of"]=1
tbl["features"]=1
tbl["like"]=1
tbl["multi-touch"]=1
tbl["accelerometer"]=1
tbl["we"]=1
tbl["think"]=1
tbl["most"]=1
tbl["beautiful"]=1
tbl["editor"]=1
tbl["ll"]=1
tbl["use"]=2
tbl["s"]=1
tbl["easy"]=1
tbl["designed"]=1
tbl["touch"]=1
tbl["your"]=3
tbl["code"]=2
tbl["to"]=2
tbl["change"]=1
tbl["number"]=1
tbl["just"]=2
tbl["tap"]=1
tbl["and"]=4
tbl["drag"]=1
tbl["it"]=2
tbl["how"]=1
tbl["about"]=2
tbl["color"]=1
tbl["you"]=6
tbl["or"]=2
tbl["an"]=1
tbl["image"]=1
tbl["tapping"]=1
tbl["will"]=1
tbl["bring"]=1
tbl["up"]=1
tbl["visual"]=2
tbl["editors"]=1
tbl["let"]=2
tbl["choose"]=1
tbl["exactly"]=1
tbl["what"]=1
tbl["want"]=2
tbl["is"]=3
tbl["built"]=1
tbl["lua"]=1
tbl["programming"]=1
tbl["simple"]=1
tbl["elegant"]=1
tbl["language"]=2
tbl["that"]=3
tbl["doesn"]=1
tbl["t"]=1
tbl["rely"]=1
tbl["too"]=1
tbl["much"]=1
tbl["on"]=3
tbl["symbols"]=1
tbl["a"]=4
tbl["perfect"]=1
tbl["match"]=1
tbl["for"]=2
tbl["ipad"]=4
tbl["join"]=1
tbl["the"]=4
tbl["forums"]=1
PhysicsWord = class()
function PhysicsWord:init(str,x,y,fnt,fsize)
self.str=str
self.fnt=fnt
self.fsize=fsize
self.bounce=nil
local xofs=0;
local tblb={}
local tblt={}
pushStyle()
font(self.fnt)
fontSize(self.fsize)
for i=1,string.len(self.str) do
local chr=string.sub(self.str,i,i)
local xmin,ymin,xmax,ymax=self:boundingBox(chr)
table.insert(tblb,vec2(xofs+xmin,ymin))
table.insert(tblb,vec2(xofs+xmax,ymin))
table.insert(tblt,1,vec2(xofs+xmin,ymax))
table.insert(tblt,1,vec2(xofs+xmax,ymax))
xofs = xofs + textSize(chr)
end
for i=1,#tblt do
table.insert(tblb,tblt[i])
end
popStyle()
self.word = physics.body(POLYGON,unpack(tblb))
self.word.x=x
self.word.y=y
self.word.restitution=0.60
self.word.gravityScale=0.2
self.word.sleepingAllowed=false
end
function PhysicsWord:boundingBox(chr)
pushMatrix()
pushStyle()
font(self.fnt)
fontSize(self.fsize)
local w,h=textSize(chr)
local img=image(w,h)
setContext(img)
textMode(CORNER)
fill(255, 255, 255, 255)
text(chr,0,0)
setContext()
local xmin,ymin,xmax,ymax=w,h,0,0
for x=1,w do
for y=1,h do
local r,g,b,a=img:get(x,y)
if (a>0) then
if (xmin>=x) then
xmin=x
end
if (xmax<=x) then
xmax=x
end
if (ymin>=y) then
ymin=y
end
if (ymax<=y) then
ymax=y
end
end
end
end
--workaround for text bug
setContext(img)
textMode(CORNER)
text("adsrfetgy",0,0)
setContext()
popStyle()
popMatrix()
return xmin,ymin,xmax,ymax
end
function PhysicsWord:draw()
local body=self.word
pushMatrix()
pushStyle()
translate(body.x, body.y)
rotate(body.angle)
stroke(150,255,150,255)
strokeWidth(5.0)
if (showOutlines==1) then
local points = body.points
for j = 1,#points do
a = points[j]
b = points[(j % #points)+1]
line(a.x, a.y, b.x, b.y)
end
end
fontSize(self.fsize)
font(self.fnt)
textMode(CORNER)
fill(255, 255, 255, 255)
text(self.str,0,0)
popStyle()
popMatrix()
if (nil) then -- waiting for inertia support
if (math.abs(body.angle)>80) then
if (self.bounce==nil) then
print(body.mass)
body:applyTorque(-120*body.angularVelocity*body.restitution*body.inertia)
self.bounce=true
end
else
self.bounce=nil
end
end
end
function PhysicsWord:touched(touch)
local touchPoint=vec2(touch.x,touch.y)
return self.word:testPoint(touchPoint)
end