# *************************************************************************** # * Copyright (c) 2017 Lorenz Lechner * # * * # * This file is part of the FreeCAD CAx development system. * # * * # * This library is free software; you can redistribute it and/or * # * modify it under the terms of the GNU Library General Public * # * License as published by the Free Software Foundation; either * # * version 2 of the License, or (at your option) any later version. * # * * # * This library 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 library; see the file COPYING.LIB. If not, * # * write to the Free Software Foundation, Inc., 59 Temple Place, * # * Suite 330, Boston, MA 02111-1307, USA * # * * # ***************************************************************************/ import Mesh import FreeCAD as App import FreeCADGui as Gui import Part import MeshPartGui from PySide.QtCore import QT_TRANSLATE_NOOP # for translations class BaseCommand(object): def __init__(self): pass def IsActive(self): if App.ActiveDocument is None: return False else: return True class CreateFlatMesh(BaseCommand): """create flat wires from a meshed face""" def GetResources(self): return { "Pixmap": "MeshPart_CreateFlatMesh.svg", "MenuText": QT_TRANSLATE_NOOP("MeshPart_CreateFlatMesh", "Unwrap mesh"), "ToolTip": QT_TRANSLATE_NOOP( "MeshPart_CreateFlatMesh", "Find a flat representation of a mesh." ), } def Activated(self): import numpy as np import flatmesh obj = Gui.Selection.getSelection()[ 0 ] # obj must be a Mesh (Mesh-Design->Meshes->Create-Mesh) points = np.array([[i.x, i.y, i.z] for i in obj.Mesh.Points]) faces = np.array([list(i) for i in obj.Mesh.Topology[1]]) flattener = flatmesh.FaceUnwrapper(points, faces) flattener.findFlatNodes(5, 0.95) boundaries = flattener.getFlatBoundaryNodes() # print('number of nodes: {}'.format(len(flattener.ze_nodes))) # print('number of faces: {}'.format(len(flattener.tris))) wires = [] for edge in boundaries: pi = Part.makePolygon([App.Vector(*node) for node in edge]) Part.show(Part.Wire(pi)) def IsActive(self): assert super(CreateFlatMesh, self).IsActive() assert isinstance(Gui.Selection.getSelection()[0].Mesh, Mesh.Mesh) return True class CreateFlatFace(BaseCommand): """create a flat face from a single face only full faces are supported right now""" def GetResources(self): return { "Pixmap": "MeshPart_CreateFlatFace.svg", "MenuText": QT_TRANSLATE_NOOP("MeshPart_CreateFlatFace", "Unwrap face"), "ToolTip": QT_TRANSLATE_NOOP( "MeshPart_CreateFlatFace", "Find a flat representation of a face." ), } def Activated(self): import numpy as np import flatmesh face = Gui.Selection.getSelectionEx()[0].SubObjects[0] shape = face.toNurbs() face = shape.Faces[0] nurbs = face.Surface nurbs.setUNotPeriodic() nurbs.setVNotPeriodic() bs = nurbs.toBSpline(1, "C0", "C0", 3, 3, 10) face = bs.toShape() face.tessellate(0.01) flattener = flatmesh.FaceUnwrapper(face) flattener.findFlatNodes(5, 0.99) poles = flattener.interpolateFlatFace(face) num_u_poles = len(bs.getPoles()) num_v_poles = len(bs.getPoles()[0]) i = 0 for u in range(num_u_poles): for v in range(num_v_poles): bs.setPole(u + 1, v + 1, App.Vector(poles[i])) i += 1 Part.show(bs.toShape()) def IsActive(self): assert super(CreateFlatFace, self).IsActive() assert isinstance(Gui.Selection.getSelectionEx()[0].SubObjects[0], Part.Face) return True # Test if pybind11 dependency is available try: import flatmesh Gui.addCommand("MeshPart_CreateFlatMesh", CreateFlatMesh()) Gui.addCommand("MeshPart_CreateFlatFace", CreateFlatFace()) except ImportError: App.Console.PrintLog("flatmesh-commands are not available\n") App.Console.PrintLog("flatmesh needs pybind11 as build dependency\n") except AttributeError: # Can happen when running FreeCAD in headless mode pass