LDCad Idea for an LDCad script


RE: Idea for an LDCad script
#25
Thank you Roland for your help and LDCad 1.7-alpha-2. The discussed "place on ground" seems to work in a first version. Also porting the collision detection from Java to LUA will take more time...

At the moment the script can:
1: collect all parts recursively and print their filename/description together with its bounding box
2: move all parts/submodel-references so that the lowest point has y==0
3: tbd: check collision of parts by comparing pairs of triangles of pairs of parts

The current implementation collects all parts at first which would not be necessary for case 1 (just print instead of collect+print) and case 2 (just collect maxY instead of all bounding boxes of all parts), so this implementation is far from being optimal in regards to timing or memory usage. But it helps me porting my collision detection Wink and maybe it is useful for others doing similar stuff.

Code:
Part={triangles={}, orig={}, level=0, pMinX=math.huge,pMinY=math.huge,pMinZ=math.huge, pMaxX=-math.huge,pMaxY=-math.huge,pMaxZ=-math.huge}
function Part:new(orig, level)
  o={}
  setmetatable(o, self)
  self.__index=self
  self.orig=orig or {}
  self.level=level or 0
  self.pMinX=math.huge
  self.pMinY=math.huge
  self.pMinZ=math.huge
  self.pMaxX=-math.huge
  self.pMaxY=-math.huge
  self.pMaxZ=-math.huge
  return o
end
function Part:add(tri)
  table.insert(self.triangles, tri)
  if tri.pMinX<self.pMinX then
    self.pMinX=tri.pMinX
  end
  if tri.pMinY<self.pMinY then
    self.pMinY=tri.pMinY
  end
  if tri.pMinZ<self.pMinZ then
    self.pMinZ=tri.pMinZ
  end
  if tri.pMaxX>self.pMaxX then
    self.pMaxX=tri.pMaxX
  end
  if tri.pMaxY>self.pMaxY then
    self.pMaxY=tri.pMaxY
  end
  if tri.pMaxZ>self.pMaxZ then
    self.pMaxZ=tri.pMaxZ
  end
end
function Part:info()
  return self.orig:getFileName()..' ('..self.orig:getDescription()..'): '..self.pMinX..' '..self.pMinY..' '..self.pMinZ..' to '..self.pMaxX..' '..self.pMaxY..' '..self.pMaxZ
end

Triangle={p1={}, p2={}, p3={}, pMinX=math.huge,pMinY=math.huge,pMinZ=math.huge, pMaxX=-math.huge,pMaxY=-math.huge,pMaxZ=-math.huge}
function Triangle:new(p1, p2, p3)
  o={}
  setmetatable(o, self)
  self.__index=self
  self.p1=p1
  self.p2=p2
  self.p3=p3
  self.pMinX=math.huge
  self.pMinY=math.huge
  self.pMinZ=math.huge
  self.pMaxX=-math.huge
  self.pMaxY=-math.huge
  self.pMaxZ=-math.huge
  self:check(p1)
  self:check(p2)
  self:check(p3)
--  print('vec: ', p1,' / ',p2,' / ',p3)
--  print('min/max: ', self.pMinX,' ',self.pMinY,' ',self.pMinZ, ' to ', self.pMaxX,' ',self.pMaxY,' ',self.pMaxZ)
  return o
end
function Triangle:check(p)
  local pX,pY,pZ=p:get()
  if pX<self.pMinX then
    self.pMinX=pX
  end
  if pY<self.pMinY then
    self.pMinY=pY
  end
  if pZ<self.pMinZ then
    self.pMinZ=pZ
  end
  if pX>self.pMaxX then
    self.pMaxX=pX
  end
  if pY>self.pMaxY then
    self.pMaxY=pY
  end
  if pZ>self.pMaxZ then
    self.pMaxZ=pZ
  end
end

function colldet_walk(sf, ppos, level, parts)
  local partCnt=sf:getRefCount()
  for i=1,partCnt do
    local part=sf:getRef(i):getSubfile()
--    print('-- part ', part:getDescription())
    local pos=sf:getRef(i):getPosOri()
    pos:mulBA(ppos)
--    print('-- pos ', pos)
    local data=part:getRenderData()
    if data:isLinked() then
      local mpart=Part:new(part, level)
      table.insert(parts, mpart)
      for g=1,data:getGroupCount() do
        local grp=data:getGroup(g)
        if grp:isTriangle() then
          local cnt=grp:getCount()
