[MOD] Minetest 3D Print 0.1 [M3D]

User avatar
aldobr
Member
 
Posts: 316
Joined: Sun Nov 25, 2012 05:46

[MOD] Minetest 3D Print 0.1 [M3D]

by aldobr » Mon Aug 18, 2014 06:26

This allows 3D printing map areas.

Minetest side script :

Code: Select all
-- FreeCAD exporting MOD - Minetest side
-- Copyright(C) 2014 - J. Aldo Gomes de Freitas Junior
-- GPLv2
-- Minetest side module

-- exporter proper
nodeexporter = {

   -- Populate this array with a list of nodes that should be rendered
   blockmapping = {
         ['default:dirt'] = 1,
         ['default:dirt_with_grass'] = 1
      },

   -- Exports a chunk of land starting at ax1, ay1, az1 and ending at ax2, ay2, az2
   exportblocks = function(athis, afilename, ax1, ay1, az1, ax2, ay2, az2)
      local destination = io.open(minetest.get_worldpath() .. "/" .. afilename, "w")
      local x, y, z
      local swapvar
      -- Verify and swap inverted coordinates
      if ax1 > ax2 then
         swapvar = ax2
         ax2 = ax1
         ax1 = swapvar
      end
      if ay1 > ay2 then
         swapvar = ay2
         ay2 = ay1
         ay1 = swapvar
      end
      if az1 > az2 then
         swapvar = az2
         az2 = az1
         az1 = swapvar
      end
      -- Write map chunk size
      destination:write((ax2 - ax1) .. '\n' .. (ay2 - ay1) .. '\n' .. (az2 - az1) .. '\n')
      -- Write map data
      for ly = ay1, ay2 do
         for lx = ax1, ax2 do
            for lz = az1, az2 do
               local node = minetest.env:get_node({ x = lx, y = ly, z = lz })
               local value = athis.blockmapping[node.name]
               if value ~= nil then
                  destination:write(value .. '\n')
               else
                  destination:write('0\n')
               end
            end
         end
      end
      destination:close()
   end
}

-- Register chat command
minetest.register_chatcommand(
   "mapexport",
   {
      params = "filename x1 y1 z1 x2 y2 z2",
      description = "Exports a piece of game map in a format that can be read by FreeCAD minetest importer plugin.",
      privs = { },
      func =
         function(name, param)
                  paramlist = string.split(param, " ")
                  local filename = paramlist[1]
                  local x1 = tonumber(paramlist[2])
                  local y1 = tonumber(paramlist[3])
                  local z1 = tonumber(paramlist[4])
                  local x2 = tonumber(paramlist[5])
                  local y2 = tonumber(paramlist[6])
                  local z2 = tonumber(paramlist[7])
                  nodeexporter:exportblocks(filename, x1, y1, z1, x2, y2, z2)
            return true, "Exported to " .. filename;
         end
   });


FreeCAD side script:
Code: Select all
# FreeCAD exporting MOD - Minetest side
# Copyright(C) 2014 - J. Aldo Gomes de Freitas Junior
# GPLv2
# FreeCAD side module

import Part, math

def makeCenter(x = 0, y = 0, z = 0):
   return FreeCAD.Vector(x, y, z)

def makeRotation(x = 0, y = 0, z = 0):
   return FreeCAD.Rotation(x, y, z)

def makePlacement(x, y, z, X, Y, Z):
   return FreeCAD.Placement(makeCenter(x, y, z), makeRotation(X, Y, Z))

def importvolumefile(filename, xscale = 10, yscale = 10, zscale = 10):
   cubes = []
   sourcefile = open(filename)
   xsize = int(float(sourcefile.readline()))
   ysize = int(float(sourcefile.readline()))
   zsize = int(float(sourcefile.readline()))
   for yposition in range(1, ysize):
      for xposition in range(1, xsize):
         for zposition in range(1, zsize):
            value = int(float(sourcefile.readline()))
            if value > 0:
               cube = Part.makeBox(zscale, xscale, yscale)
               cube.Placement = makePlacement(xposition * xscale, yposition * yscale, zposition * zscale, 0, 0, 0)
               cubes.append(cube)
   sourcefile.close()
   solid = Part.makeCompound(cubes)
   return solid

