Arch: First version of Sweethome3D importer - issue #2584

This commit is contained in:
Yorik van Havre 2016-06-15 21:24:03 -03:00
parent 4acf8e09dc
commit 3510c71f2b
3 changed files with 207 additions and 0 deletions

View File

@ -37,6 +37,7 @@ SET(Arch_SRCS
ArchProfile.py
import3DS.py
ArchPrecast.py
importSH3D.py
)
SET(Dice3DS_SRCS

View File

@ -29,3 +29,4 @@ FreeCAD.addExportType("WebGL file (*.html)","importWebGL")
FreeCAD.addImportType("Collada (*.dae)","importDAE")
FreeCAD.addExportType("Collada (*.dae)","importDAE")
FreeCAD.addImportType("3D Studio mesh (*.3ds)","import3DS")
FreeCAD.addImportType("SweetHome3D XML export (*.zip)","importSH3D")

205
src/Mod/Arch/importSH3D.py Normal file
View File

@ -0,0 +1,205 @@
#***************************************************************************
#* *
#* Copyright (c) 2016 Yorik van Havre <yorik@uncreated.net> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
__title__ = "FreeCAD SweetHome3D importer"
__author__ = "Yorik van Havre"
__url__ = "http://www.freecadweb.org"
import os,zipfile,xml.sax,FreeCAD,Part,Draft,Arch,Mesh,tempfile,math,Sketcher
DEBUG = True
if open.__module__ == '__builtin__':
pyopen = open # because we'll redefine open below
def open(filename):
"called when freecad wants to open a file"
docname = (os.path.splitext(os.path.basename(filename))[0]).encode("utf8")
doc = FreeCAD.newDocument(docname)
doc.Label = decode(docname)
FreeCAD.ActiveDocument = doc
read(filename)
return doc
def insert(filename,docname):
"called when freecad wants to import a file"
try:
doc = FreeCAD.getDocument(docname)
except NameError:
doc = FreeCAD.newDocument(docname)
FreeCAD.ActiveDocument = doc
read(filename)
return doc
def decode(name):
"decodes encoded strings"
try:
decodedName = (name.decode("utf8"))
except UnicodeDecodeError:
try:
decodedName = (name.decode("latin1"))
except UnicodeDecodeError:
FreeCAD.Console.PrintError(translate("Arch","Error: Couldn't determine character encoding"))
decodedName = name
return decodedName
def read(filename):
"reads the file and creates objects in the active document"
z = zipfile.ZipFile(filename)
homexml = z.read("Home.xml")
handler = SH3DHandler(z)
xml.sax.parseString(homexml,handler)
FreeCAD.ActiveDocument.recompute()
if not handler.makeIndividualWalls:
delete = []
walls = []
for k,lines in handler.lines.items():
sk = FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject","Walls_trace")
for l in lines:
for edge in l.Shape.Edges:
sk.addGeometry(edge.Curve)
delete.append(l.Name)
FreeCAD.ActiveDocument.recompute()
k = k.split(";")
walls.append(Arch.makeWall(baseobj=sk,width=float(k[0]),height=float(k[1])))
for d in delete:
FreeCAD.ActiveDocument.removeObject(d)
w = walls.pop()
w.Additions = walls
w.Subtractions = handler.windows
g = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup","Furniture")
g.Group = handler.furniture
FreeCAD.ActiveDocument.recompute()
class SH3DHandler(xml.sax.ContentHandler):
def __init__(self,z):
self.makeIndividualWalls = False
self.z = z
self.windows = []
self.furniture = []
self.lines = {}
def startElement(self, tag, attributes):
if tag == "wall":
name = attributes["id"]
p1 = FreeCAD.Vector(float(attributes["xStart"])*10,float(attributes["yStart"])*10,0)
p2 = FreeCAD.Vector(float(attributes["xEnd"])*10,float(attributes["yEnd"])*10,0)
height = float(attributes["height"])*10
thickness = float(attributes["thickness"])*10
if DEBUG: print "Creating wall: ",name
line = Draft.makeLine(p1,p2)
if self.makeIndividualWalls:
wall = Arch.makeWall(baseobj=line,width=thickness,height=height,name=name)
wall.Label = name
else:
self.lines.setdefault(str(thickness)+";"+str(height),[]).append(line)
elif tag == "pieceOfFurniture":
name = attributes["name"]
data = self.z.read(attributes["model"])
tf = tempfile.mkstemp(suffix=".obj")[1]
f = pyopen(tf,"wb")
f.write(data)
f.close()
m = Mesh.read(tf)
fx = (float(attributes["width"])/100)/m.BoundBox.XLength
fy = (float(attributes["height"])/100)/m.BoundBox.YLength
fz = (float(attributes["depth"])/100)/m.BoundBox.ZLength
mat = FreeCAD.Matrix()
mat.scale(1000*fx,1000*fy,1000*fz)
mat.rotateX(math.pi/2)
mat.rotateZ(math.pi)
if DEBUG: print "Creating furniture: ",name
if "angle" in attributes.keys():
mat.rotateZ(float(attributes["angle"]))
m.transform(mat)
os.remove(tf)
p = m.BoundBox.Center.negative()
p = p.add(FreeCAD.Vector(float(attributes["x"])*10,float(attributes["y"])*10,0))
p = p.add(FreeCAD.Vector(0,0,m.BoundBox.Center.z-m.BoundBox.ZMin))
m.Placement.Base = p
obj = FreeCAD.ActiveDocument.addObject("Mesh::Feature",name)
obj.Mesh = m
self.furniture.append(obj)
elif tag == "doorOrWindow":
name = attributes["name"]
data = self.z.read(attributes["model"])
tf = tempfile.mkstemp(suffix=".obj")[1]
f = pyopen(tf,"wb")
f.write(data)
f.close()
m = Mesh.read(tf)
fx = (float(attributes["width"])/100)/m.BoundBox.XLength
fy = (float(attributes["height"])/100)/m.BoundBox.YLength
fz = (float(attributes["depth"])/100)/m.BoundBox.ZLength
mat = FreeCAD.Matrix()
mat.scale(1000*fx,1000*fy,1000*fz)
mat.rotateX(math.pi/2)
m.transform(mat)
b = m.BoundBox
v1 = FreeCAD.Vector(b.XMin,b.YMin-500,b.ZMin)
v2 = FreeCAD.Vector(b.XMax,b.YMin-500,b.ZMin)
v3 = FreeCAD.Vector(b.XMax,b.YMax+500,b.ZMin)
v4 = FreeCAD.Vector(b.XMin,b.YMax+500,b.ZMin)
sub = Part.makePolygon([v1,v2,v3,v4,v1])
sub = Part.Face(sub)
sub = sub.extrude(FreeCAD.Vector(0,0,b.ZLength))
os.remove(tf)
shape = Arch.getShapeFromMesh(m)
if not shape:
shape=Part.Shape()
shape.makeShapeFromMesh(m.Topology,0.100000)
shape = shape.removeSplitter()
if shape:
if DEBUG: print "Creating window: ",name
if "angle" in attributes.keys():
shape.rotate(shape.BoundBox.Center,FreeCAD.Vector(0,0,1),math.degrees(float(attributes["angle"])))
sub.rotate(shape.BoundBox.Center,FreeCAD.Vector(0,0,1),math.degrees(float(attributes["angle"])))
p = shape.BoundBox.Center.negative()
p = p.add(FreeCAD.Vector(float(attributes["x"])*10,float(attributes["y"])*10,0))
p = p.add(FreeCAD.Vector(0,0,shape.BoundBox.Center.z-shape.BoundBox.ZMin))
if "elevation" in attributes.keys():
p = p.add(FreeCAD.Vector(0,0,float(attributes["elevation"])*10))
shape.translate(p)
sub.translate(p)
obj = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body")
obj.Shape = shape
subobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_sub")
subobj.Shape = sub
if FreeCAD.GuiUp:
subobj.ViewObject.hide()
win = Arch.makeWindow(baseobj=obj,name=name)
win.Label = name
win.Subvolume = subobj
self.windows.append(win)
else:
print("importSH3D: Error creating shape for door/window "+name)