--          print('triangle strip contains ', cnt, ' entries')
          for j=1,cnt do
            local a,b,c=grp:getPositionIndices(j)
--            print('triPosRel: ', data:getPosition(a), '; ', data:getPosition(b), '; ', data:getPosition(c))
--            print('triPosAbs: ', data:getPosition(a):getTransformed(pos), '; ', data:getPosition(b):getTransformed(pos), '; ', data:getPosition(c):getTransformed(pos))
            mpart:add(Triangle:new(data:getPosition(a):getTransformed(pos), data:getPosition(b):getTransformed(pos), data:getPosition(c):getTransformed(pos)))
          end
        elseif grp:isQuad() then
          local cnt=grp:getCount()
--          print('quad strip contains ', cnt, ' entries')
          for j=1,cnt do
            local a,b,c,d=grp:getPositionIndices(j)
--            print('quadPosRel: ', data:getPosition(a), '; ', data:getPosition(b), '; ', data:getPosition(c), '; ', data:getPosition(d))
--            print('quadPosAbs: ', data:getPosition(a):getTransformed(pos), '; ', data:getPosition(b):getTransformed(pos), '; ', data:getPosition(c):getTransformed(pos), '; ', data:getPosition(d):getTransformed(pos))
            mpart:add(Triangle:new(data:getPosition(a):getTransformed(pos), data:getPosition(b):getTransformed(pos), data:getPosition(c):getTransformed(pos)))
            mpart:add(Triangle:new(data:getPosition(c):getTransformed(pos), data:getPosition(d):getTransformed(pos), data:getPosition(a):getTransformed(pos)))
          end
        end
      end
    else
      colldet_walk(part, pos, level+1, parts)
    end
  end
end

function colldet_collect()
  local sf=ldc.subfile()
  local pos=ldc.matrix()
  --identity is set by default: pos:setIdentity()
  local parts={}
  colldet_walk(sf, pos, 0, parts)
  print('found ',#parts,' parts:')
  for i=1,#parts do
    print(i, ': ', parts[i]:info())
  end
end

function colldet_floor()
  local sf=ldc.subfile()
  local pos=ldc.matrix()
  pos:setIdentity()
  local parts={}
  colldet_walk(sf, pos, 0, parts)
  if #parts==0 then
    print('no part found')
  else
    local max=parts[1].pMaxY
    for i=2,#parts do
      if max<parts[i].pMaxY then
        max=parts[i].pMaxY
      end
    end
    local partCnt=sf:getRefCount()
    for i=1,partCnt do
      local ref=sf:getRef(i)
      local x,y,z=ref:getPos():get()
      ref:setPos(ldc.vector(x,y-max,z))
    end
  end
end

function colldet_check()
  print('not implemented yet!')
  local sf=ldc.subfile()
  local pos=ldc.matrix()
  pos:setIdentity()
  local parts={}
  colldet_walk(sf, pos, 0, parts)
  for i=2,#parts do
    for j=1,i-1 do
      local p1=parts[i]
      local p2=parts[j]
      print('todo: checking ', i, ' (', p1:info(), ') against ', j, ' (', p2:info(), ')')
      -- todo
    end
  end
end

function register()
  local macro=ldc.macro('CD: 1 collect parts')
  macro:setHint('Collision Detection: collect parts')
  macro:setEvent('run', 'colldet_collect')
  local macro=ldc.macro('CD: 2 move to floor')
  macro:setHint('Collision Detection: move bottom point down/up to 0')
  macro:setEvent('run', 'colldet_floor')
  local macro=ldc.macro('CD: 3 check collision')
  macro:setHint('Collision Detection: check part collision')
  macro:setEvent('run', 'colldet_check')
end

register()
Reply
« Next Oldest | Next Newest »



Messages In This Thread
Idea for an LDCad script - by N. W. Perry - 2021-12-31, 21:13
RE: Idea for an LDCad script - by Owen Dive - 2022-01-03, 0:18
RE: Idea for an LDCad script - by N. W. Perry - 2022-01-06, 19:57
RE: Idea for an LDCad script - by N. W. Perry - 2022-01-10, 15:58
RE: Idea for an LDCad script - by Stefan Frenz - 2022-05-30, 15:30

Forum Jump:


Users browsing this thread: 11 Guest(s)