# replace filename - needs a beter interface
map = importvolumefile("c:/minetest/minetest-0.4.10/worlds/aldo/teste.vol")
Part.show(map)


Already works in my computer. I can - if trully needed - use FreeCAD boolean operations to fuse all cubes into a single entity, but this is quite a costly operation.

TODO:

Minetest side - Add parameter handling and checking. Populate the mapping table. There are only two entries right now. (dirt and dirt with grass)
FreeCAD side - Add file selection interface. Change tile color by minetest mod mapping. Handle nodebox.

This is the result inside freecad:

https://www.dropbox.com/s/liznoix6ezkx9uy/freecad.png

To export a map piece from minetest :

Code: Select all
/minetest <filename> <x1> <y1> <z1> <x2> <y2> <z2>


To import into FreeCAD :

Edit this line:

Code: Select all
# replace filename - needs a beter interface
map = importvolumefile("c:/minetest/minetest-0.4.10/worlds/aldo/teste.vol")


"c:/minetest/minetest-0.4.10/worlds/aldo/teste.vol" is a fully qualified filename that points to a volume that i exported in my harddisk. Replace it with a correct fully qualified path name that points to the correct file inside your computer.

Cubes might happend to be mirrored/inverted, coords might happen to be rotated (x vs y, x vs z etc). Those small bugs need to be fixed by tests. First thing is to pupulate the "blockmapping" array in the lua source code. The blockmap has a simple structure, ["<registerednodename>"] = <value>. Any value above 0 will become a block inside minetest. The is scale is so that each block (node) inside minetest becomes a 10mm x 10mm x 10mm cube inside freecad. The scale can be changed by adding scale values to the importvolumefile call.

Code: Select all
p = importvolumefile(<filename>, [<xscale>, [<yscale>, [<zscale>]]])


How to use :

Export a map area from inside minetest. The file will be saved into the world directory. Open that file in FreeCAD using the macro provided. Export the file in a format that can be understood by Slic3r. Slice it, and send to printer. Later i can provide a better interface for both freecad and minetest. But now it works and thats sufficient.
 

User avatar
aldobr
Member
 
Posts: 316
Joined: Sun Nov 25, 2012 05:46
 

spin
Member
 
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: [MOD] Minetest 3D Print 0.1 [M3D]

by spin » Mon Aug 18, 2014 12:31

aldobr,
I think boolean will be necessary to import huge chunks of map data. Look at the scene stats here (top of screen)
download/file.php?id=1020
This is not a big chunk world-wise, and it's terribly slow to perform any operations on already.

Initial processing investment in booleans will pay back with increased performance later on, though may generate anomalous geometry (any error gets propagated across the process).

It would be ideal if the map import was (optionally) 'cored out' of any cubes that are not visible (so every cube that is surrounded by 14 cubes on each side was skipped. 6 is not possible due to booleans requiring non-ambiguous geometry, but something in-between could theoretically work to make external walls thinner), this would make performance drastically better.


I don't know how to handle material export in booleans case (merge only materials of certain type? That would allow for some hardcore texturing).

Also, viewtopic.php?f=3&t=156&start=2450#p151540
 

User avatar
aldobr
Member
 
Posts: 316
Joined: Sun Nov 25, 2012 05:46

Re: [MOD] Minetest 3D Print 0.1 [M3D]

by aldobr » Mon Aug 18, 2014 14:49

Well, testing this thing in my computer, a little quad core atom, takes forever to load. My little processor is screaming like a pig on fire...

Not that being quad core means much, four idiots cannot change a light bulb better than a single smart person :P
 

spin
Member
 
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: [MOD] Minetest 3D Print 0.1 [M3D]

by spin » Mon Aug 18, 2014 15:29

Yeah, I think this may take a few hours depending on dataset and processor. But it makes the data manageable by user in realtime later on.

I saw some really huge Minecraft exports, and it was some time ago, I wonder if those exporters tackled the problem of resulting geometry in some way. Maybe we're trying to reinvent the wheel?
 

