diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 9ccfeaf1a..d70807cf5 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -423,7 +423,12 @@ def getShapeFromMesh(mesh,fast=True,tolerance=0.001,flat=False,cut=True): pts = [] for pp in p: pts.append(FreeCAD.Vector(pp[0],pp[1],pp[2])) - faces.append(Part.Face(Part.makePolygon(pts))) + try: + f = Part.Face(Part.makePolygon(pts)) + except: + pass + else: + faces.append(f) shell = Part.makeShell(faces) solid = Part.Solid(shell) solid = solid.removeSplitter() @@ -509,6 +514,14 @@ def meshToShape(obj,mark=True,fast=True,tol=0.001,flat=False,cut=True): return newobj return None +def removeCurves(shape,tolerance=5): + '''removeCurves(shape,tolerance=5): replaces curved faces in a shape + with faceted segments''' + import Mesh + t = shape.cleaned().tessellate(tolerance) + m = Mesh.Mesh(t) + return getShapeFromMesh(m) + def removeShape(objs,mark=True): '''removeShape(objs,mark=True): takes an arch object (wall or structure) built on a cubic shape, and removes the inner shape, keeping its length, width and height as parameters. If mark is True, objects that cannot diff --git a/src/Mod/Arch/ArchMaterial.py b/src/Mod/Arch/ArchMaterial.py index 5dbdd6d94..bc035f7bf 100644 --- a/src/Mod/Arch/ArchMaterial.py +++ b/src/Mod/Arch/ArchMaterial.py @@ -46,8 +46,10 @@ def getMaterialContainer(): for obj in FreeCAD.ActiveDocument.Objects: if obj.Name == "MaterialContainer": return obj - obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup","MaterialContainer") + obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython","MaterialContainer") obj.Label = "Materials" + _ArchMaterialContainer(obj) + _ViewProviderArchMaterialContainer(obj.ViewObject) return obj @@ -66,7 +68,7 @@ def getDocumentMaterials(): class _CommandArchMaterial: "the Arch Material command definition" def GetResources(self): - return {'Pixmap': 'Arch_Material', + return {'Pixmap': 'Arch_Material_Group', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Material","Set material..."), 'Accel': "M, T", 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Material","Creates or edits the material definition of a selected object.")} @@ -90,6 +92,26 @@ class _CommandArchMaterial: return False +class _ArchMaterialContainer: + "The Material Container" + def __init__(self,obj): + self.Type = "MaterialContainer" + obj.Proxy = self + + def execute(self,obj): + return + + +class _ViewProviderArchMaterialContainer: + "A View Provider for the Material Container" + + def __init__(self,vobj): + vobj.Proxy = self + + def getIcon(self): + return ":/icons/Arch_Material_Group.svg" + + class _ArchMaterial: "The Material object" def __init__(self,obj): @@ -97,11 +119,18 @@ class _ArchMaterial: obj.Proxy = self def execute(self,obj): + if obj.Material and FreeCAD.GuiUp: + if "Color" in obj.Material: + c = tuple([float(f) for f in obj.Material['Color'].strip("()").split(",")]) + for p in obj.InList: + if hasattr(p,"BaseMaterial"): + if p.BaseMaterial.Name == obj.Name: + p.ViewObject.ShapeColor = c return class _ViewProviderArchMaterial: - "A View Provider for the MechanicalMaterial object" + "A View Provider for the Material object" def __init__(self,vobj): vobj.Proxy = self @@ -158,6 +187,8 @@ class _ArchMaterialTaskPanel: "sets the task box contents from self.material" if 'Name' in self.material: self.form.FieldName.setText(self.material['Name']) + elif self.obj: + self.form.FieldName.setText(self.obj.Label) if 'Description' in self.material: self.form.FieldDescription.setText(self.material['Description']) if 'Color' in self.material: @@ -168,7 +199,6 @@ class _ArchMaterialTaskPanel: colorPix = QtGui.QPixmap(16,16) colorPix.fill(self.color) self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix)) - self.form.FieldColor.setText(self.material['Color']) if 'StandardCode' in self.material: self.form.FieldCode.setText(self.material['StandardCode']) if 'ProductURL' in self.material: @@ -188,10 +218,7 @@ class _ArchMaterialTaskPanel: if hasattr(self.obj,"Material"): self.obj.Material = self.material self.obj.Label = self.material['Name'] - FreeCADGui.Control.closeDialog() - - def reject(self): - FreeCADGui.Control.closeDialog() + FreeCADGui.ActiveDocument.resetEdit() def chooseMat(self, card): "sets self.material from a card" diff --git a/src/Mod/Arch/ArchMaterial.ui b/src/Mod/Arch/ArchMaterial.ui index 5d75191f3..90789cfc1 100644 --- a/src/Mod/Arch/ArchMaterial.ui +++ b/src/Mod/Arch/ArchMaterial.ui @@ -6,7 +6,7 @@ 0 0 - 223 + 193 233 @@ -82,13 +82,6 @@ - - - - () - - - diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc index 143d8c271..a3310217c 100644 --- a/src/Mod/Arch/Resources/Arch.qrc +++ b/src/Mod/Arch/Resources/Arch.qrc @@ -55,6 +55,7 @@ icons/Git.svg icons/Arch_Component.svg icons/Arch_Material.svg + icons/Arch_Material_Group.svg ui/archprefs-base.ui ui/archprefs-defaults.ui ui/archprefs-import.ui diff --git a/src/Mod/Arch/Resources/icons/Arch_Material_Group.svg b/src/Mod/Arch/Resources/icons/Arch_Material_Group.svg new file mode 100644 index 000000000..2bab17b3a --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Material_Group.svg @@ -0,0 +1,680 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index e827d6001..16d573e44 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -838,6 +838,15 @@ def export(exportList,filename): isi = ifcfile.createIfcStyledItem(None,[psa],None) isr = ifcfile.createIfcStyledRepresentation(context,"Style","Material",[isi]) imd = ifcfile.createIfcMaterialDefinitionRepresentation(None,None,[isr],mat) + relobjs = [] + for o in m.InList: + if hasattr(o,"BaseMaterial"): + if o.BaseMaterial: + if o.BaseMaterial.Name == m.Name: + if o.Name in products: + relobjs.append(products[o.Name]) + if relobjs: + ifcfile.createIfcRelAssociatesMaterial(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'MaterialLink','',relobjs,mat) if DEBUG: print "writing ",filename,"..." ifcfile.write(filename) @@ -989,42 +998,44 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess curves = True break if curves: - shapetype = "triangulated" - tris = fcsolid.tessellate(tessellation) - for tri in tris[1]: - pts = [ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri] - loop = ifcfile.createIfcPolyLoop(pts) - bound = ifcfile.createIfcFaceOuterBound(loop,True) - face = ifcfile.createIfcFace([bound]) - faces.append(face) - else: - shapetype = "brep" - for fcface in fcsolid.Faces: - loops = [] - verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(fcface.OuterWire.Edges)).Vertexes] - c = fcface.CenterOfMass - v1 = verts[0].sub(c) - v2 = verts[1].sub(c) - n = fcface.normalAt(0,0) - if DraftVecUtils.angle(v2,v1,n) >= 0: - verts.reverse() # inverting verts order if the direction is couterclockwise - pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts] - loop = ifcfile.createIfcPolyLoop(pts) - bound = ifcfile.createIfcFaceOuterBound(loop,True) - loops.append(bound) - for wire in fcface.Wires: - if wire.hashCode() != fcface.OuterWire.hashCode(): - verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)).Vertexes] - v1 = verts[0].sub(c) - v2 = verts[1].sub(c) - if DraftVecUtils.angle(v2,v1,DraftVecUtils.neg(n)) >= 0: - verts.reverse() - pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts] - loop = ifcfile.createIfcPolyLoop(pts) - bound = ifcfile.createIfcFaceBound(loop,True) - loops.append(bound) - face = ifcfile.createIfcFace(loops) - faces.append(face) + #shapetype = "triangulated" + #tris = fcsolid.tessellate(tessellation) + #for tri in tris[1]: + # pts = [ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri] + # loop = ifcfile.createIfcPolyLoop(pts) + # bound = ifcfile.createIfcFaceOuterBound(loop,True) + # face = ifcfile.createIfcFace([bound]) + # faces.append(face) + fcsolid = Arch.removeCurves(fcsolid) + + shapetype = "brep" + for fcface in fcsolid.Faces: + loops = [] + verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(fcface.OuterWire.Edges)).Vertexes] + c = fcface.CenterOfMass + v1 = verts[0].sub(c) + v2 = verts[1].sub(c) + n = fcface.normalAt(0,0) + if DraftVecUtils.angle(v2,v1,n) >= 0: + verts.reverse() # inverting verts order if the direction is couterclockwise + pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts] + loop = ifcfile.createIfcPolyLoop(pts) + bound = ifcfile.createIfcFaceOuterBound(loop,True) + loops.append(bound) + for wire in fcface.Wires: + if wire.hashCode() != fcface.OuterWire.hashCode(): + verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)).Vertexes] + v1 = verts[0].sub(c) + v2 = verts[1].sub(c) + if DraftVecUtils.angle(v2,v1,DraftVecUtils.neg(n)) >= 0: + verts.reverse() + pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts] + loop = ifcfile.createIfcPolyLoop(pts) + bound = ifcfile.createIfcFaceBound(loop,True) + loops.append(bound) + face = ifcfile.createIfcFace(loops) + faces.append(face) + shell = ifcfile.createIfcClosedShell(faces) shape = ifcfile.createIfcFacetedBrep(shell) shapes.append(shape) @@ -1033,6 +1044,14 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess # set surface style if FreeCAD.GuiUp and (not subtraction) and hasattr(obj.ViewObject,"ShapeColor"): + # only set a surface style if the object has no material. + # apparently not needed, no harm in having both. + #m = False + #if hasattr(obj,"BaseMaterial"): + # if obj.BaseMaterial: + # if "Color" in obj.BaseMaterial.Material: + # m = True + #if not m: rgb = obj.ViewObject.ShapeColor[:3] if rgb in surfstyles: psa = surfstyles[rgb] diff --git a/src/Mod/Material/materials-editor.ui b/src/Mod/Material/materials-editor.ui index d8fb395f1..4c26adac7 100644 --- a/src/Mod/Material/materials-editor.ui +++ b/src/Mod/Material/materials-editor.ui @@ -7,7 +7,7 @@ 0 0 450 - 599 + 604 @@ -545,7 +545,7 @@ Execution Instructions - Specific execution or installation insstructions + Specific execution or installation instructions ItemIsSelectable|ItemIsEditable|ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled @@ -879,10 +879,10 @@ - Section Fill Pattern + View Linewidth - An SVG pattern to apply on cut faces, expressed as either a name of an existing pattern (such as "simple") or a complete <pattern>...</pattern> SVG element + An optional linewidth factor for viewed faces @@ -893,10 +893,18 @@ - View Linewidth + Section Color - An optional linewidth factor for viewed faces + A base color for sectionned faces, expressed with 3 comma-separated float values, for ex. 0.5,0.5,0.5 + + + + + Section Fill Pattern + + + An SVG pattern to apply on cut faces, expressed as either a name of an existing pattern (such as "simple") or a complete <pattern>...</pattern> SVG element