I am using a struct in julia called "Droplet" which has fields for certain parameters of a particle such as x,y,z location, radius, and speed in the x,y,z directions. These are type specified as Float64 values:
module ParticlePoints
mutable struct Droplet
radius::Float64
osmolarity::Float64
x::Float64
y::Float64
z::Float64
xvelocity::Float64
yvelocity::Float64
zvelocity::Float64
xacceleration::Float64
yacceleration::Float64
zacceleration::Float64
searchradius::Float64
end # End the struct
I import the module into the ODE file and populate it each timestep. The droplet fields are given by indices from the vector u. Using view() doesn't work for the assignment because view gives me a sub-array. Is there any way to just get the float 64 value out of the view command, or a way to get the float 64 value out of the indices without consuming memory? Regardless, it is consuming a huge amount of memory for the following code, including large memory consumption for the line where I just specify droplet.searchradius as "10.":
for i in 1:dropletcount
# display(typeof(droplets[i]))
droplets[i].radius = getindex(u,i,1)::Float64
droplets[i].osmolarity = getindex(u, i+dropletcount)::Float64
droplets[i].x = getindex(u, Int(i+2*dropletcount))::Float64
droplets[i].y = getindex(u, Int(i+3*dropletcount))::Float64
droplets[i].z = getindex(u, Int(i+4*dropletcount))::Float64
droplets[i].xvelocity = getindex(u, Int(i+5*dropletcount))::Float64
droplets[i].yvelocity = getindex(u, Int(i+6*dropletcount))::Float64
droplets[i].zvelocity = getindex(u, Int(i+7*dropletcount))::Float64
droplets[i].searchradius = 10.
# display(typeof(droplets[i]))
end # End the for loop
The struct droplet is stored in a seperate module called particle points and is imported at the start of the module as such:
module MyDropletVectorJComponents
include("myparticlepoints.jl")
# include("myquadtreequery.jl")
using Interpolations
using LinearAlgebra
using RegionTrees
using StaticArrays: SVector
import RegionTrees: AbstractRefinery, needs_refinement, refine_data, adaptivesampling!
using .ParticlePoints
using DifferentialEquations
# The exports of this particular module
# export mydropfun!, myOvitoPrint!
export dropvecj!
I do not know why assigning a float64 value to this struct field which is type specified as float64 is causing such large memory allocations. The "droplets" you see is a vector that is called outside the ODE function and then imported in using the parameters p:
# Create the vector of droplets that will be fed into the main ODE
droplets::Vector{Droplet} = Droplet[] # Change this to a vector that needs to be imported in
for i in 1:outerdropletcount
droplet::Droplet = Droplet(0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.) #< ----- > THE FORMATTING FOR THE DROPLET
push!(droplets, droplet)
end # End the for loop
# typeof(droplets)
# display(droplets)
# Create the current residual that makes the osmolarity activate after the droplets settle
# normvelocity = zeros(1,1)
p = [outerdropletcount, k, L, γ, D, boolean_osm, dradii, dosmolarities, dvelocities, ρ, accelerationvec, droplets, xyzaccel, flux]
prob = ODEProblem(mydropfun!, ICvector, tspan, p)
sol = solve(prob, Tsit5(), reltol=1e-8, saveat = 0.1)
Additionally, it should be specified that the file containing the struct is in a separate file but in the same folder/directory as the ODE. Also the ODE and the function that lays out some of the parameters like the aforementioned "droplets" vector are in the same file. Any help would be deeply appreciated, and I am happy to provide more information on request.
EDIT: Here is a full MWE of the code. I reduced as much as I could. This should run:
module MyOvitoPrint
export myovitoprint
function myovitoprint(sol, dropletcount)
# This function will recast the solution of our ordinary differential equation into a printed file that can be visualized in ovito.
V = convert(Array,sol) # Convert the ODE solution into an array that can be worked on
V = dropdims(V, dims = 2) # Dimension 2 is a singleton and should be eliminated
totalsteps::Int64 = size(V,2)
# Create the empty string vector that will be used to create the printout
myprintout = Array{String}(undef, (5+dropletcount)*totalsteps, 1)
# Initialize the timestep
timestep::Float64 = 0.
stepindex::Int64 = 1
for i in 1: 5+dropletcount: (5+dropletcount)*totalsteps
myprintout[i] = "ITEM: TIMESTEP"
myprintout[i+1] = "$timestep"
myprintout[i+2] = "ITEM: NUMBER OF ATOMS"
myprintout[i+3] = "$dropletcount"
myprintout[i+4] = "ITEM: ATOMS x y z radius osmolarity"
for j in 1:dropletcount
# myprintout[i+4+j] = "$x $y $z $radius $osmolarity"
x = V[2*dropletcount+j, stepindex]
y = V[3*dropletcount+j, stepindex]
z = V[4*dropletcount+j, stepindex]
radius = V[j, stepindex]
osmolarity = V[dropletcount + j, stepindex]
myprintout[i+4+j] = "$x $y $z $radius $(osmolarity)"
end # End sub-loop for droplets
stepindex += 1
timestep += 0.1
end # End loop
# Now print the .xyz file
outfile = "E:/Research Scripts and Functions/OVITO_Files/visual_model.ovito"
f = open(outfile, "w")
for i in eachindex(myprintout)
println(f, myprintout[i])
end
close(f)
end # Function end
end # End module MyOvitoPrint
module DropletFields
export Droplet, TreeCellData
mutable struct Droplet
radius::Float64
osmolarity::Float64
x::Float64
y::Float64
z::Float64
xvelocity::Float64
yvelocity::Float64
zvelocity::Float64
xacceleration::Float64
yacceleration::Float64
zacceleration::Float64
searchradius::Float64
end # End the struct
mutable struct TreeCellData
list::Vector{Droplet}
endindex::Int64
end # End the struct
end # End module DropletFields
module NateDropOde
# Imports -----
using ..DropletFields
using RegionTrees
using StaticArrays: SVector
import RegionTrees: AbstractRefinery, needs_refinement, refine_data, adaptivesampling!
using DifferentialEquations
# Exports -----
export natedropode
function natedropode(du, u, p, t)
# Put in the parameters that are needed, very important line of code: #=========================================================================
dropletcount, k, L, γ, D, boolean_osm, dradii, dosmolarities, dvelocities, ρ, accelerationvec, droplets, xyzaccel, flux = p;
maxradius = 0.
dropletcount = dropletcount
maxradius = maximum(view(u,1:dropletcount))
normvelocity = 0.
ℷ = abs.(view(u, 5*dropletcount+1:8*dropletcount))
ℸ = view(u, 5*dropletcount+1:8*dropletcount)
Ζ = view(u, 5*dropletcount+1:8*dropletcount)
broadcast(abs, ℸ)
ℶ = view(u, 5*dropletcount+1:8*dropletcount).^2
ℵ= sum(ℶ)
ℵ = sqrt(ℵ)
if (t > 0.1 && normvelocity/dropletcount <= 1e-4)
boolean_osm[1] = 1.0
end # End conditional
for i in 1:dropletcount
# display(typeof(droplets[i]))
droplets[i].radius = getindex(u,i,1)::Float64
droplets[i].osmolarity = getindex(u, i+dropletcount)::Float64
droplets[i].x = getindex(u, Int(i+2*dropletcount))::Float64
droplets[i].y = getindex(u, Int(i+3*dropletcount))::Float64
droplets[i].z = getindex(u, Int(i+4*dropletcount))::Float64
droplets[i].xvelocity = getindex(u, Int(i+5*dropletcount))::Float64
droplets[i].yvelocity = getindex(u, Int(i+6*dropletcount))::Float64
droplets[i].zvelocity = getindex(u, Int(i+7*dropletcount))::Float64
droplets[i].searchradius = 10.
# display(typeof(droplets[i]))
end # End the for loop
xvec = view(u, Int(2*dropletcount+1):Int(3*dropletcount))
xorigin::Float64 = minimum(xvec) - 0.1
yvec = view(u, Int(3*dropletcount+1):Int(4*dropletcount))
yorigin::Float64 = minimum(yvec) - 0.1
zvec = view(u, Int(4*dropletcount+1):Int(5*dropletcount))
zorigin::Float64 = minimum(zvec) - 0.1
xwidth::Float64 = (maximum(xvec) - xorigin) * 1.1
ywidth::Float64 = (maximum(yvec) - yorigin) * 1.1
zwidth::Float64 = (maximum(zvec) - zorigin) * 1.1
r = MyRefinery(0.0)
asaf = TreeCellData(droplets, dropletcount)
root::Cell = Cell(SVector(xorigin, yorigin, zorigin), SVector(xwidth, ywidth, zwidth), asaf)
myquadtree = adaptivesampling!(root, r)
for i in 1:dropletcount
fill!(xyzaccel, 0.)
flux[1] = 0.
jvec = 0.
query(myquadtree, droplets[i], xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
myvolume = 4/3 * pi * droplets[i].radius^3
dvelocities[i] = (xyzaccel[1] - γ * droplets[i].xvelocity) / (ρ * myvolume)
dvelocities[i+dropletcount] = (xyzaccel[2] - γ * droplets[i].yvelocity) / (ρ * myvolume)
dvelocities[i+2*dropletcount] = (xyzaccel[3] - γ * droplets[i].zvelocity) / (ρ * myvolume)
mymoles = droplets[i].osmolarity * myvolume
myvolume = myvolume + flux[1]
dradii[i] = (3/(4*pi) * myvolume)^(1/3) - droplets[i].radius
dosmolarities[i] = mymoles/myvolume - droplets[i].osmolarity
end # End the for loop
du[1:dropletcount] = dradii
du[dropletcount+1 : 2*dropletcount] = dosmolarities
du[2*dropletcount+1 : 5*dropletcount] = view(u, 5*dropletcount+1:8*dropletcount)
du[5*dropletcount+1 : 8*dropletcount] = dvelocities
end # End the main function
struct MyRefinery <: AbstractRefinery
tolerance::Int64
end # End struct
function needs_refinement(r::MyRefinery, cell)
myindex::Int64 = 0
for i in 1:cell.data.endindex
# Adress an edge case where the point sits directly in top of the line of division
edgecorrectionx = 0.
edgecorrectiony = 0.
edgecorrectionz = 0.
edgecasex1::Bool = cell.data.list[i].x == cell.boundary.origin[1]
edgecasex2::Bool = cell.data.list[i].x == cell.boundary.origin[1] + cell.boundary.widths[1]
edgecasey1::Bool = cell.data.list[i].y == cell.boundary.origin[2]
edgecasey2::Bool = cell.data.list[i].y == cell.boundary.origin[2] + cell.boundary.widths[2]
edgecasez1::Bool = cell.data.list[i].z == cell.boundary.origin[3]
edgecasez2::Bool = cell.data.list[i].z == cell.boundary.origin[3] + cell.boundary.widths[3]
edgecasex1 ? edgecorrectionx::Float64 += (cell.boundary.widths[1]+10)^(-1/cell.boundary.widths[1]) : nothing
edgecasex2 ? edgecorrectionx::Float64 += (cell.boundary.widths[1]+10)^(-1/cell.boundary.widths[1]) : nothing
edgecasey1 ? edgecorrectiony::Float64 += (cell.boundary.widths[2]+10)^(-1/cell.boundary.widths[2]) : nothing
edgecasey2 ? edgecorrectiony::Float64 += (cell.boundary.widths[2]+10)^(-1/cell.boundary.widths[2]) : nothing
edgecasez1 ? edgecorrectionz::Float64 += (cell.boundary.widths[3]+10)^(-1/cell.boundary.widths[3]) : nothing
edgecasez2 ? edgecorrectionz::Float64 += (cell.boundary.widths[3]+10)^(-1/cell.boundary.widths[3]) : nothing
case1 = cell.boundary.origin[1] < cell.data.list[i].x + edgecorrectionx < cell.boundary.origin[1] + cell.boundary.widths[1]
case2 = cell.boundary.origin[2] < cell.data.list[i].y + edgecorrectiony < cell.boundary.origin[2] + cell.boundary.widths[2]
case3 = cell.boundary.origin[3] < cell.data.list[i].z + edgecorrectionz < cell.boundary.origin[3] + cell.boundary.widths[3]
if case1 && case2 && case3 == true
myindex += Int(1)
cell.data.list[myindex] = cell.data.list[i]
end # end conditional
end # End the for loop
cell.data.endindex = myindex
myindex == r.tolerance
end # End function
function refine_data(r::MyRefinery, cell::Cell, indices)
cell.data
end # End function
function intersects(cell, mydroplet)
case1x = mydroplet.x - mydroplet.searchradius + 2 * mydroplet.searchradius <= cell.boundary.origin[1]
case2x = mydroplet.x - mydroplet.searchradius >= cell.boundary.origin[1] + cell.boundary.widths[1]
casex = case1x || case2x
case1y = mydroplet.y - mydroplet.searchradius + 2 * mydroplet.searchradius <= cell.boundary.origin[2]
case2y = mydroplet.y - mydroplet.searchradius >= cell.boundary.origin[2] + cell.boundary.widths[2]
casey = case1y || case2y
case1z = mydroplet.z - mydroplet.searchradius + 2 * mydroplet.searchradius <= cell.boundary.origin[3]
case2z = mydroplet.z - mydroplet.searchradius >= cell.boundary.origin[3] + cell.boundary.widths[3]
casez = case1z || case2z
!(casex || casey || casez)
end # End function
function contains(point, mydroplet)
xdist = mydroplet.x - point.x
ydist = mydroplet.y - point.y
zdist = mydroplet.z - point.z
sqrt(xdist^2 + ydist^2 + zdist^2) <= mydroplet.radius+point.radius && (sqrt(xdist^2 + ydist^2 + zdist^2) != 0)
end # End function
function query(cell, mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
if intersects(cell, mydroplet) == false
return nothing
else
if isleaf(cell)
for i in 1 : length(cell.data.list)
contains(cell.data.list[i], mydroplet) ? xyzaccel .+= mygetaccelerationandflux(cell.data.list[i], mydroplet, L, k, boolean_osm, D, jvec, accelerationvec)[1] : nothing
contains(cell.data.list[i], mydroplet) ? flux .+= mygetaccelerationandflux(cell.data.list[i], mydroplet, L, k, boolean_osm, D, jvec, accelerationvec)[2] : nothing
end # End the for loop
end # End the conditional
if !isleaf(cell)
query(cell[1,1,1], mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
query(cell[1,1,2], mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
query(cell[1,2,1], mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
query(cell[1,2,2], mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
query(cell[2,2,2], mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
query(cell[2,2,1], mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
query(cell[2,1,2], mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
query(cell[2,1,1], mydroplet, xyzaccel, flux, L, k, boolean_osm, D, jvec, accelerationvec)
end # End conditional
end # End conditional
# Perform the final calculations
return xyzaccel
return flux
end # End function
function mygetaccelerationandflux(fardrop::Droplet, neardrop::Droplet, L, k, boolean_osm, D, jvec, accelerationvec)#::Matrix{Float64}
xdist = fardrop.x - neardrop.x
ydist = fardrop.y - neardrop.y
zdist = fardrop.z - neardrop.z
directionx = xdist/sqrt(xdist^2 + ydist^2 + zdist^2)
directiony = ydist/sqrt(xdist^2 + ydist^2 + zdist^2)
directionz = zdist/sqrt(xdist^2 + ydist^2 + zdist^2)
mybilayerdist = L * (neardrop.radius + fardrop.radius)
accelerationvec[1] = directionx * -k * (abs(mybilayerdist * directionx) - abs(xdist))
accelerationvec[2] = directiony * -k * (abs(mybilayerdist * directiony) - abs(ydist))
accelerationvec[3] = directionz * -k * (abs(mybilayerdist * directionz) - abs(zdist))
# =================== The osmolarity part of the code ================================= #
intersectcase1 = neardrop.radius + fardrop.radius - sqrt(xdist^2 + ydist^2 + zdist^2) >= 0
intersectcase2 = sqrt(xdist^2 + ydist^2 + zdist^2) + neardrop.radius - fardrop.radius >= 0
intersectcase3 = sqrt(xdist^2 + ydist^2 + zdist^2) + fardrop.radius - neardrop.radius >= 0
# jvec = 0
if boolean_osm[1] >= 1.0
if (intersectcase1 && intersectcase2 && intersectcase3)
component1 = (sqrt(xdist^2 + ydist^2 + zdist^2)^2 - fardrop.radius^2 + neardrop.radius^2)^2
component2 = 4 * sqrt(xdist^2 + ydist^2 + zdist^2)^2 * neardrop.radius^2
component3 = component2 - component1
component4 = 1/(2*sqrt(xdist^2 + ydist^2 + zdist^2)) * sqrt(component3)
mycircular_area = pi * component4^2
osmdiff = neardrop.osmolarity - fardrop.osmolarity
jvec = D * mycircular_area * osmdiff
end # End the conditional
end # End the conditional
return accelerationvec, jvec
end # End function
end # End module
module NateOdeManager
using ..NateDropOde
using ..DropletFields
using ..MyOvitoPrint
using DifferentialEquations
ICmatrix = [3 0.1 3 0 0 0 0 0; 3 1. 9 0 0 0 0 0; 3 0.4 14 0 0 0 0 0]
ρ = 0.2 # The density of the droplet, used to calculate the mass of each droplet within the system as a function of radius. To wit Eqn = mass(rho,volume(radius))
k = 1000. # The spring force between each droplet
L = 0.8 # The natural length proportional to the radii that droplets will settle at
γ = 30. # The simplified version of both fluid response and spring damping in the system
timeend = 250. # The time at which the ODE will end
D = 2. *10^-2 # The rate at which diffusion will happen in the system
boolean_osm = [0.0] # The "on" switch for when the diffusion in the sytem will activate
tstepextract = Int(timeend * 10)
ICvector = reshape(ICmatrix, :, 1);
dropletcount = size(ICmatrix,1)
tspan = (0.0, timeend);
dradii = zeros(dropletcount,1)
dosmolarities = zeros(dropletcount,1)
dvelocities = zeros(3*dropletcount,1)
accelerationvec = zeros(3,1)
xyzaccel = zeros(3,1)
flux = zeros(1,1)
# Create the vector of droplets that will be fed into the main ODE
droplets = Droplet[] # Change this to a vector that needs to be imported in
for i in 1:dropletcount
droplet = Droplet(0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.) #< ----- > THE FORMATTING FOR THE DROPLET
push!(droplets, droplet)
end # End the for loop
p = [dropletcount, k, L, γ, D, boolean_osm, dradii, dosmolarities, dvelocities, ρ, accelerationvec, droplets, xyzaccel, flux]
prob = ODEProblem(natedropode, ICvector, tspan, p)
sol = solve(prob, Tsit5(),saveat = 0.1, dt = 0.1)
myovitoprint(sol, dropletcount)
end # End module NateOdeManager
I need to initialize a 3D tensor with an index-dependent function in torch7, i.e.
func = function(i,j,k) --i, j is the index of an element in the tensor
return i*j*k --do operations within func which're dependent of i, j
end
then I initialize a 3D tensor A like this:
for i=1,A:size(1) do
for j=1,A:size(2) do
for k=1,A:size(3) do
A[{i,j,k}] = func(i,j,k)
end
end
end
But this code runs very slow, and I found it takes up 92% of total running time. Are there any more efficient ways to initialize a 3D tensor in torch7?
See the documentation for the Tensor:apply
These functions apply a function to each element of the tensor on
which the method is called (self). These methods are much faster than
using a for loop in Lua.
The example in the docs initializes a 2D array based on its index i (in memory). Below is an extended example for 3 dimensions and below that one for N-D tensors. Using the apply method is much, much faster on my machine:
require 'torch'
A = torch.Tensor(100, 100, 1000)
B = torch.Tensor(100, 100, 1000)
function func(i,j,k)
return i*j*k
end
t = os.clock()
for i=1,A:size(1) do
for j=1,A:size(2) do
for k=1,A:size(3) do
A[{i, j, k}] = i * j * k
end
end
end
print("Original time:", os.difftime(os.clock(), t))
t = os.clock()
function forindices(A, func)
local i = 1
local j = 1
local k = 0
local d3 = A:size(3)
local d2 = A:size(2)
return function()
k = k + 1
if k > d3 then
k = 1
j = j + 1
if j > d2 then
j = 1
i = i + 1
end
end
return func(i, j, k)
end
end
B:apply(forindices(A, func))
print("Apply method:", os.difftime(os.clock(), t))
EDIT
This will work for any Tensor object:
function tabulate(A, f)
local idx = {}
local ndims = A:dim()
local dim = A:size()
idx[ndims] = 0
for i=1, (ndims - 1) do
idx[i] = 1
end
return A:apply(function()
for i=ndims, 0, -1 do
idx[i] = idx[i] + 1
if idx[i] <= dim[i] then
break
end
idx[i] = 1
end
return f(unpack(idx))
end)
end
-- usage for 3D case.
tabulate(A, function(i, j, k) return i * j * k end)
So I recently purchased the draw library on Touch Lua! I've started trying to make a simple Tic Tac Toe game. I'm using a simple setup they used to detect clicks on the NumPad default program, so the buttons should work.
The problem is that when you tap a square, the O fills into seemingly-random squares, sometimes more than 1, up to 4+ squares may get filled.
I suspect the problem is the function Picked, which sets the title to X/O and then updates the board.
local Turn = nil
local Move = "O"
local Mode = nil
::ModePick::
print("1 player mode? (y/n)")
local plrs = io.read()
if plrs == "y" then
Mode = 1
goto TurnChoice
elseif plrs == "n" then
Mode = 2
goto Game
else
goto ModePick
end
::TurnChoice::
print("Would you like to go first? (Be O) (y/n)")
do
local pick = io.read()
if pick == "y" then
Turn = 1
elseif pick == "n" then
Turn = 2
else
goto TurnChoice
end
end
::Game::
local Buttons = {}
draw.setscreen(1)
draw.settitle("Tic Tac Toe")
draw.clear()
width, height = draw.getport()
function Picked(b)
for i,v in pairs(Buttons) do
if v == b then
b.title = Move
UpdateBoard()
end
end
--Fill in X/O details
--Detect if there's a tic/tac/toe
--Set winning screen
if Move == "O" then
--Compute Move (1 player)
--Move = "X" (2 player)
else
Move = "O"
end
end
function DrawButton(b)
draw.setfont('Helvetica', 50)
draw.setlinestyle(2, 'butt')
local x1, y1 = b.x, b.y
local x2, y2 = x1+b.width, y1+b.height
draw.rect(x1, y1, x2, y2, b.color)
local w, h = draw.stringsize(b.title)
local x = b.x + (b.width - w)/2
local y = b.y + (b.height - h)/2
draw.string(b.title, x, y, draw.black)
return b
end
function Button(x, y, x2, y2, title, color, action)
local action = action or function() end
local button = {x = x, y = y, width = x2, height = y2, color = color, title = title, action = action}
table.insert(Buttons, button)
return button
end
function LookUpButton(x, y)
for i = 1, #Buttons do
local b = Buttons[i]
if x > b.x and x < b.x+b.width and y > b.y and y < b.y+b.height then
return b
end
end
return nil
end
function TouchBegan(x, y)
local b = LookUpButton(x, y)
if b then
b.action(b)
end
end
function TouchMoved(x, y)
end
function TouchEnded(x, y)
end
draw.tracktouches(TouchBegan, TouchMoved, TouchEnded)
function CreateButton(x,y,x2,y2,txt,col,func)
return DrawButton(Button(x, y, x2, y2, txt, col, func))
end
function UpdateBoard()
draw.clear()
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, Buttons[i + ii].title, draw.blue, Picked)
end
end
end
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, "", draw.blue, Picked)
end
end
while true do
draw.doevents()
sleep(1)
end
Note: Sorry if the indention came out wrong, I pasted all this code in on my iPod, so I had to manually put in 4 spaces starting each line.
If anybody could help me out with this small setback I have, I'd love the help, if there's anything I'm missing I'd gladly edit it in just reply in the comments :D
EDIT: I've modified some of the code to fix how the table keeps getting new buttons, this is the code I have now, same problem, buttons are added in wrong place (and getting removed now):
function Button(x, y, x2, y2, title, color, action, prev)
local action = action or function() end
local button = {x = x, y = y, width = x2, height = y2, color = color, title = title, action = action}
if prev then
for i,v in pairs(Buttons) do
if v == prev then
table.remove(Buttons, i)
end
end
end
table.insert(Buttons, button)
return button
end
function CreateButton(x,y,x2,y2,txt,col,func, prev)
return DrawButton(Button(x, y, x2, y2, txt, col, func, prev))
end
function UpdateBoard()
draw.clear()
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, Buttons[i + ii].title, draw.blue, Picked, Buttons[i + ii])
end
end
end
EDIT: Thanks to Etan I've fixed UpdateBoard, squares are still random:
function UpdateBoard()
draw.clear()
local n = 1
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, Buttons[n].title, draw.blue, Picked, Buttons[n])
n = n + 1
end
end
end
It's been a while since I've got around to post the finished code, but this is what it looks like:
function UpdateBoard(ended)
local ended = ended or false
local Act = nil
if ended == true then
Act = function() end
else
Act = Picked
end
draw.clear()
local Buttons2 = {}
for i,v in pairs(Buttons) do
Buttons2[i] = v
end
Buttons = {}
local n = 1
for i = 1,3 do
for ii = 1,3 do
CreateButton(100 * (ii - 1) + 7.5, 100 * (i - 1) + 75, 100, 100, Buttons2[n].title, draw.blue, Act, Buttons2[n], i, ii)
n = n + 1
end
end
OpenButtons = {}
ClosedButtons = {}
for i,v in pairs(Buttons) do
if v.title == "" then
table.insert(OpenButtons, v)
else
table.insert(ClosedButtons, v)
end
end
end
It may seem a bit complicated for the question, but this is the code after multiple other things.
The main difference you should note here, is that it's recreating the table of buttons, so it does not recount new buttons, and it uses n to count up, instead of using i and ii.
How I can change the colors from this:
into this:
I generated the output image using Gimp with the input image as layer one, and the background color from the image as layer two, in the Layers panel I selected the mode "colors"
I want preserve the background color, but want the colors be shades of brown.
Any ideas to do this with ChunkyPNG? Or should I use ImageMagick with color lookup tables?
Thanks for your ideas.
I found the one from Linuxios the most helpful Gimp layer modes
require "json"
require "httpclient"
require "chunky_png"
module ChunkyPNG::Color
def h(value)
r,g,b = r(value).to_f / MAX, g(value).to_f / MAX, b(value).to_f / MAX
min, max = [r,g,b].minmax
return 0 if max == min
result = case max
when r then (g - b) / (max - min) + (g < b ? 6 : 0)
when g then (b - r) / (max - min) + 2
when b then (r - g) / (max - min) + 4
end
result * 60
end
def s(value)
min, max = [r(value), g(value), b(value)].minmax.map { |value| value.to_f / MAX }
max == 0 ? 0 : (max - min) / max
end
def v(value)
[r(value), g(value), b(value)].max.to_f / MAX
end
def hsv(h, s, v)
h = h.to_f / 360
i = (h * 6).floor
f = h * 6 - i
p = v * (1 - s)
q = v * (1 - f * s)
t = v * (1 - (1 - f) * s)
case i % 6
when 0 then r, g, b = v, t, p
when 1 then r, g, b = q, v, p
when 2 then r, g, b = p, v, t
when 3 then r, g, b = p, q, v
when 4 then r, g, b = t, p, v
when 5 then r, g, b = v, p, q
end
rgb *[r,g,b].map {|value| (value * 255).round }
end
end
module CoderWall
module_function
def badges(username)
url = URI.escape("https://coderwall.com/#{username}.json")
response = HTTPClient.get(url)
json = JSON.parse(response.body)
urls = json['badges'].map {|b| b['badge']}
brown = ChunkyPNG::Color.from_hex("#bf8a30")
hue = ChunkyPNG::Color.h(brown)
saturation = ChunkyPNG::Color.s(brown)
value = ChunkyPNG::Color.v(brown)
urls.each do |url|
matches = url.match /(\w+)\-/
response = HTTPClient.get(url)
filename = "./tmp/coderwall/"+matches[1]+".png"
File.open(filename,"w") {|f| f.write(response.body)}
image = ChunkyPNG::Image.from_file(filename)
image.pixels.map! do |pixel|
v = ChunkyPNG::Color.v(pixel)
unless ChunkyPNG::Color.a(pixel) > 0
v = value
end
ChunkyPNG::Color.hsv(hue,saturation, v)
end
image.save(filename.gsub(/\.png/,"_brown.png"), :fast_rgba)
end
end
end
badges = CoderWall.badges("astropanic")
That above code consists from some snippets found around the web.
Here is the result: Stop doing new year resolutions. Make the change now !