User avatar
aldobr
Member
 
Posts: 316
Joined: Sun Nov 25, 2012 05:46

Re: [MOD] Minetest 3D Print 0.1 [M3D]

by aldobr » Mon Aug 18, 2014 16:10

Found another way, based on OpenSCAD. It looks more stable.
 

spin
Member
 
Posts: 25
Joined: Fri Aug 15, 2014 16:12

Re: [MOD] Minetest 3D Print 0.1 [M3D]

by spin » Mon Aug 18, 2014 17:46

Awesome! Keeping an eye on this thread :)
 

User avatar
aldobr
Member
 
Posts: 316
Joined: Sun Nov 25, 2012 05:46

Re: [MOD] Minetest 3D Print 0.1 [M3D]

by aldobr » Mon Aug 18, 2014 22:51

This is the OpenSCAD exporter. Takes forever to load but looks more stable than freecad.

Code: Select all
-- OpenSCAD exporting MOD for minetest
-- Copyright(C) 2014 - J. Aldo Gomes de Freitas Junior
-- GPLv2

-- exporter
nodeexporter = {

   -- Populate this array with a list of nodes that should be rendered
   blockmapping = {
         ['default:dirt'] = 1,
         ['default:dirt_with_grass'] = 1,
         ['default:stone'] = 1
      },

   -- Exports a chunk of land starting at ax1, ay1, az1 and ending at ax2, ay2, az2
   exportblocks = function(athis, afilename, ax1, ay1, az1, ax2, ay2, az2, scale)
      local destination = io.open(minetest.get_worldpath() .. "/" .. afilename, "w")
      local x, y, z
      local swapvar
      -- Verify and swap inverted coordinates
      if ax1 > ax2 then
         swapvar = ax2
         ax2 = ax1
         ax1 = swapvar
      end
      if ay1 > ay2 then
         swapvar = ay2
         ay2 = ay1
         ay1 = swapvar
      end
      if az1 > az2 then
         swapvar = az2
         az2 = az1
         az1 = swapvar
      end
      destination:write('union() {\n')
      -- Write map data
      for ly = ay1, ay2 do
         for lx = ax1, ax2 do
            for lz = az1, az2 do
               local node = minetest.env:get_node({ x = lx, y = ly, z = lz })
               local value = athis.blockmapping[node.name]
               if value ~= nil then
                  destination:write(string.format('    translate([%d, %d, %d]) {\n        cube([%d, %d, %d]);\n    }\n', lx * scale, ly * scale, lz * scale, scale, scale, scale))
               end
            end
         end
      end
      destination:write('}\n')
      destination:close()
   end
}

-- Register chat command
minetest.register_chatcommand(
   "openscad",
   {
      params = "filename x1 y1 z1 x2 y2 z2 scale",
      description = "Exports a piece of game map in a format that can be rendered by OpenSCAD.",
      privs = { },
      func =
         function(name, param)
                  paramlist = string.split(param, " ")
                  local filename = paramlist[1]
                  local x1 = tonumber(paramlist[2])
                  local y1 = tonumber(paramlist[3])
                  local z1 = tonumber(paramlist[4])
                  local x2 = tonumber(paramlist[5])
                  local y2 = tonumber(paramlist[6])
                  local z2 = tonumber(paramlist[7])
                  local sc = tonumber(paramlist[8])
                  nodeexporter:exportblocks(filename, x1, y1, z1, x2, y2, z2, sc)
            return true, "Exported to " .. filename;
         end
   });


To use :

/openscad <file.scad> <x1> <y1> <z1> <x2> <y2> <z2> <scale>

usually scale is 10 meaning 1 node is 10mm x 10mm x 10mm

The file will be saved at the world directory. Open the file using OpenSCAD and compile. After the image appears onscreen, export it as STL and open it in slic3r to print.

TODO.: Populate the blockmapping array with values or change the behaviour to print everything but air.
 


Return to WIP Mods



Who is online

Users browsing this forum: Majestic-12 [Bot], Skamiz Kazzarch and 6 guests