diff options
Diffstat (limited to 'common/coords.lua')
-rw-r--r-- | common/coords.lua | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/common/coords.lua b/common/coords.lua new file mode 100644 index 0000000..1bb9154 --- /dev/null +++ b/common/coords.lua @@ -0,0 +1,90 @@ +-- Hex: q,r,s. invariant that q+r+s=0 +-- add, subtract +-- constructor takes 3 positions and rounds to closest hex centre. + +-- round to nearest int, rounding .5 away from 0. +local function round(x) + if x<0 then + return math.ceil(x-0.5) + else + return math.floor(x+0.5) + end +end + +local Pos, Hex + +local SR3 = math.sqrt(3) + +Hex={} +Hex.__index = Hex +function Hex.make(q,r,s) + s=s or -q-r + assert(q+r+s==0,"hex coord doesn't meet invariant") + return setmetatable({q=q,r=r,s=s},Hex) +end +function Hex.round(self) + -- return a new Hex rounded to integer coordinates + local fq,fr,fs = self.q,self.r,self.s + -- round all to nearest integer + -- find which was changed the most, reset that one to be coherent with the other two. + local abs = math.abs + + local rq,rr,rs = round(fq),round(fr),round(fs) + local dq,dr,ds = abs(fq-rq), abs(fr-rr), abs(fs-rs) + + if dq>dr and dq>ds then + rq = -rr-rs + elseif dr>ds then + rr = -rq-rs + else + rs = -rq-rr + end + + return Hex.make(rq,rr,rs) +end + +function Hex.to_pos(self) + local x = self.q*SR3 + self.r*(SR3/2) + local y = self.r*(3/2) + return Pos.make(x,y) +end + +function Hex.__add(self,other) return Hex.make(self.q+other.q, self.r+other.r, self.s+other.s) end +function Hex.__sub(self,other) return Hex.make(self.q-other.q, self.r-other.r, self.s-other.s) end +function Hex.__tostring(self) return string.format("H(%.2f,%.2f)",self.q,self.r) end + + +Pos = {} +Pos.__index=Pos +function Pos.make(x,y) + return setmetatable({x=x,y=y},Pos) +end +function Pos.__add(self,other) return Pos.make(self.x+other.x,self.y+other.y) end +function Pos.__sub(self,other) return Pos.make(self.x-other.x,self.y-other.y) end +function Pos.__mul(a,b) + if type(a) == "number" then + return Pos.make(a*b.x,a*b.y) + elseif type(b) == "number" then + return Pos.make(a.x*b,a.y*b) + else + error("can only multiply Pos by scalar") + end +end +function Pos.__div(a,b) + assert(type(b) == "number","can only divide Pos by scalar, and can't divide scalar by Pos") + return a*(1/b) +end +function Pos.lensq(self) return self.x^2 + self.y^2 end +function Pos.len(self) return math.sqrt(self:lensq()) end +function Pos.to_hex(self) + local q = self.x*(SR3/3) - self.y*(1/3) + local r = (2/3)*self.y + return Hex.make(q,r,-q-r) +end +function Pos.__tostring(self) return string.format("(%.2f,%.2f)",self.x,self.y) end + + + +return {Hex=Hex,Pos=Pos} + + |