Exemple #1
0
    def read(self, file_name):
        mesh_builder = MeshBuilder()
        scene_node = SceneNode()

        if use_numpystl:
            self._loadWithNumpySTL(file_name, mesh_builder)
        else:
            f = open(file_name, "rb")
            if not self._loadBinary(mesh_builder, f):
                f.close()
                f = open(file_name, "rt")
                try:
                    self._loadAscii(mesh_builder, f)
                except UnicodeDecodeError:
                    return None
                f.close()

            Job.yieldThread() # Yield somewhat to ensure the GUI has time to update a bit.

        mesh_builder.calculateNormals(fast = True)
        mesh_builder.setFileName(file_name)

        mesh = mesh_builder.build()
        Logger.log("d", "Loaded a mesh with %s vertices", mesh_builder.getVertexCount())
        scene_node.setMeshData(mesh)
        return scene_node
Exemple #2
0
def test_render():
    mocked_shader = MagicMock()
    with patch("UM.View.GL.OpenGL.OpenGL.getInstance"):
        render_batch = RenderBatch(mocked_shader)

    # Render without a camera shouldn't cause any effect.
    render_batch.render(None)
    assert mocked_shader.bind.call_count == 0

    # Rendering with a camera should cause the shader to be bound and released (even if the batch is empty)
    mocked_camera = MagicMock()
    mocked_camera.getWorldTransformation = MagicMock(return_value=Matrix())
    mocked_camera.getViewProjectionMatrix = MagicMock(return_value=Matrix())
    with patch("UM.View.GL.OpenGLContext.OpenGLContext.properties"):
        render_batch.render(mocked_camera)
    assert mocked_shader.bind.call_count == 1
    assert mocked_shader.release.call_count == 1

    # Actualy render with an item in the batch
    mb = MeshBuilder()
    mb.addPyramid(10, 10, 10, color=Color(0.0, 1.0, 0.0, 1.0))
    mb.calculateNormals()
    mesh_data = mb.build()
    render_batch.addItem(Matrix(), mesh_data, {})
    with patch("UM.View.GL.OpenGL.OpenGL.getInstance"):
        with patch("UM.View.GL.OpenGLContext.OpenGLContext.properties"):
            render_batch.render(mocked_camera)
    assert mocked_shader.bind.call_count == 2
    assert mocked_shader.release.call_count == 2
Exemple #3
0
def test_render():
    mocked_shader = MagicMock()
    with patch("UM.View.GL.OpenGL.OpenGL.getInstance"):
        render_batch = RenderBatch(mocked_shader)

    # Render without a camera shouldn't cause any effect.
    render_batch.render(None)
    assert mocked_shader.bind.call_count == 0

    # Rendering with a camera should cause the shader to be bound and released (even if the batch is empty)
    mocked_camera = MagicMock()
    mocked_camera.getWorldTransformation = MagicMock(return_value = Matrix())
    mocked_camera.getViewProjectionMatrix = MagicMock(return_value=Matrix())
    with patch("UM.View.GL.OpenGLContext.OpenGLContext.properties"):
        render_batch.render(mocked_camera)
    assert mocked_shader.bind.call_count == 1
    assert mocked_shader.release.call_count == 1

    # Actualy render with an item in the batch
    mb = MeshBuilder()
    mb.addPyramid(10, 10, 10, color=Color(0.0, 1.0, 0.0, 1.0))
    mb.calculateNormals()
    mesh_data = mb.build()
    render_batch.addItem(Matrix(), mesh_data, {})
    with patch("UM.View.GL.OpenGL.OpenGL.getInstance"):
        with patch("UM.View.GL.OpenGLContext.OpenGLContext.properties"):
            render_batch.render(mocked_camera)
    assert mocked_shader.bind.call_count == 2
    assert mocked_shader.release.call_count == 2
    def read(self, file_name):
        mesh_builder = MeshBuilder()
        scene_node = SceneNode()

        if use_numpystl:
            self._loadWithNumpySTL(file_name, mesh_builder)
        else:
            f = open(file_name, "rb")
            if not self._loadBinary(mesh_builder, f):
                f.close()
                f = open(file_name, "rt")
                try:
                    self._loadAscii(mesh_builder, f)
                except UnicodeDecodeError:
                    return None
                f.close()

            Job.yieldThread() # Yield somewhat to ensure the GUI has time to update a bit.

        mesh_builder.calculateNormals(fast = True)

        mesh = mesh_builder.build()
        Logger.log("d", "Loaded a mesh with %s vertices", mesh_builder.getVertexCount())
        scene_node.setMeshData(mesh)
        return scene_node
Exemple #5
0
    def _read(self, file_name):
        try:
            self.defs = {}
            self.shapes = []

            tree = ET.parse(file_name)
            xml_root = tree.getroot()

            if xml_root.tag != "X3D":
                return None

            scale = 1000  # Default X3D unit it one meter, while Cura's is one millimeters
            if xml_root[0].tag == "head":
                for head_node in xml_root[0]:
                    if head_node.tag == "unit" and head_node.attrib.get(
                            "category") == "length":
                        scale *= float(head_node.attrib["conversionFactor"])
                        break
                xml_scene = xml_root[1]
            else:
                xml_scene = xml_root[0]

            if xml_scene.tag != "Scene":
                return None

            self.transform = Matrix()
            self.transform.setByScaleFactor(scale)
            self.index_base = 0

            # Traverse the scene tree, populate the shapes list
            self.processChildNodes(xml_scene)

            if self.shapes:
                builder = MeshBuilder()
                builder.setVertices(
                    numpy.concatenate([shape.verts for shape in self.shapes]))
                builder.setIndices(
                    numpy.concatenate([shape.faces for shape in self.shapes]))
                builder.calculateNormals()
                builder.setFileName(file_name)
                mesh_data = builder.build()

                # Manually try and get the extents of the mesh_data. This should prevent nasty NaN issues from
                # leaving the reader.
                mesh_data.getExtents()

                node = SceneNode()
                node.setMeshData(mesh_data)
                node.setSelectable(True)
                node.setName(file_name)

            else:
                return None

        except Exception:
            Logger.logException("e", "Exception in X3D reader")
            return None

        return node
Exemple #6
0
    def read(self, file_name):
        try:
            self.defs = {}
            self.shapes = []
            
            tree = ET.parse(file_name)
            xml_root = tree.getroot()
            
            if xml_root.tag != "X3D":
                return None

            scale = 1000 # Default X3D unit it one meter, while Cura's is one millimeters            
            if xml_root[0].tag == "head":
                for head_node in xml_root[0]:
                    if head_node.tag == "unit" and head_node.attrib.get("category") == "length":
                        scale *= float(head_node.attrib["conversionFactor"])
                        break 
                xml_scene = xml_root[1]
            else:
                xml_scene = xml_root[0]
                
            if xml_scene.tag != "Scene":
                return None
            
            self.transform = Matrix()
            self.transform.setByScaleFactor(scale)
            self.index_base = 0
            
            # Traverse the scene tree, populate the shapes list
            self.processChildNodes(xml_scene)
            
            if self.shapes:
                builder = MeshBuilder()
                builder.setVertices(numpy.concatenate([shape.verts for shape in self.shapes]))
                builder.setIndices(numpy.concatenate([shape.faces for shape in self.shapes]))
                builder.calculateNormals()
                builder.setFileName(file_name)
                mesh_data = builder.build()

                # Manually try and get the extents of the mesh_data. This should prevent nasty NaN issues from
                # leaving the reader.
                mesh_data.getExtents()

                node = SceneNode()
                node.setMeshData(mesh_data)
                node.setSelectable(True)
                node.setName(file_name)

            else:
                return None
            
        except Exception:
            Logger.logException("e", "Exception in X3D reader")
            return None

        return node
Exemple #7
0
    def _createCube(self, size, maxs, height, dep):
        mesh = MeshBuilder()

        # Intial Comment from Ultimaker B.V. I have never try to verify this point
        # Can't use MeshBuilder.addCube() because that does not get per-vertex normals
        # Per-vertex normals require duplication of vertices
        s = size / 2
        sm = maxs / 2
        l = height 
        s_inf=math.tan(math.radians(dep))*l+s
        
        if sm>s and dep!=0:
            l_max=(sm-s) / math.tan(math.radians(dep))
        else :
            l_max=l
        
        # Difference between Cone and Cone + max base size
        if l_max<l and l_max>0:
            nbv=40        
            verts = [ # 10 faces with 4 corners each
                [-sm, -l_max,  sm], [-s,  s,  s], [ s,  s,  s], [ sm, -l_max,  sm],
                [-s,  s, -s], [-sm, -l_max, -sm], [ sm, -l_max, -sm], [ s,  s, -s],
                [-sm, -l,  sm], [-sm,  -l_max,  sm], [ sm,  -l_max,  sm], [ sm, -l,  sm],
                [-sm,  -l_max, -sm], [-sm, -l, -sm], [ sm, -l, -sm], [ sm,  -l_max, -sm],
                [ sm, -l, -sm], [-sm, -l, -sm], [-sm, -l,  sm], [ sm, -l,  sm],
                [-s,  s, -s], [ s,  s, -s], [ s,  s,  s], [-s,  s,  s],
                [-sm, -l,  sm], [-sm, -l, -sm], [-sm,  -l_max, -sm], [-sm,  -l_max,  sm],
                [ sm, -l, -sm], [ sm, -l,  sm], [ sm,  -l_max,  sm], [ sm,  -l_max, -sm],  
                [-sm, -l_max,  sm], [-sm, -l_max, -sm], [-s,  s, -s], [-s,  s,  s],
                [ sm, -l_max, -sm], [ sm, -l_max,  sm], [ s,  s,  s], [ s,  s, -s]
            ]       
        else:
            nbv=24        
            verts = [ # 6 faces with 4 corners each
                [-s_inf, -l,  s_inf], [-s,  s,  s], [ s,  s,  s], [ s_inf, -l,  s_inf],
                [-s,  s, -s], [-s_inf, -l, -s_inf], [ s_inf, -l, -s_inf], [ s,  s, -s],
                [ s_inf, -l, -s_inf], [-s_inf, -l, -s_inf], [-s_inf, -l,  s_inf], [ s_inf, -l,  s_inf],
                [-s,  s, -s], [ s,  s, -s], [ s,  s,  s], [-s,  s,  s],
                [-s_inf, -l,  s_inf], [-s_inf, -l, -s_inf], [-s,  s, -s], [-s,  s,  s],
                [ s_inf, -l, -s_inf], [ s_inf, -l,  s_inf], [ s,  s,  s], [ s,  s, -s]
            ]
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        for i in range(0, nbv, 4): # All 6 quads (12 triangles)
            indices.append([i, i+2, i+1])
            indices.append([i, i+3, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
Exemple #8
0
def test_readBinary(application):
    reader = STLReader.STLReader(application)
    binary_path = os.path.join(test_path, "simpleTestCubeBinary.stl")
    result = reader.read(binary_path)

    if STLReader.use_numpystl:
        # If the system the test runs on supporst numpy stl, we should also check the non numpy stl option.
        f = open(binary_path, "rb")
        mesh_builder = MeshBuilder()
        reader._loadBinary(mesh_builder, f)
        mesh_builder.calculateNormals(fast=True)

        assert mesh_builder.getVertexCount() != 0
    assert result
Exemple #9
0
def test_readASCII():
    reader = STLReader.STLReader()
    ascii_path = os.path.join(test_path, "simpleTestCubeASCII.stl")
    result = reader.read(ascii_path)
    assert result

    if STLReader.use_numpystl:
        # If the system the test runs on supporst numpy stl, we should also check the non numpy stl option.
        f = open(ascii_path, "rt")
        mesh_builder = MeshBuilder()
        reader._loadAscii(mesh_builder, f)
        mesh_builder.calculateNormals(fast=True)

        assert mesh_builder.getVertexCount() != 0
Exemple #10
0
def test_readASCII(application):
    reader = STLReader.STLReader()
    ascii_path = os.path.join(test_path, "simpleTestCubeASCII.stl")
    result = reader.read(ascii_path)
    assert result

    if STLReader.use_numpystl:
        # If the system the test runs on supports numpy stl, we should also check the non numpy stl option.
        f = open(ascii_path, "rt", encoding = "utf-8")
        mesh_builder = MeshBuilder()
        reader._loadAscii(mesh_builder, f)
        mesh_builder.calculateNormals(fast=True)

        assert mesh_builder.getVertexCount() != 0
Exemple #11
0
    def read(self, file_name):
        #Here you would typically open the file, read its contents, parse it, etc.
        #For this example we will just always create a cube and return that.

        builder = MeshBuilder() #To construct your own mesh, look at the methods provided by MeshBuilder.
        builder.addCube(10, 10, 10, Vector(0, 0, 0)) #Cube of 10 by 10 by 10.
        builder.calculateNormals()

        #Put the mesh inside a scene node.
        result_node = SceneNode()
        result_node.setMeshData(builder.build())
        result_node.setName(file_name) #Typically the file name that the mesh originated from is a good name for the node.

        return result_node
Exemple #12
0
def test_readBinary(application):
    reader = STLReader.STLReader()
    binary_path = os.path.join(test_path, "simpleTestCubeBinary.stl")
    result = reader.read(binary_path)

    if STLReader.use_numpystl:
        # If the system the test runs on supporst numpy stl, we should also check the non numpy stl option.
        f = open(binary_path, "rb")
        mesh_builder = MeshBuilder()
        reader._loadBinary(mesh_builder, f)
        mesh_builder.calculateNormals(fast=True)

        assert mesh_builder.getVertexCount() != 0
    assert result
Exemple #13
0
    def _createPlane(self, size):
        mesh = MeshBuilder()
        s = size / 2
        verts = [  # 1 face with 4 corners
            [-s, 0, -s],
            [s, 0, -s],
            [s, 0, s],
            [-s, 0, s],
        ]
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        for i in range(0, 4, 4):  # All 1 quad (2 triangles)
            indices.append([i, i + 2, i + 1])
            indices.append([i, i + 3, i + 2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
Exemple #14
0
    def setMeshDataFromPywimTriangles(self,
                                      face: pywim.geom.tri.Face,
                                      axis: pywim.geom.Vector = None):

        if len(face.triangles) == 0:
            return

        self.face = face
        self.axis = axis

        mb = MeshBuilder()

        for tri in self.face.triangles:
            mb.addFace(tri.v1, tri.v2, tri.v3)

        mb.calculateNormals()

        self.setMeshData(mb.build())

        self._setupTools()
Exemple #15
0
    def _createPastille(self, size, nb , lg, He):
        mesh = MeshBuilder()
        # Per-vertex normals require duplication of vertices
        r = size / 2
        # First layer length
        sup = -lg + He
        l = -lg
        rng = int(360 / nb)
        ang = math.radians(nb)
        
        verts = []
        for i in range(0, rng):
            # Top
            verts.append([0, sup, 0])
            verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
            verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
            #Side 1a
            verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
            verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
            verts.append([r*math.cos((i+1)*ang), l, r*math.sin((i+1)*ang)])
            #Side 1b
            verts.append([r*math.cos((i+1)*ang), l, r*math.sin((i+1)*ang)])
            verts.append([r*math.cos(i*ang), l, r*math.sin(i*ang)])
            verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
            #Bottom 
            verts.append([0, l, 0])
            verts.append([r*math.cos(i*ang), l, r*math.sin(i*ang)])
            verts.append([r*math.cos((i+1)*ang), l, r*math.sin((i+1)*ang)]) 
            
            
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        # for every angle increment 12 Vertices
        tot = rng * 12
        for i in range(0, tot, 3): # 
            indices.append([i, i+1, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
    def _createCube(self, size, height):
        mesh = MeshBuilder()

        # Can't use MeshBuilder.addCube() because that does not get per-vertex normals
        # Per-vertex normals require duplication of vertices
        s = size / 2
        l = height
        #s_inf=math.tan(math.radians(dep))*l+s
        if self._WiderBase:
            base_size = self._SupportBaseSize/2
        else:
            base_size = s
        if self._DropToBuildplate:
            verts = [ # 6 faces with 4 corners each
                [-base_size, -l,  base_size], [-s,  s,  s], [ s,  s,  s], [ base_size, -l,  base_size],
                [-s,  s, -s], [-base_size, -l, -base_size], [ base_size, -l, -base_size], [ s,  s, -s],
                [ base_size, -l, -base_size], [-base_size, -l, -base_size], [-base_size, -l,  base_size], [ base_size, -l,  base_size],
                [-s,  s, -s], [ s,  s, -s], [ s,  s,  s], [-s,  s,  s],
                [-base_size, -l,  base_size], [-base_size, -l, -base_size], [-s,  s, -s], [-s,  s,  s],
                [ base_size, -l, -base_size], [ base_size, -l,  base_size], [ s,  s,  s], [ s,  s, -s]
            ]
        else:
            verts = [ # 6 faces with 4 corners each
                [-s, -s,  s], [-s,  s,  s], [ s,  s,  s], [ s, -s,  s],
                [-s,  s, -s], [-s, -s, -s], [ s, -s, -s], [ s,  s, -s],
                [ s, -s, -s], [-s, -s, -s], [-s, -s,  s], [ s, -s,  s],
                [-s,  s, -s], [ s,  s, -s], [ s,  s,  s], [-s,  s,  s],
                [-s, -s,  s], [-s, -s, -s], [-s,  s, -s], [-s,  s,  s],
                [ s, -s, -s], [ s, -s,  s], [ s,  s,  s], [ s,  s, -s]
            ]
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        for i in range(0, 24, 4): # All 6 quads (12 triangles)
            indices.append([i, i+2, i+1])
            indices.append([i, i+3, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
Exemple #17
0
    def _createCube(self, size):
        mesh = MeshBuilder()

        # Can't use MeshBuilder.addCube() because that does not get per-vertex normals
        # Per-vertex normals require duplication of vertices
        s = size / 2
        verts = [  # 6 faces with 4 corners each
            [-s, -s, s], [-s, s, s], [s, s, s], [s, -s, s], [-s, s, -s],
            [-s, -s, -s], [s, -s, -s], [s, s, -s], [s, -s, -s], [-s, -s, -s],
            [-s, -s, s], [s, -s, s], [-s, s, -s], [s, s, -s], [s, s, s],
            [-s, s, s], [-s, -s, s], [-s, -s, -s], [-s, s, -s], [-s, s, s],
            [s, -s, -s], [s, -s, s], [s, s, s], [s, s, -s]
        ]
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        for i in range(0, 24, 4):  # All 6 quads (12 triangles)
            indices.append([i, i + 2, i + 1])
            indices.append([i, i + 3, i + 2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
Exemple #18
0
    def _createCube(self, size):
        mesh = MeshBuilder()

        # Can't use MeshBuilder.addCube() because that does not get per-vertex normals
        # Per-vertex normals require duplication of vertices
        s = size / 2
        verts = [ # 6 faces with 4 corners each
            [-s, -s,  s], [-s,  s,  s], [ s,  s,  s], [ s, -s,  s],
            [-s,  s, -s], [-s, -s, -s], [ s, -s, -s], [ s,  s, -s],
            [ s, -s, -s], [-s, -s, -s], [-s, -s,  s], [ s, -s,  s],
            [-s,  s, -s], [ s,  s, -s], [ s,  s,  s], [-s,  s,  s],
            [-s, -s,  s], [-s, -s, -s], [-s,  s, -s], [-s,  s,  s],
            [ s, -s, -s], [ s, -s,  s], [ s,  s,  s], [ s,  s, -s]
        ]
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        for i in range(0, 24, 4): # All 6 quads (12 triangles)
            indices.append([i, i+2, i+1])
            indices.append([i, i+3, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
def test_calculateNormals():
    builder = MeshBuilder()
    # Builder shouldn't start off with normals
    assert not builder.hasNormals()
    # Ensure that if there are no vertices / faces that calling the calculate doesn't break anything.
    builder.calculateNormals()
    assert not builder.hasNormals()

    builder.addFaceByPoints(0, 0, 0, 10, 0, 0, 10, 10, 0)

    builder.calculateNormals()
    assert builder.hasNormals()
    assert numpy.array_equal(builder.getNormals(), numpy.array([[0., 0., 1.], [0., 0., 1.], [0., 0., 1.]]))

    builder2 = MeshBuilder()
    builder2.addFaceByPoints(0, 0, 0, 0, 10, 0, 0, 10, 10)
    builder2.calculateNormals(fast = True)
    assert numpy.array_equal(builder2.getNormals(), numpy.array([[1., 0., 0], [1., 0., 0.], [1., 0., 0.]]))
Exemple #20
0
    def read(self, file_name):
        result = SceneNode()
        # The base object of 3mf is a zipped archive.
        archive = zipfile.ZipFile(file_name, "r")
        try:
            root = ET.parse(archive.open("3D/3dmodel.model"))

            # There can be multiple objects, try to load all of them.
            objects = root.findall("./3mf:resources/3mf:object",
                                   self._namespaces)
            if len(objects) == 0:
                Logger.log(
                    "w",
                    "No objects found in 3MF file %s, either the file is corrupt or you are using an outdated format",
                    file_name)
                return None

            for entry in objects:
                mesh_builder = MeshBuilder()
                node = SceneNode()
                vertex_list = []
                #for vertex in entry.mesh.vertices.vertex:
                for vertex in entry.findall(".//3mf:vertex", self._namespaces):
                    vertex_list.append(
                        [vertex.get("x"),
                         vertex.get("y"),
                         vertex.get("z")])
                    Job.yieldThread()

                triangles = entry.findall(".//3mf:triangle", self._namespaces)
                mesh_builder.reserveFaceCount(len(triangles))

                for triangle in triangles:
                    v1 = int(triangle.get("v1"))
                    v2 = int(triangle.get("v2"))
                    v3 = int(triangle.get("v3"))

                    mesh_builder.addFaceByPoints(
                        vertex_list[v1][0], vertex_list[v1][1],
                        vertex_list[v1][2], vertex_list[v2][0],
                        vertex_list[v2][1], vertex_list[v2][2],
                        vertex_list[v3][0], vertex_list[v3][1],
                        vertex_list[v3][2])

                    Job.yieldThread()

                # Rotate the model; We use a different coordinate frame.
                rotation = Matrix()
                rotation.setByRotationAxis(-0.5 * math.pi, Vector(1, 0, 0))

                # TODO: We currently do not check for normals and simply recalculate them.
                mesh_builder.calculateNormals()
                mesh_builder.setFileName(file_name)
                node.setMeshData(mesh_builder.build().getTransformed(rotation))
                node.setSelectable(True)

                transformations = root.findall(
                    "./3mf:build/3mf:item[@objectid='{0}']".format(
                        entry.get("id")), self._namespaces)
                transformation = transformations[0] if transformations else None
                if transformation is not None and transformation.get(
                        "transform"):
                    splitted_transformation = transformation.get(
                        "transform").split()
                    ## Transformation is saved as:
                    ## M00 M01 M02 0.0
                    ## M10 M11 M12 0.0
                    ## M20 M21 M22 0.0
                    ## M30 M31 M32 1.0
                    ## We switch the row & cols as that is how everyone else uses matrices!
                    temp_mat = Matrix()
                    # Rotation & Scale
                    temp_mat._data[0, 0] = splitted_transformation[0]
                    temp_mat._data[1, 0] = splitted_transformation[1]
                    temp_mat._data[2, 0] = splitted_transformation[2]
                    temp_mat._data[0, 1] = splitted_transformation[3]
                    temp_mat._data[1, 1] = splitted_transformation[4]
                    temp_mat._data[2, 1] = splitted_transformation[5]
                    temp_mat._data[0, 2] = splitted_transformation[6]
                    temp_mat._data[1, 2] = splitted_transformation[7]
                    temp_mat._data[2, 2] = splitted_transformation[8]

                    # Translation
                    temp_mat._data[0, 3] = splitted_transformation[9]
                    temp_mat._data[1, 3] = splitted_transformation[10]
                    temp_mat._data[2, 3] = splitted_transformation[11]

                    node.setTransformation(temp_mat)

                result.addChild(node)

                Job.yieldThread()

            # If there is more then one object, group them.
            if len(objects) > 1:
                group_decorator = GroupDecorator()
                result.addDecorator(group_decorator)
            elif len(objects) == 1:
                result = result.getChildren()[
                    0]  # Only one object found, return that.
        except Exception as e:
            Logger.log("e", "exception occured in 3mf reader: %s", e)

        try:  # Selftest - There might be more functions that should fail
            boundingBox = result.getBoundingBox()
            boundingBox.isValid()
        except:
            return None

        return result
Exemple #21
0
    def _generateSceneNode(self, file_name, offset, peak_height, slopeHeight,
                           closeTopButtonFace, reversePathToration, splitWord):
        Job.yieldThread()
        if not splitWord:
            scene_node = SceneNode()
            mesh = MeshBuilder()
        else:
            scene_node = []
        areaTop = 0
        areaBottom = 0
        pathDetectNotEqual = False
        for subPaths in self._paths:
            if splitWord:
                mesh = MeshBuilder()
            pros = self._vu._gen_offset_paths(subPaths)
            clocks = []
            for path in subPaths:
                reverse = file_name.endswith('.nc')
                if reverse == (not reversePathToration):
                    path.reverse()
                (clock, holePoint) = self._vu.clockWish(path)
                clocks.append(clock)

            lastPaths = self._vu._exec_offset(pros, clocks, 0)
            if offset != 0:
                currPaths = lastPaths
                self._vu.addSidFaces(lastPaths, currPaths, clocks, mesh, 0,
                                     peak_height - slopeHeight)
                currPaths = self._vu._exec_offset(pros, clocks, offset)
                pathDetectNotEqual = self._vu.addSidFaces(
                    lastPaths, currPaths, clocks, mesh,
                    peak_height - slopeHeight, peak_height)
            else:
                currPaths = lastPaths
                self._vu.addSidFaces(lastPaths, currPaths, clocks, mesh, 0,
                                     peak_height)
            if closeTopButtonFace:
                areaTop += self._vu.addTopButtonFace(True, currPaths, mesh,
                                                     peak_height)
                areaBottom += self._vu.addTopButtonFace(
                    False, lastPaths, mesh, 0)
            if splitWord:
                mesh.calculateNormals(fast=True)
                _sceneNode = SceneNode()
                _sceneNode.setMeshData(mesh.build())
                scene_node.append(_sceneNode)
        if not splitWord:
            mesh.calculateNormals(fast=True)
            scene_node.setMeshData(mesh.build())
        else:
            scene_node.reverse()
        if closeTopButtonFace:
            if pathDetectNotEqual:
                m = Message(i18n_catalog.i18nc(
                    '@info:status',
                    'Top/Buttom area :{} mm\xc2\xb2 ,{} mm\xc2\xb2\n There may be broken, please reduce the offset',
                    round(areaTop, 2), round(areaBottom, 2)),
                            lifetime=0)
            else:
                m = Message(i18n_catalog.i18nc(
                    '@info:status',
                    'Top/Buttom area :{} mm\xc2\xb2 ,{} mm\xc2\xb2',
                    round(areaTop, 2), round(areaBottom, 2)),
                            lifetime=0)
            m.addAction(
                'regenerate', i18n_catalog.i18nc('@action:button',
                                                 'regenerate'), 'regenerate',
                i18n_catalog.i18nc('@info:tooltip', 'Regenerating model'))
            m._filename = file_name
            m.actionTriggered.connect(self._onMessageActionTriggered)
            m.show()
        return scene_node
Exemple #22
0
    def _createCustom(self, size, maxs, pos1 , pos2, dep, ztop):
        mesh = MeshBuilder()
        # Init point
        Pt1 = Vector(pos1.x,pos1.z,pos1.y)
        Pt2 = Vector(pos2.x,pos2.z,pos2.y)

        V_Dir = Pt2 - Pt1

        # Calcul vecteur
        s = size / 2
        sm = maxs / 2
        l_a = pos1.y 
        s_infa=math.tan(math.radians(dep))*l_a+s
        l_b = pos2.y 
        s_infb=math.tan(math.radians(dep))*l_b+s
 
        if sm>s and dep!=0:
            l_max_a=(sm-s) / math.tan(math.radians(dep))
            l_max_b=(sm-s) / math.tan(math.radians(dep))
        else :
            l_max_a=l_a
            l_max_b=l_b
 
        Vtop = Vector(0,0,ztop)
        VZ = Vector(0,0,s)
        VZa = Vector(0,0,-l_a)
        VZb = Vector(0,0,-l_b)
        
        Norm=Vector.cross(V_Dir,VZ).normalized()
        Dec = Vector(Norm.x*s,Norm.y*s,Norm.z*s)
            
        if l_max_a<l_a and l_max_b<l_b and l_max_a>0 and l_max_b>0: 
            nbv=40
            
            Deca = Vector(Norm.x*sm,Norm.y*sm,Norm.z*sm)
            Decb = Vector(Norm.x*sm,Norm.y*sm,Norm.z*sm)

            VZam = Vector(0,0,-l_max_a)
            VZbm = Vector(0,0,-l_max_b)
        
            # X Z Y
            P_1t = Vtop+Dec
            P_2t = Vtop-Dec
            P_3t = V_Dir+Vtop+Dec
            P_4t = V_Dir+Vtop-Dec
 
            P_1m = VZam+Deca
            P_2m = VZam-Deca
            P_3m = VZbm+V_Dir+Decb
            P_4m = VZbm+V_Dir-Decb
            
            P_1i = VZa+Deca
            P_2i = VZa-Deca
            P_3i = VZb+V_Dir+Decb
            P_4i = VZb+V_Dir-Decb
             
            """
            1) Top
            2) Front
            3) Left
            4) Right
            5) Back 
            6) Front inf
            7) Left inf
            8) Right inf
            9) Back inf
            10) Bottom
            """
            verts = [ # 10 faces with 4 corners each
                [P_1t.x, P_1t.z, P_1t.y], [P_2t.x, P_2t.z, P_2t.y], [P_4t.x, P_4t.z, P_4t.y], [P_3t.x, P_3t.z, P_3t.y],              
                [P_1t.x, P_1t.z, P_1t.y], [P_3t.x, P_3t.z, P_3t.y], [P_3m.x, P_3m.z, P_3m.y], [P_1m.x, P_1m.z, P_1m.y],
                [P_2t.x, P_2t.z, P_2t.y], [P_1t.x, P_1t.z, P_1t.y], [P_1m.x, P_1m.z, P_1m.y], [P_2m.x, P_2m.z, P_2m.y],
                [P_3t.x, P_3t.z, P_3t.y], [P_4t.x, P_4t.z, P_4t.y], [P_4m.x, P_4m.z, P_4m.y], [P_3m.x, P_3m.z, P_3m.y],
                [P_4t.x, P_4t.z, P_4t.y], [P_2t.x, P_2t.z, P_2t.y], [P_2m.x, P_2m.z, P_2m.y], [P_4m.x, P_4m.z, P_4m.y],
                [P_1m.x, P_1m.z, P_1m.y], [P_3m.x, P_3m.z, P_3m.y], [P_3i.x, P_3i.z, P_3i.y], [P_1i.x, P_1i.z, P_1i.y],
                [P_2m.x, P_2m.z, P_2m.y], [P_1m.x, P_1m.z, P_1m.y], [P_1i.x, P_1i.z, P_1i.y], [P_2i.x, P_2i.z, P_2i.y],
                [P_3m.x, P_3m.z, P_3m.y], [P_4m.x, P_4m.z, P_4m.y], [P_4i.x, P_4i.z, P_4i.y], [P_3i.x, P_3i.z, P_3i.y],
                [P_4m.x, P_4m.z, P_4m.y], [P_2m.x, P_2m.z, P_2m.y], [P_2i.x, P_2i.z, P_2i.y], [P_4i.x, P_4i.z, P_4i.y],
                [P_1i.x, P_1i.z, P_1i.y], [P_2i.x, P_2i.z, P_2i.y], [P_4i.x, P_4i.z, P_4i.y], [P_3i.x, P_3i.z, P_3i.y]
            ]
            
        else:
            nbv=24

            Deca = Vector(Norm.x*s_infa,Norm.y*s_infa,Norm.z*s_infa)
            Decb = Vector(Norm.x*s_infb,Norm.y*s_infb,Norm.z*s_infb)

            # X Z Y
            P_1t = Vtop+Dec
            P_2t = Vtop-Dec
            P_3t = V_Dir+Vtop+Dec
            P_4t = V_Dir+Vtop-Dec
     
            P_1i = VZa+Deca
            P_2i = VZa-Deca
            P_3i = VZb+V_Dir+Decb
            P_4i = VZb+V_Dir-Decb
             
            """
            1) Top
            2) Front
            3) Left
            4) Right
            5) Back 
            6) Bottom
            """
            verts = [ # 6 faces with 4 corners each
                [P_1t.x, P_1t.z, P_1t.y], [P_2t.x, P_2t.z, P_2t.y], [P_4t.x, P_4t.z, P_4t.y], [P_3t.x, P_3t.z, P_3t.y],
                [P_1t.x, P_1t.z, P_1t.y], [P_3t.x, P_3t.z, P_3t.y], [P_3i.x, P_3i.z, P_3i.y], [P_1i.x, P_1i.z, P_1i.y],
                [P_2t.x, P_2t.z, P_2t.y], [P_1t.x, P_1t.z, P_1t.y], [P_1i.x, P_1i.z, P_1i.y], [P_2i.x, P_2i.z, P_2i.y],
                [P_3t.x, P_3t.z, P_3t.y], [P_4t.x, P_4t.z, P_4t.y], [P_4i.x, P_4i.z, P_4i.y], [P_3i.x, P_3i.z, P_3i.y],
                [P_4t.x, P_4t.z, P_4t.y], [P_2t.x, P_2t.z, P_2t.y], [P_2i.x, P_2i.z, P_2i.y], [P_4i.x, P_4i.z, P_4i.y],
                [P_1i.x, P_1i.z, P_1i.y], [P_2i.x, P_2i.z, P_2i.y], [P_4i.x, P_4i.z, P_4i.y], [P_3i.x, P_3i.z, P_3i.y]
            ]
        
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        for i in range(0, nbv, 4): # All 6 quads (12 triangles)
            indices.append([i, i+2, i+1])
            indices.append([i, i+3, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
Exemple #23
0
    def _convertSavitarNodeToUMNode(
            self,
            savitar_node: Savitar.SceneNode,
            file_name: str = "") -> Optional[SceneNode]:
        node_name = savitar_node.getName()
        node_id = savitar_node.getId()
        if node_name == "":
            if file_name != "":
                node_name = os.path.basename(file_name)
            else:
                node_name = "Object {}".format(node_id)

        active_build_plate = CuraApplication.getInstance(
        ).getMultiBuildPlateModel().activeBuildPlate

        um_node = CuraSceneNode()  # This adds a SettingOverrideDecorator
        um_node.addDecorator(BuildPlateDecorator(active_build_plate))
        um_node.setName(node_name)
        um_node.setId(node_id)
        transformation = self._createMatrixFromTransformationString(
            savitar_node.getTransformation())
        um_node.setTransformation(transformation)
        mesh_builder = MeshBuilder()

        data = numpy.fromstring(
            savitar_node.getMeshData().getFlatVerticesAsBytes(),
            dtype=numpy.float32)

        vertices = numpy.resize(data, (int(data.size / 3), 3))
        mesh_builder.setVertices(vertices)
        mesh_builder.calculateNormals(fast=True)
        if file_name:
            # The filename is used to give the user the option to reload the file if it is changed on disk
            # It is only set for the root node of the 3mf file
            mesh_builder.setFileName(file_name)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            um_node.setMeshData(mesh_data)

        for child in savitar_node.getChildren():
            child_node = self._convertSavitarNodeToUMNode(child)
            if child_node:
                um_node.addChild(child_node)

        if um_node.getMeshData() is None and len(um_node.getChildren()) == 0:
            return None

        settings = savitar_node.getSettings()

        # Add the setting override decorator, so we can add settings to this node.
        if settings:
            global_container_stack = CuraApplication.getInstance(
            ).getGlobalContainerStack()

            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                default_stack = ExtruderManager.getInstance().getExtruderStack(
                    0)

                if default_stack:
                    um_node.callDecoration("setActiveExtruder",
                                           default_stack.getId())

                # Get the definition & set it
                definition_id = ContainerTree.getInstance().machines[
                    global_container_stack.definition.getId(
                    )].quality_definition
                um_node.callDecoration("getStack").getTop().setDefinition(
                    definition_id)

            setting_container = um_node.callDecoration("getStack").getTop()

            for key in settings:
                setting_value = settings[key]

                # Extruder_nr is a special case.
                if key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance(
                    ).getExtruderStack(int(setting_value))
                    if extruder_stack:
                        um_node.callDecoration("setActiveExtruder",
                                               extruder_stack.getId())
                    else:
                        Logger.log("w",
                                   "Unable to find extruder in position %s",
                                   setting_value)
                    continue
                setting_container.setProperty(key, "value", setting_value)

        if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None:
            group_decorator = GroupDecorator()
            um_node.addDecorator(group_decorator)
        um_node.setSelectable(True)
        if um_node.getMeshData():
            # Assuming that all nodes with mesh data are printable objects
            # affects (auto) slicing
            sliceable_decorator = SliceableObjectDecorator()
            um_node.addDecorator(sliceable_decorator)
        return um_node
Exemple #24
0
    def _convertSavitarNodeToUMNode(self, savitar_node):
        um_node = SceneNode()
        transformation = self._createMatrixFromTransformationString(
            savitar_node.getTransformation())
        um_node.setTransformation(transformation)
        mesh_builder = MeshBuilder()

        data = numpy.fromstring(
            savitar_node.getMeshData().getFlatVerticesAsBytes(),
            dtype=numpy.float32)

        vertices = numpy.resize(data, (int(data.size / 3), 3))
        mesh_builder.setVertices(vertices)
        mesh_builder.calculateNormals(fast=True)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            um_node.setMeshData(mesh_data)

        for child in savitar_node.getChildren():
            child_node = self._convertSavitarNodeToUMNode(child)
            if child_node:
                um_node.addChild(child_node)

        if um_node.getMeshData() is None and len(um_node.getChildren()) == 0:
            return None

        settings = savitar_node.getSettings()

        # Add the setting override decorator, so we can add settings to this node.
        if settings:
            um_node.addDecorator(SettingOverrideDecorator())

            global_container_stack = Application.getInstance(
            ).getGlobalContainerStack()

            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                default_stack = ExtruderManager.getInstance().getExtruderStack(
                    0)

                if default_stack:
                    um_node.callDecoration("setActiveExtruder",
                                           default_stack.getId())

                # Get the definition & set it
                definition = QualityManager.getInstance(
                ).getParentMachineDefinition(
                    global_container_stack.getBottom())
                um_node.callDecoration("getStack").getTop().setDefinition(
                    definition.getId())

            setting_container = um_node.callDecoration("getStack").getTop()

            for key in settings:
                setting_value = settings[key]

                # Extruder_nr is a special case.
                if key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance(
                    ).getExtruderStack(int(setting_value))
                    if extruder_stack:
                        um_node.callDecoration("setActiveExtruder",
                                               extruder_stack.getId())
                    else:
                        Logger.log("w",
                                   "Unable to find extruder in position %s",
                                   setting_value)
                    continue
                setting_container.setProperty(key, "value", setting_value)

        if len(um_node.getChildren()) > 0:
            group_decorator = GroupDecorator()
            um_node.addDecorator(group_decorator)
        um_node.setSelectable(True)
        if um_node.getMeshData():
            # Assuming that all nodes with mesh data are printable objects
            # affects (auto) slicing
            sliceable_decorator = SliceableObjectDecorator()
            um_node.addDecorator(sliceable_decorator)
        return um_node
Exemple #25
0
    def read(self, file_name):
        result = SceneNode()
        # The base object of 3mf is a zipped archive.
        archive = zipfile.ZipFile(file_name, "r")
        try:
            root = ET.parse(archive.open("3D/3dmodel.model"))

            # There can be multiple objects, try to load all of them.
            objects = root.findall("./3mf:resources/3mf:object", self._namespaces)
            if len(objects) == 0:
                Logger.log("w", "No objects found in 3MF file %s, either the file is corrupt or you are using an outdated format", file_name)
                return None

            for entry in objects:
                mesh_builder = MeshBuilder()
                node = SceneNode()
                vertex_list = []
                #for vertex in entry.mesh.vertices.vertex:
                for vertex in entry.findall(".//3mf:vertex", self._namespaces):
                    vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
                    Job.yieldThread()

                triangles = entry.findall(".//3mf:triangle", self._namespaces)
                mesh_builder.reserveFaceCount(len(triangles))

                #for triangle in object.mesh.triangles.triangle:
                for triangle in triangles:
                    v1 = int(triangle.get("v1"))
                    v2 = int(triangle.get("v2"))
                    v3 = int(triangle.get("v3"))

                    mesh_builder.addFaceByPoints(vertex_list[v1][0], vertex_list[v1][1], vertex_list[v1][2],
                                                 vertex_list[v2][0], vertex_list[v2][1], vertex_list[v2][2],
                                                 vertex_list[v3][0], vertex_list[v3][1], vertex_list[v3][2])

                    Job.yieldThread()

                # Rotate the model; We use a different coordinate frame.
                rotation = Matrix()
                rotation.setByRotationAxis(-0.5 * math.pi, Vector(1,0,0))

                #TODO: We currently do not check for normals and simply recalculate them.
                mesh_builder.calculateNormals()

                node.setMeshData(mesh_builder.build().getTransformed(rotation))
                node.setSelectable(True)

                transformations = root.findall("./3mf:build/3mf:item[@objectid='{0}']".format(entry.get("id")), self._namespaces)
                transformation = transformations[0] if transformations else None
                if transformation is not None and transformation.get("transform"):
                    splitted_transformation = transformation.get("transform").split()
                    ## Transformation is saved as:
                    ## M00 M01 M02 0.0
                    ## M10 M11 M12 0.0
                    ## M20 M21 M22 0.0
                    ## M30 M31 M32 1.0
                    ## We switch the row & cols as that is how everyone else uses matrices!
                    temp_mat = Matrix()
                    # Rotation & Scale
                    temp_mat._data[0,0] = splitted_transformation[0]
                    temp_mat._data[1,0] = splitted_transformation[1]
                    temp_mat._data[2,0] = splitted_transformation[2]
                    temp_mat._data[0,1] = splitted_transformation[3]
                    temp_mat._data[1,1] = splitted_transformation[4]
                    temp_mat._data[2,1] = splitted_transformation[5]
                    temp_mat._data[0,2] = splitted_transformation[6]
                    temp_mat._data[1,2] = splitted_transformation[7]
                    temp_mat._data[2,2] = splitted_transformation[8]

                    # Translation
                    temp_mat._data[0,3] = splitted_transformation[9]
                    temp_mat._data[1,3] = splitted_transformation[10]
                    temp_mat._data[2,3] = splitted_transformation[11]

                    node.setTransformation(temp_mat)

                result.addChild(node)

                Job.yieldThread()

            #If there is more then one object, group them.
            if len(objects) > 1:
                group_decorator = GroupDecorator()
                result.addDecorator(group_decorator)
        except Exception as e:
            Logger.log("e" ,"exception occured in 3mf reader: %s" , e)

        return result  
Exemple #26
0
    def read(self, file_name):
        scene_node = None

        extension = os.path.splitext(file_name)[1]
        if extension.lower() in self._supported_extensions:
            vertex_list = []
            normal_list = []
            uv_list = []
            face_list = []
            scene_node = SceneNode()

            mesh_builder = MeshBuilder()
            mesh_builder.setFileName(file_name)
            f = open(file_name, "rt")
            for line in f:
                parts = line.split()
                if len(parts) < 1:
                    continue
                if parts[0] == "v":
                    vertex_list.append(
                        [float(parts[1]),
                         float(parts[3]), -float(parts[2])])
                if parts[0] == "vn":
                    normal_list.append(
                        [float(parts[1]),
                         float(parts[3]), -float(parts[2])])
                if parts[0] == "vt":
                    uv_list.append([float(parts[1]), float(parts[2])])
                if parts[0] == "f":
                    parts = [i for i in map(lambda p: p.split("/"), parts)]
                    for idx in range(1, len(parts) - 2):
                        data = [
                            int(parts[1][0]),
                            int(parts[idx + 1][0]),
                            int(parts[idx + 2][0])
                        ]
                        if len(parts[1]) > 2:
                            data += [
                                int(parts[1][2]),
                                int(parts[idx + 1][2]),
                                int(parts[idx + 2][2])
                            ]

                            if parts[1][1] and parts[idx +
                                                     1][1] and parts[idx +
                                                                     2][1]:
                                data += [
                                    int(parts[1][1]),
                                    int(parts[idx + 1][1]),
                                    int(parts[idx + 2][1])
                                ]
                        face_list.append(data)
                Job.yieldThread()
            f.close()

            mesh_builder.reserveVertexCount(3 * len(face_list))
            num_vertices = len(vertex_list)
            num_normals = len(normal_list)

            for face in face_list:
                # Substract 1 from index, as obj starts counting at 1 instead of 0
                i = face[0] - 1
                j = face[1] - 1
                k = face[2] - 1

                if len(face) > 3:
                    ni = face[3] - 1
                    nj = face[4] - 1
                    nk = face[5] - 1
                else:
                    ni = -1
                    nj = -1
                    nk = -1

                if len(face) > 6:
                    ui = face[6] - 1
                    uj = face[7] - 1
                    uk = face[8] - 1
                else:
                    ui = -1
                    uj = -1
                    uk = -1

                #TODO: improve this handling, this can cause weird errors (negative indexes are relative indexes, and are not properly handled)
                if i < 0 or i >= num_vertices:
                    i = 0
                if j < 0 or j >= num_vertices:
                    j = 0
                if k < 0 or k >= num_vertices:
                    k = 0
                if ni != -1 and nj != -1 and nk != -1:
                    mesh_builder.addFaceWithNormals(
                        vertex_list[i][0], vertex_list[i][1],
                        vertex_list[i][2], normal_list[ni][0],
                        normal_list[ni][1], normal_list[ni][2],
                        vertex_list[j][0], vertex_list[j][1],
                        vertex_list[j][2], normal_list[nj][0],
                        normal_list[nj][1], normal_list[nj][2],
                        vertex_list[k][0], vertex_list[k][1],
                        vertex_list[k][2], normal_list[nk][0],
                        normal_list[nk][1], normal_list[nk][2])
                else:
                    mesh_builder.addFaceByPoints(
                        vertex_list[i][0], vertex_list[i][1],
                        vertex_list[i][2], vertex_list[j][0],
                        vertex_list[j][1], vertex_list[j][2],
                        vertex_list[k][0], vertex_list[k][1],
                        vertex_list[k][2])

                if ui != -1:
                    mesh_builder.setVertexUVCoordinates(
                        mesh_builder.getVertexCount() - 3, uv_list[ui][0],
                        uv_list[ui][1])

                if uj != -1:
                    mesh_builder.setVertexUVCoordinates(
                        mesh_builder.getVertexCount() - 2, uv_list[uj][0],
                        uv_list[uj][1])

                if uk != -1:
                    mesh_builder.setVertexUVCoordinates(
                        mesh_builder.getVertexCount() - 1, uv_list[uk][0],
                        uv_list[uk][1])

                Job.yieldThread()
            if not mesh_builder.hasNormals():
                mesh_builder.calculateNormals(fast=True)
            scene_node.setMeshData(mesh_builder.build())

        return scene_node
    def read(self, file_name):
        scene_node = None

        extension = os.path.splitext(file_name)[1]
        if extension.lower() in self._supported_extensions:
            vertex_list = []
            normal_list = []
            uv_list = []
            face_list = []
            scene_node = SceneNode()

            mesh_builder = MeshBuilder()
            mesh_builder.setFileName(file_name)
            f = open(file_name, "rt")
            for line in f:
                parts = line.split()
                if len(parts) < 1:
                    continue
                if parts[0] == "v":
                    vertex_list.append([float(parts[1]), float(parts[3]), -float(parts[2])])
                if parts[0] == "vn":
                    normal_list.append([float(parts[1]), float(parts[3]), -float(parts[2])])
                if parts[0] == "vt":
                    uv_list.append([float(parts[1]), float(parts[2])])
                if parts[0] == "f":
                    parts = [i for i in map(lambda p: p.split("/"), parts)]
                    for idx in range(1, len(parts)-2):
                        data = [int(parts[1][0]), int(parts[idx+1][0]), int(parts[idx+2][0])]
                        if len(parts[1]) > 2:
                            data += [int(parts[1][2]), int(parts[idx+1][2]), int(parts[idx+2][2])]

                            if parts[1][1] and parts[idx+1][1] and parts[idx+2][1]:
                                data += [int(parts[1][1]), int(parts[idx+1][1]), int(parts[idx+2][1])]
                        face_list.append(data)
                Job.yieldThread()
            f.close()

            mesh_builder.reserveVertexCount(3 * len(face_list))
            num_vertices = len(vertex_list)
            num_normals = len(normal_list)

            for face in face_list:
                # Substract 1 from index, as obj starts counting at 1 instead of 0
                i = face[0] - 1
                j = face[1] - 1
                k = face[2] - 1

                if len(face) > 3:
                    ni = face[3] - 1
                    nj = face[4] - 1
                    nk = face[5] - 1
                else:
                    ni = -1
                    nj = -1
                    nk = -1

                if len(face) > 6:
                    ui = face[6] - 1
                    uj = face[7] - 1
                    uk = face[8] - 1
                else:
                    ui = -1
                    uj = -1
                    uk = -1

                #TODO: improve this handling, this can cause weird errors (negative indexes are relative indexes, and are not properly handled)
                if i < 0 or i >= num_vertices:
                    i = 0
                if j < 0 or j >= num_vertices:
                    j = 0
                if k < 0 or k >= num_vertices:
                    k = 0
                if ni != -1 and nj != -1 and nk != -1:
                    mesh_builder.addFaceWithNormals(vertex_list[i][0], vertex_list[i][1], vertex_list[i][2], normal_list[ni][0], normal_list[ni][1], normal_list[ni][2], vertex_list[j][0], vertex_list[j][1], vertex_list[j][2], normal_list[nj][0], normal_list[nj][1], normal_list[nj][2], vertex_list[k][0], vertex_list[k][1], vertex_list[k][2],normal_list[nk][0], normal_list[nk][1], normal_list[nk][2])
                else:
                    mesh_builder.addFaceByPoints(vertex_list[i][0], vertex_list[i][1], vertex_list[i][2], vertex_list[j][0], vertex_list[j][1], vertex_list[j][2], vertex_list[k][0], vertex_list[k][1], vertex_list[k][2])

                if ui != -1:
                    mesh_builder.setVertexUVCoordinates(mesh_builder.getVertexCount() - 3, uv_list[ui][0], uv_list[ui][1])

                if uj != -1:
                    mesh_builder.setVertexUVCoordinates(mesh_builder.getVertexCount() - 2, uv_list[uj][0], uv_list[uj][1])

                if uk != -1:
                    mesh_builder.setVertexUVCoordinates(mesh_builder.getVertexCount() - 1, uv_list[uk][0], uv_list[uk][1])

                Job.yieldThread()
            if not mesh_builder.hasNormals():
                mesh_builder.calculateNormals(fast = True)
            scene_node.setMeshData(mesh_builder.build())

        return scene_node
    def _createCylinder(self, size, nb , height):
        mesh = MeshBuilder()
        # Per-vertex normals require duplication of vertices
        r = size / 2
        # additionale length
        sup = size * 0.1
        l = -height
        rng = int(360 / nb)
        ang = math.radians(nb)
        verts = []
        
        if self._WiderBase:
            r_base = self._SupportBaseSize/2
        else:
            r_base = r

        if self._DropToBuildplate:
            for i in range(0, rng):
                # Top
                verts.append([0, sup, 0])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                #Side 1a
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([r_base*math.cos((i+1)*ang), l, r_base*math.sin((i+1)*ang)])
                #Side 1b
                verts.append([r_base*math.cos((i+1)*ang), l, r_base*math.sin((i+1)*ang)])
                verts.append([r_base*math.cos(i*ang), l, r_base*math.sin(i*ang)])
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                #Bottom 
                verts.append([0, l, 0])
                verts.append([r_base*math.cos((i+1)*ang), l, r_base*math.sin((i+1)*ang)]) 
                verts.append([r_base*math.cos(i*ang), l, r_base*math.sin(i*ang)])
        else:
            for i in range(0, rng):
                # Top
                verts.append([0, sup, 0])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                #Side 1a
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([r*math.cos((i+1)*ang), -size, r*math.sin((i+1)*ang)])
                #Side 1b
                verts.append([r*math.cos((i+1)*ang), -size, r*math.sin((i+1)*ang)])
                verts.append([r*math.cos(i*ang), -size, r*math.sin(i*ang)])
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                #Bottom 
                verts.append([0, -size, 0])
                verts.append([r*math.cos((i+1)*ang), -size, r*math.sin((i+1)*ang)]) 
                verts.append([r*math.cos(i*ang), -size, r*math.sin(i*ang)])
        
        
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))
        indices = []
        # for every angle increment 12 Vertices
        tot = rng * 12
        for i in range(0, tot, 3): # 
            indices.append([i, i+1, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))
        mesh.calculateNormals()
        return mesh
Exemple #29
0
    def _createTube(self, size, maxs, isize, nb , lg ,dep):
        # Logger.log('d', 'isize : ' + str(isize)) 
        mesh = MeshBuilder()
        # Per-vertex normals require duplication of vertices
        r = size / 2
        ri = isize / 2
        rm = maxs / 2
        # additionale length
        sup = size * 0.1
        l = -lg
        rng = int(360 / nb)
        ang = math.radians(nb)
        r_inf=math.tan(math.radians(dep))*lg+r
        if rm>r and dep!=0:
            l_max=(rm-r) / math.tan(math.radians(dep))
        else :
            l_max=l
            
        verts = []
        if l_max<lg and l_max>0:
            nbv=30
            for i in range(0, rng):
                # Top
                verts.append([ri*math.cos(i*ang), sup, ri*math.sin(i*ang)])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                
                verts.append([ri*math.cos((i+1)*ang), sup, ri*math.sin((i+1)*ang)])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([ri*math.cos(i*ang), sup, ri*math.sin(i*ang)])

                #Side 1a
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([rm*math.cos((i+1)*ang), -l_max, rm*math.sin((i+1)*ang)])
                
                #Side 1b
                verts.append([rm*math.cos((i+1)*ang), -l_max, rm*math.sin((i+1)*ang)])
                verts.append([rm*math.cos(i*ang), -l_max, rm*math.sin(i*ang)])
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                
                #Side 2a
                verts.append([rm*math.cos(i*ang), -l_max, rm*math.sin(i*ang)])
                verts.append([rm*math.cos((i+1)*ang), -l_max, rm*math.sin((i+1)*ang)])
                verts.append([rm*math.cos((i+1)*ang), l, rm*math.sin((i+1)*ang)])
                
                #Side 2b
                verts.append([rm*math.cos((i+1)*ang), l, rm*math.sin((i+1)*ang)])
                verts.append([rm*math.cos(i*ang), l, rm*math.sin(i*ang)])
                verts.append([rm*math.cos(i*ang), -l_max, rm*math.sin(i*ang)])
                
                #Bottom 
                verts.append([ri*math.cos(i*ang), l, ri*math.sin(i*ang)])
                verts.append([rm*math.cos(i*ang), l, rm*math.sin(i*ang)])
                verts.append([rm*math.cos((i+1)*ang), l, rm*math.sin((i+1)*ang)]) 
                
                verts.append([ri*math.cos((i+1)*ang), l, ri*math.sin((i+1)*ang)])
                verts.append([ri*math.cos(i*ang), l, ri*math.sin(i*ang)])
                verts.append([rm*math.cos((i+1)*ang), l, rm*math.sin((i+1)*ang)]) 
                
                #Side Inta
                verts.append([ri*math.cos(i*ang), sup, ri*math.sin(i*ang)])
                verts.append([ri*math.cos((i+1)*ang), l, ri*math.sin((i+1)*ang)])
                verts.append([ri*math.cos((i+1)*ang), sup, ri*math.sin((i+1)*ang)])
                
                #Side Intb
                verts.append([ri*math.cos((i+1)*ang), l, ri*math.sin((i+1)*ang)])
                verts.append([ri*math.cos(i*ang), sup, ri*math.sin(i*ang)])
                verts.append([ri*math.cos(i*ang), l, ri*math.sin(i*ang)])
                
        else:
            nbv=24
            for i in range(0, rng):
                # Top
                verts.append([ri*math.cos(i*ang), sup, ri*math.sin(i*ang)])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                
                verts.append([ri*math.cos((i+1)*ang), sup, ri*math.sin((i+1)*ang)])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([ri*math.cos(i*ang), sup, ri*math.sin(i*ang)])
                
                #Side 1a
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                verts.append([r*math.cos((i+1)*ang), sup, r*math.sin((i+1)*ang)])
                verts.append([r_inf*math.cos((i+1)*ang), l, r_inf*math.sin((i+1)*ang)])
                
                #Side 1b
                verts.append([r_inf*math.cos((i+1)*ang), l, r_inf*math.sin((i+1)*ang)])
                verts.append([r_inf*math.cos(i*ang), l, r_inf*math.sin(i*ang)])
                verts.append([r*math.cos(i*ang), sup, r*math.sin(i*ang)])
                
                #Bottom 
                verts.append([ri*math.cos(i*ang), l, ri*math.sin(i*ang)])
                verts.append([r_inf*math.cos(i*ang), l, r_inf*math.sin(i*ang)])
                verts.append([r_inf*math.cos((i+1)*ang), l, r_inf*math.sin((i+1)*ang)]) 
                
                verts.append([ri*math.cos((i+1)*ang), l, ri*math.sin((i+1)*ang)])
                verts.append([ri*math.cos(i*ang), l, ri*math.sin(i*ang)])
                verts.append([r_inf*math.cos((i+1)*ang), l, r_inf*math.sin((i+1)*ang)]) 
                
                #Side Inta
                verts.append([ri*math.cos(i*ang), sup, ri*math.sin(i*ang)])
                verts.append([ri*math.cos((i+1)*ang), l, ri*math.sin((i+1)*ang)])
                verts.append([ri*math.cos((i+1)*ang), sup, ri*math.sin((i+1)*ang)])
                
                #Side Intb
                verts.append([ri*math.cos((i+1)*ang), l, ri*math.sin((i+1)*ang)])
                verts.append([ri*math.cos(i*ang), sup, ri*math.sin(i*ang)])
                verts.append([ri*math.cos(i*ang), l, ri*math.sin(i*ang)])

        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        # for every angle increment ( 24  or 30 ) Vertices
        tot = rng * nbv
        for i in range(0, tot, 3): # 
            indices.append([i, i+1, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
Exemple #30
0
    def _generateSceneNode(self, file_name, xz_size, peak_height, base_height,
                           blur_iterations, max_size, lighter_is_higher,
                           use_transparency_model, transmittance_1mm):
        scene_node = SceneNode()

        mesh = MeshBuilder()

        img = QImage(file_name)

        if img.isNull():
            Logger.log("e", "Image is corrupt.")
            return None

        width = max(img.width(), 2)
        height = max(img.height(), 2)
        aspect = height / width

        if img.width() < 2 or img.height() < 2:
            img = img.scaled(width, height, Qt.IgnoreAspectRatio)

        base_height = max(base_height, 0)
        peak_height = max(peak_height, -base_height)

        xz_size = max(xz_size, 1)
        scale_vector = Vector(xz_size, peak_height, xz_size)

        if width > height:
            scale_vector = scale_vector.set(z=scale_vector.z * aspect)
        elif height > width:
            scale_vector = scale_vector.set(x=scale_vector.x / aspect)

        if width > max_size or height > max_size:
            scale_factor = max_size / width
            if height > width:
                scale_factor = max_size / height

            width = int(max(round(width * scale_factor), 2))
            height = int(max(round(height * scale_factor), 2))
            img = img.scaled(width, height, Qt.IgnoreAspectRatio)

        width_minus_one = width - 1
        height_minus_one = height - 1

        Job.yieldThread()

        texel_width = 1.0 / (width_minus_one) * scale_vector.x
        texel_height = 1.0 / (height_minus_one) * scale_vector.z

        height_data = numpy.zeros((height, width), dtype=numpy.float32)

        for x in range(0, width):
            for y in range(0, height):
                qrgb = img.pixel(x, y)
                if use_transparency_model:
                    height_data[y, x] = (
                        0.299 * math.pow(qRed(qrgb) / 255.0, 2.2) +
                        0.587 * math.pow(qGreen(qrgb) / 255.0, 2.2) +
                        0.114 * math.pow(qBlue(qrgb) / 255.0, 2.2))
                else:
                    height_data[y, x] = (
                        0.212655 * qRed(qrgb) + 0.715158 * qGreen(qrgb) +
                        0.072187 * qBlue(qrgb)
                    ) / 255  # fast computation ignoring gamma and degamma

        Job.yieldThread()

        if lighter_is_higher == use_transparency_model:
            height_data = 1 - height_data

        for _ in range(0, blur_iterations):
            copy = numpy.pad(height_data, ((1, 1), (1, 1)), mode="edge")

            height_data += copy[1:-1, 2:]
            height_data += copy[1:-1, :-2]
            height_data += copy[2:, 1:-1]
            height_data += copy[:-2, 1:-1]

            height_data += copy[2:, 2:]
            height_data += copy[:-2, 2:]
            height_data += copy[2:, :-2]
            height_data += copy[:-2, :-2]

            height_data /= 9

            Job.yieldThread()

        if use_transparency_model:
            divisor = 1.0 / math.log(
                transmittance_1mm / 100.0
            )  # log-base doesn't matter here. Precompute this value for faster computation of each pixel.
            min_luminance = (transmittance_1mm / 100.0)**(peak_height -
                                                          base_height)
            for (y, x) in numpy.ndindex(height_data.shape):
                mapped_luminance = min_luminance + (
                    1.0 - min_luminance) * height_data[y, x]
                height_data[y, x] = base_height + divisor * math.log(
                    mapped_luminance
                )  # use same base as a couple lines above this
        else:
            height_data *= scale_vector.y
            height_data += base_height

        if img.hasAlphaChannel():
            for x in range(0, width):
                for y in range(0, height):
                    height_data[y, x] *= qAlpha(img.pixel(x, y)) / 255.0

        heightmap_face_count = 2 * height_minus_one * width_minus_one
        total_face_count = heightmap_face_count + (width_minus_one * 2) * (
            height_minus_one * 2) + 2

        mesh.reserveFaceCount(total_face_count)

        # initialize to texel space vertex offsets.
        # 6 is for 6 vertices for each texel quad.
        heightmap_vertices = numpy.zeros(
            (width_minus_one * height_minus_one, 6, 3), dtype=numpy.float32)
        heightmap_vertices = heightmap_vertices + numpy.array(
            [[[0, base_height, 0], [0, base_height, texel_height],
              [texel_width, base_height, texel_height],
              [texel_width, base_height, texel_height],
              [texel_width, base_height, 0], [0, base_height, 0]]],
            dtype=numpy.float32)

        offsetsz, offsetsx = numpy.mgrid[0:height_minus_one, 0:width - 1]
        offsetsx = numpy.array(offsetsx, numpy.float32).reshape(
            -1, 1) * texel_width
        offsetsz = numpy.array(offsetsz, numpy.float32).reshape(
            -1, 1) * texel_height

        # offsets for each texel quad
        heightmap_vertex_offsets = numpy.concatenate([
            offsetsx,
            numpy.zeros((offsetsx.shape[0], offsetsx.shape[1]),
                        dtype=numpy.float32), offsetsz
        ], 1)
        heightmap_vertices += heightmap_vertex_offsets.repeat(6, 0).reshape(
            -1, 6, 3)

        # apply height data to y values
        heightmap_vertices[:, 0,
                           1] = heightmap_vertices[:, 5,
                                                   1] = height_data[:-1, :
                                                                    -1].reshape(
                                                                        -1)
        heightmap_vertices[:, 1, 1] = height_data[1:, :-1].reshape(-1)
        heightmap_vertices[:, 2,
                           1] = heightmap_vertices[:, 3, 1] = height_data[
                               1:, 1:].reshape(-1)
        heightmap_vertices[:, 4, 1] = height_data[:-1, 1:].reshape(-1)

        heightmap_indices = numpy.array(numpy.mgrid[0:heightmap_face_count *
                                                    3],
                                        dtype=numpy.int32).reshape(-1, 3)

        mesh._vertices[0:(heightmap_vertices.size //
                          3), :] = heightmap_vertices.reshape(-1, 3)
        mesh._indices[0:(heightmap_indices.size // 3), :] = heightmap_indices

        mesh._vertex_count = heightmap_vertices.size // 3
        mesh._face_count = heightmap_indices.size // 3

        geo_width = width_minus_one * texel_width
        geo_height = height_minus_one * texel_height

        # bottom
        mesh.addFaceByPoints(0, 0, 0, 0, 0, geo_height, geo_width, 0,
                             geo_height)
        mesh.addFaceByPoints(geo_width, 0, geo_height, geo_width, 0, 0, 0, 0,
                             0)

        # north and south walls
        for n in range(0, width_minus_one):
            x = n * texel_width
            nx = (n + 1) * texel_width

            hn0 = height_data[0, n]
            hn1 = height_data[0, n + 1]

            hs0 = height_data[height_minus_one, n]
            hs1 = height_data[height_minus_one, n + 1]

            mesh.addFaceByPoints(x, 0, 0, nx, 0, 0, nx, hn1, 0)
            mesh.addFaceByPoints(nx, hn1, 0, x, hn0, 0, x, 0, 0)

            mesh.addFaceByPoints(x, 0, geo_height, nx, 0, geo_height, nx, hs1,
                                 geo_height)
            mesh.addFaceByPoints(nx, hs1, geo_height, x, hs0, geo_height, x, 0,
                                 geo_height)

        # west and east walls
        for n in range(0, height_minus_one):
            y = n * texel_height
            ny = (n + 1) * texel_height

            hw0 = height_data[n, 0]
            hw1 = height_data[n + 1, 0]

            he0 = height_data[n, width_minus_one]
            he1 = height_data[n + 1, width_minus_one]

            mesh.addFaceByPoints(0, 0, y, 0, 0, ny, 0, hw1, ny)
            mesh.addFaceByPoints(0, hw1, ny, 0, hw0, y, 0, 0, y)

            mesh.addFaceByPoints(geo_width, 0, y, geo_width, 0, ny, geo_width,
                                 he1, ny)
            mesh.addFaceByPoints(geo_width, he1, ny, geo_width, he0, y,
                                 geo_width, 0, y)

        mesh.calculateNormals(fast=True)

        scene_node.setMeshData(mesh.build())

        return scene_node
Exemple #31
0
    def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, image_color_invert):
        scene_node = SceneNode()

        mesh = MeshBuilder()

        img = QImage(file_name)

        if img.isNull():
            Logger.log("e", "Image is corrupt.")
            return None

        width = max(img.width(), 2)
        height = max(img.height(), 2)
        aspect = height / width

        if img.width() < 2 or img.height() < 2:
            img = img.scaled(width, height, Qt.IgnoreAspectRatio)

        base_height = max(base_height, 0)
        peak_height = max(peak_height, -base_height)

        xz_size = max(xz_size, 1)
        scale_vector = Vector(xz_size, peak_height, xz_size)

        if width > height:
            scale_vector = scale_vector.set(z=scale_vector.z * aspect)
        elif height > width:
            scale_vector = scale_vector.set(x=scale_vector.x / aspect)

        if width > max_size or height > max_size:
            scale_factor = max_size / width
            if height > width:
                scale_factor = max_size / height

            width = int(max(round(width * scale_factor), 2))
            height = int(max(round(height * scale_factor), 2))
            img = img.scaled(width, height, Qt.IgnoreAspectRatio)

        width_minus_one = width - 1
        height_minus_one = height - 1

        Job.yieldThread()

        texel_width = 1.0 / (width_minus_one) * scale_vector.x
        texel_height = 1.0 / (height_minus_one) * scale_vector.z

        height_data = numpy.zeros((height, width), dtype=numpy.float32)

        for x in range(0, width):
            for y in range(0, height):
                qrgb = img.pixel(x, y)
                avg = float(qRed(qrgb) + qGreen(qrgb) + qBlue(qrgb)) / (3 * 255)
                height_data[y, x] = avg

        Job.yieldThread()

        if image_color_invert:
            height_data = 1 - height_data

        for _ in range(0, blur_iterations):
            copy = numpy.pad(height_data, ((1, 1), (1, 1)), mode= "edge")

            height_data += copy[1:-1, 2:]
            height_data += copy[1:-1, :-2]
            height_data += copy[2:, 1:-1]
            height_data += copy[:-2, 1:-1]

            height_data += copy[2:, 2:]
            height_data += copy[:-2, 2:]
            height_data += copy[2:, :-2]
            height_data += copy[:-2, :-2]

            height_data /= 9

            Job.yieldThread()

        height_data *= scale_vector.y
        height_data += base_height

        heightmap_face_count = 2 * height_minus_one * width_minus_one
        total_face_count = heightmap_face_count + (width_minus_one * 2) * (height_minus_one * 2) + 2

        mesh.reserveFaceCount(total_face_count)

        # initialize to texel space vertex offsets.
        # 6 is for 6 vertices for each texel quad.
        heightmap_vertices = numpy.zeros((width_minus_one * height_minus_one, 6, 3), dtype = numpy.float32)
        heightmap_vertices = heightmap_vertices + numpy.array([[
            [0, base_height, 0],
            [0, base_height, texel_height],
            [texel_width, base_height, texel_height],
            [texel_width, base_height, texel_height],
            [texel_width, base_height, 0],
            [0, base_height, 0]
        ]], dtype = numpy.float32)

        offsetsz, offsetsx = numpy.mgrid[0: height_minus_one, 0: width - 1]
        offsetsx = numpy.array(offsetsx, numpy.float32).reshape(-1, 1) * texel_width
        offsetsz = numpy.array(offsetsz, numpy.float32).reshape(-1, 1) * texel_height

        # offsets for each texel quad
        heightmap_vertex_offsets = numpy.concatenate([offsetsx, numpy.zeros((offsetsx.shape[0], offsetsx.shape[1]), dtype=numpy.float32), offsetsz], 1)
        heightmap_vertices += heightmap_vertex_offsets.repeat(6, 0).reshape(-1, 6, 3)

        # apply height data to y values
        heightmap_vertices[:, 0, 1] = heightmap_vertices[:, 5, 1] = height_data[:-1, :-1].reshape(-1)
        heightmap_vertices[:, 1, 1] = height_data[1:, :-1].reshape(-1)
        heightmap_vertices[:, 2, 1] = heightmap_vertices[:, 3, 1] = height_data[1:, 1:].reshape(-1)
        heightmap_vertices[:, 4, 1] = height_data[:-1, 1:].reshape(-1)

        heightmap_indices = numpy.array(numpy.mgrid[0:heightmap_face_count * 3], dtype=numpy.int32).reshape(-1, 3)

        mesh._vertices[0:(heightmap_vertices.size // 3), :] = heightmap_vertices.reshape(-1, 3)
        mesh._indices[0:(heightmap_indices.size // 3), :] = heightmap_indices

        mesh._vertex_count = heightmap_vertices.size // 3
        mesh._face_count = heightmap_indices.size // 3

        geo_width = width_minus_one * texel_width
        geo_height = height_minus_one * texel_height

        # bottom
        mesh.addFaceByPoints(0, 0, 0, 0, 0, geo_height, geo_width, 0, geo_height)
        mesh.addFaceByPoints(geo_width, 0, geo_height, geo_width, 0, 0, 0, 0, 0)

        # north and south walls
        for n in range(0, width_minus_one):
            x = n * texel_width
            nx = (n + 1) * texel_width

            hn0 = height_data[0, n]
            hn1 = height_data[0, n + 1]

            hs0 = height_data[height_minus_one, n]
            hs1 = height_data[height_minus_one, n + 1]

            mesh.addFaceByPoints(x, 0, 0, nx, 0, 0, nx, hn1, 0)
            mesh.addFaceByPoints(nx, hn1, 0, x, hn0, 0, x, 0, 0)

            mesh.addFaceByPoints(x, 0, geo_height, nx, 0, geo_height, nx, hs1, geo_height)
            mesh.addFaceByPoints(nx, hs1, geo_height, x, hs0, geo_height, x, 0, geo_height)

        # west and east walls
        for n in range(0, height_minus_one):
            y = n * texel_height
            ny = (n + 1) * texel_height

            hw0 = height_data[n, 0]
            hw1 = height_data[n + 1, 0]

            he0 = height_data[n, width_minus_one]
            he1 = height_data[n + 1, width_minus_one]

            mesh.addFaceByPoints(0, 0, y, 0, 0, ny, 0, hw1, ny)
            mesh.addFaceByPoints(0, hw1, ny, 0, hw0, y, 0, 0, y)

            mesh.addFaceByPoints(geo_width, 0, y, geo_width, 0, ny, geo_width, he1, ny)
            mesh.addFaceByPoints(geo_width, he1, ny, geo_width, he0, y, geo_width, 0, y)

        mesh.calculateNormals(fast=True)

        scene_node.setMeshData(mesh.build())

        return scene_node
    def updateSceneFromOptimizationResult(
            self, analysis: pywim.smartslice.result.Analysis):

        type_map = {
            'int': int,
            'float': float,
            'str': str,
            'enum': str,
            'bool': bool
        }

        our_only_node = getPrintableNodes()[0]
        active_extruder = getNodeActiveExtruder(our_only_node)

        # TODO - Move this into a common class or function to apply an am.Config to GlobalStack/ExtruderStack
        if analysis.print_config.infill:

            infill_density = analysis.print_config.infill.density
            infill_pattern = analysis.print_config.infill.pattern

            if infill_pattern is None or infill_pattern == pywim.am.InfillType.unknown:
                infill_pattern = pywim.am.InfillType.grid

            infill_pattern_name = SmartSliceJobHandler.INFILL_SMARTSLICE_CURA[
                infill_pattern]

            extruder_dict = {
                "wall_line_count": analysis.print_config.walls,
                "top_layers": analysis.print_config.top_layers,
                "bottom_layers": analysis.print_config.bottom_layers,
                "infill_sparse_density": analysis.print_config.infill.density,
                "infill_pattern": infill_pattern_name
            }

            Logger.log("d",
                       "Optimized extruder settings: {}".format(extruder_dict))

            for key, value in extruder_dict.items():
                if value is not None:
                    property_type = type_map.get(
                        active_extruder.getProperty(key, "type"))
                    if property_type:
                        active_extruder.setProperty(key,
                                                    "value",
                                                    property_type(value),
                                                    set_from_cache=True)
                        active_extruder.setProperty(key,
                                                    "state",
                                                    InstanceState.User,
                                                    set_from_cache=True)

            Application.getInstance().getMachineManager(
            ).forceUpdateAllSettings()
            self.optimizationResultAppliedToScene.emit()

        # Remove any modifier meshes which are present from a previous result
        mod_meshes = getModifierMeshes()
        if len(mod_meshes) > 0:
            for node in mod_meshes:
                node.addDecorator(SmartSliceRemovedDecorator())
                our_only_node.removeChild(node)
            Application.getInstance().getController().getScene(
            ).sceneChanged.emit(node)

        # Add in the new modifier meshes
        for modifier_mesh in analysis.modifier_meshes:
            # Building the scene node
            modifier_mesh_node = CuraSceneNode()
            modifier_mesh_node.setName("SmartSliceMeshModifier")
            modifier_mesh_node.setSelectable(True)
            modifier_mesh_node.setCalculateBoundingBox(True)

            # Use the data from the SmartSlice engine to translate / rotate / scale the mod mesh
            modifier_mesh_node.setTransformation(
                Matrix(modifier_mesh.transform))

            # Building the mesh

            # # Preparing the data from pywim for MeshBuilder
            modifier_mesh_vertices = [[v.x, v.y, v.z]
                                      for v in modifier_mesh.vertices]
            modifier_mesh_indices = [[triangle.v1, triangle.v2, triangle.v3]
                                     for triangle in modifier_mesh.triangles]

            # Doing the actual build
            modifier_mesh_data = MeshBuilder()
            modifier_mesh_data.setVertices(
                numpy.asarray(modifier_mesh_vertices, dtype=numpy.float32))
            modifier_mesh_data.setIndices(
                numpy.asarray(modifier_mesh_indices, dtype=numpy.int32))
            modifier_mesh_data.calculateNormals()

            modifier_mesh_node.setMeshData(modifier_mesh_data.build())
            modifier_mesh_node.calculateBoundingBoxMesh()

            active_build_plate = Application.getInstance(
            ).getMultiBuildPlateModel().activeBuildPlate
            modifier_mesh_node.addDecorator(
                BuildPlateDecorator(active_build_plate))
            modifier_mesh_node.addDecorator(SliceableObjectDecorator())
            modifier_mesh_node.addDecorator(SmartSliceAddedDecorator())

            bottom = modifier_mesh_node.getBoundingBox().bottom

            z_offset_decorator = ZOffsetDecorator()
            z_offset_decorator.setZOffset(bottom)
            modifier_mesh_node.addDecorator(z_offset_decorator)

            stack = modifier_mesh_node.callDecoration("getStack")
            settings = stack.getTop()

            modifier_mesh_node_infill_pattern = SmartSliceJobHandler.INFILL_SMARTSLICE_CURA[
                modifier_mesh.print_config.infill.pattern]
            definition_dict = {
                "infill_mesh": True,
                "infill_pattern": modifier_mesh_node_infill_pattern,
                "infill_sparse_density":
                modifier_mesh.print_config.infill.density,
                "wall_line_count": modifier_mesh.print_config.walls,
                "top_layers": modifier_mesh.print_config.top_layers,
                "bottom_layers": modifier_mesh.print_config.bottom_layers,
            }
            Logger.log(
                "d",
                "Optimized modifier mesh settings: {}".format(definition_dict))

            for key, value in definition_dict.items():
                if value is not None:
                    definition = stack.getSettingDefinition(key)
                    property_type = type_map.get(stack.getProperty(
                        key, "type"))
                    if property_type:
                        new_instance = SettingInstance(definition, settings)

                        new_instance.setProperty("value", property_type(value))

                        new_instance.resetState(
                        )  # Ensure that the state is not seen as a user state.
                        settings.addInstance(new_instance)

            our_only_node.addChild(modifier_mesh_node)

            # emit changes and connect error tracker
            Application.getInstance().getController().getScene(
            ).sceneChanged.emit(modifier_mesh_node)
Exemple #33
0
    def _createNodeFromObject(self, object, name=""):
        node = SceneNode()
        node.setName(name)
        mesh_builder = MeshBuilder()
        vertex_list = []

        components = object.find(".//3mf:components", self._namespaces)
        if components:
            for component in components:
                id = component.get("objectid")
                new_object = self._root.find(
                    "./3mf:resources/3mf:object[@id='{0}']".format(id),
                    self._namespaces)
                new_node = self._createNodeFromObject(
                    new_object, self._base_name + "_" + str(id))
                node.addChild(new_node)
                transform = component.get("transform")
                if transform is not None:
                    new_node.setTransformation(
                        self._createMatrixFromTransformationString(transform))

        # for vertex in entry.mesh.vertices.vertex:
        for vertex in object.findall(".//3mf:vertex", self._namespaces):
            vertex_list.append(
                [vertex.get("x"),
                 vertex.get("y"),
                 vertex.get("z")])
            Job.yieldThread()

        xml_settings = list(object.findall(".//cura:setting",
                                           self._namespaces))

        # Add the setting override decorator, so we can add settings to this node.
        if xml_settings:
            node.addDecorator(SettingOverrideDecorator())

            global_container_stack = Application.getInstance(
            ).getGlobalContainerStack()
            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                multi_extrusion = global_container_stack.getProperty(
                    "machine_extruder_count", "value") > 1
                # Ensure that all extruder data is reset
                if not multi_extrusion:
                    default_stack_id = global_container_stack.getId()
                else:
                    default_stack = ExtruderManager.getInstance(
                    ).getExtruderStack(0)
                    if default_stack:
                        default_stack_id = default_stack.getId()
                    else:
                        default_stack_id = global_container_stack.getId()
                node.callDecoration("setActiveExtruder", default_stack_id)

                # Get the definition & set it
                definition = QualityManager.getInstance(
                ).getParentMachineDefinition(
                    global_container_stack.getBottom())
                node.callDecoration("getStack").getTop().setDefinition(
                    definition)

            setting_container = node.callDecoration("getStack").getTop()
            for setting in xml_settings:
                setting_key = setting.get("key")
                setting_value = setting.text

                # Extruder_nr is a special case.
                if setting_key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance(
                    ).getExtruderStack(int(setting_value))
                    if extruder_stack:
                        node.callDecoration("setActiveExtruder",
                                            extruder_stack.getId())
                    else:
                        Logger.log("w",
                                   "Unable to find extruder in position %s",
                                   setting_value)
                    continue
                setting_container.setProperty(setting_key, "value",
                                              setting_value)

        if len(node.getChildren()) > 0:
            group_decorator = GroupDecorator()
            node.addDecorator(group_decorator)

        triangles = object.findall(".//3mf:triangle", self._namespaces)
        mesh_builder.reserveFaceCount(len(triangles))

        for triangle in triangles:
            v1 = int(triangle.get("v1"))
            v2 = int(triangle.get("v2"))
            v3 = int(triangle.get("v3"))

            mesh_builder.addFaceByPoints(
                vertex_list[v1][0], vertex_list[v1][1], vertex_list[v1][2],
                vertex_list[v2][0], vertex_list[v2][1], vertex_list[v2][2],
                vertex_list[v3][0], vertex_list[v3][1], vertex_list[v3][2])

            Job.yieldThread()

        # TODO: We currently do not check for normals and simply recalculate them.
        mesh_builder.calculateNormals(fast=True)
        mesh_builder.setFileName(name)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            node.setMeshData(mesh_data)

        node.setSelectable(True)
        return node
Exemple #34
0
    def rebuild(self):
        if not self._width or not self._height or not self._depth:
            return

        min_w = -self._width / 2
        max_w = self._width / 2
        min_h = 0.0
        max_h = self._height
        min_d = -self._depth / 2
        max_d = self._depth / 2

        z_fight_distance = 0.2 # Distance between buildplate and disallowed area meshes to prevent z-fighting

        if self._shape != "elliptic":
            # Outline 'cube' of the build volume
            mb = MeshBuilder()
            mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)

            mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)

            mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
            mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)

            self.setMeshData(mb.build())

            # Build plate grid mesh
            mb = MeshBuilder()
            mb.addQuad(
                Vector(min_w, min_h - z_fight_distance, min_d),
                Vector(max_w, min_h - z_fight_distance, min_d),
                Vector(max_w, min_h - z_fight_distance, max_d),
                Vector(min_w, min_h - z_fight_distance, max_d)
            )

            for n in range(0, 6):
                v = mb.getVertex(n)
                mb.setVertexUVCoordinates(n, v[0], v[2])
            self._grid_mesh = mb.build()

        else:
            # Bottom and top 'ellipse' of the build volume
            aspect = 1.0
            scale_matrix = Matrix()
            if self._width != 0:
                # Scale circular meshes by aspect ratio if width != height
                aspect = self._height / self._width
                scale_matrix.compose(scale = Vector(1, 1, aspect))
            mb = MeshBuilder()
            mb.addArc(max_w, Vector.Unit_Y, center = (0, min_h - z_fight_distance, 0), color = self.VolumeOutlineColor)
            mb.addArc(max_w, Vector.Unit_Y, center = (0, max_h, 0),  color = self.VolumeOutlineColor)
            self.setMeshData(mb.build().getTransformed(scale_matrix))

            # Build plate grid mesh
            mb = MeshBuilder()
            mb.addVertex(0, min_h - z_fight_distance, 0)
            mb.addArc(max_w, Vector.Unit_Y, center = Vector(0, min_h - z_fight_distance, 0))
            sections = mb.getVertexCount() - 1 # Center point is not an arc section
            indices = []
            for n in range(0, sections - 1):
                indices.append([0, n + 2, n + 1])
            mb.addIndices(numpy.asarray(indices, dtype = numpy.int32))
            mb.calculateNormals()

            for n in range(0, mb.getVertexCount()):
                v = mb.getVertex(n)
                mb.setVertexUVCoordinates(n, v[0], v[2] * aspect)
            self._grid_mesh = mb.build().getTransformed(scale_matrix)

        # Indication of the machine origin
        if self._global_container_stack.getProperty("machine_center_is_zero", "value"):
            origin = (Vector(min_w, min_h, min_d) + Vector(max_w, min_h, max_d)) / 2
        else:
            origin = Vector(min_w, min_h, max_d)

        mb = MeshBuilder()
        mb.addCube(
            width = self._origin_line_length,
            height = self._origin_line_width,
            depth = self._origin_line_width,
            center = origin + Vector(self._origin_line_length / 2, 0, 0),
            color = self.XAxisColor
        )
        mb.addCube(
            width = self._origin_line_width,
            height = self._origin_line_length,
            depth = self._origin_line_width,
            center = origin + Vector(0, self._origin_line_length / 2, 0),
            color = self.YAxisColor
        )
        mb.addCube(
            width = self._origin_line_width,
            height = self._origin_line_width,
            depth = self._origin_line_length,
            center = origin - Vector(0, 0, self._origin_line_length / 2),
            color = self.ZAxisColor
        )
        self._origin_mesh = mb.build()

        disallowed_area_height = 0.1
        disallowed_area_size = 0
        if self._disallowed_areas:
            mb = MeshBuilder()
            color = Color(0.0, 0.0, 0.0, 0.15)
            for polygon in self._disallowed_areas:
                points = polygon.getPoints()
                first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d))
                previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d))
                for point in points:
                    new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d))
                    mb.addFace(first, previous_point, new_point, color = color)
                    previous_point = new_point

                # Find the largest disallowed area to exclude it from the maximum scale bounds.
                # This is a very nasty hack. This pretty much only works for UM machines.
                # This disallowed area_size needs a -lot- of rework at some point in the future: TODO
                if numpy.min(points[:, 1]) >= 0: # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area.
                    size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
                else:
                    size = 0
                disallowed_area_size = max(size, disallowed_area_size)

            self._disallowed_area_mesh = mb.build()
        else:
            self._disallowed_area_mesh = None

        if self._error_areas:
            mb = MeshBuilder()
            for error_area in self._error_areas:
                color = Color(1.0, 0.0, 0.0, 0.5)
                points = error_area.getPoints()
                first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height,
                               self._clamp(points[0][1], min_d, max_d))
                previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height,
                                        self._clamp(points[0][1], min_d, max_d))
                for point in points:
                    new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height,
                                       self._clamp(point[1], min_d, max_d))
                    mb.addFace(first, previous_point, new_point, color=color)
                    previous_point = new_point
            self._error_mesh = mb.build()
        else:
            self._error_mesh = None

        self._volume_aabb = AxisAlignedBox(
            minimum = Vector(min_w, min_h - 1.0, min_d),
            maximum = Vector(max_w, max_h - self._raft_thickness, max_d))

        bed_adhesion_size = self._getEdgeDisallowedSize()

        # As this works better for UM machines, we only add the disallowed_area_size for the z direction.
        # This is probably wrong in all other cases. TODO!
        # The +1 and -1 is added as there is always a bit of extra room required to work properly.
        scale_to_max_bounds = AxisAlignedBox(
            minimum = Vector(min_w + bed_adhesion_size + 1, min_h, min_d + disallowed_area_size - bed_adhesion_size + 1),
            maximum = Vector(max_w - bed_adhesion_size - 1, max_h - self._raft_thickness, max_d - disallowed_area_size + bed_adhesion_size - 1)
        )

        Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
Exemple #35
0
    def _generateSceneNode(self, file_name, xz_size, peak_height, base_height,
                           blur_iterations, max_size, lighter_is_higher):
        scene_node = SceneNode()

        mesh = MeshBuilder()

        img = QImage(file_name)

        if img.isNull():
            Logger.log("e", "Image is corrupt.")
            return None

        width = max(img.width(), 2)
        height = max(img.height(), 2)
        aspect = height / width

        if img.width() < 2 or img.height() < 2:
            img = img.scaled(width, height, Qt.IgnoreAspectRatio)

        base_height = max(base_height, 0)
        peak_height = max(peak_height, -base_height)

        xz_size = max(xz_size, 1)
        scale_vector = Vector(xz_size, peak_height, xz_size)

        if width > height:
            scale_vector = scale_vector.set(z=scale_vector.z * aspect)
        elif height > width:
            scale_vector = scale_vector.set(x=scale_vector.x / aspect)

        if width > max_size or height > max_size:
            scale_factor = max_size / width
            if height > width:
                scale_factor = max_size / height

            width = int(max(round(width * scale_factor), 2))
            height = int(max(round(height * scale_factor), 2))
            img = img.scaled(width, height, Qt.IgnoreAspectRatio)

        width_minus_one = width - 1
        height_minus_one = height - 1

        Job.yieldThread()

        texel_width = 1.0 / (width_minus_one) * scale_vector.x
        texel_height = 1.0 / (height_minus_one) * scale_vector.z

        height_data = numpy.zeros((height, width), dtype=numpy.float32)

        for x in range(0, width):
            for y in range(0, height):
                qrgb = img.pixel(x, y)
                avg = float(qRed(qrgb) + qGreen(qrgb) + qBlue(qrgb)) / (3 *
                                                                        255)
                height_data[y, x] = avg

        Job.yieldThread()

        if not lighter_is_higher:
            height_data = 1 - height_data

        for _ in range(0, blur_iterations):
            copy = numpy.pad(height_data, ((1, 1), (1, 1)), mode="edge")

            height_data += copy[1:-1, 2:]
            height_data += copy[1:-1, :-2]
            height_data += copy[2:, 1:-1]
            height_data += copy[:-2, 1:-1]

            height_data += copy[2:, 2:]
            height_data += copy[:-2, 2:]
            height_data += copy[2:, :-2]
            height_data += copy[:-2, :-2]

            height_data /= 9

            Job.yieldThread()

        height_data *= scale_vector.y
        height_data += base_height

        heightmap_face_count = 2 * height_minus_one * width_minus_one
        total_face_count = heightmap_face_count + (width_minus_one * 2) * (
            height_minus_one * 2) + 2

        mesh.reserveFaceCount(total_face_count)

        # initialize to texel space vertex offsets.
        # 6 is for 6 vertices for each texel quad.
        heightmap_vertices = numpy.zeros(
            (width_minus_one * height_minus_one, 6, 3), dtype=numpy.float32)
        heightmap_vertices = heightmap_vertices + numpy.array(
            [[[0, base_height, 0], [0, base_height, texel_height],
              [texel_width, base_height, texel_height],
              [texel_width, base_height, texel_height],
              [texel_width, base_height, 0], [0, base_height, 0]]],
            dtype=numpy.float32)

        offsetsz, offsetsx = numpy.mgrid[0:height_minus_one, 0:width - 1]
        offsetsx = numpy.array(offsetsx, numpy.float32).reshape(
            -1, 1) * texel_width
        offsetsz = numpy.array(offsetsz, numpy.float32).reshape(
            -1, 1) * texel_height

        # offsets for each texel quad
        heightmap_vertex_offsets = numpy.concatenate([
            offsetsx,
            numpy.zeros((offsetsx.shape[0], offsetsx.shape[1]),
                        dtype=numpy.float32), offsetsz
        ], 1)
        heightmap_vertices += heightmap_vertex_offsets.repeat(6, 0).reshape(
            -1, 6, 3)

        # apply height data to y values
        heightmap_vertices[:, 0,
                           1] = heightmap_vertices[:, 5,
                                                   1] = height_data[:-1, :
                                                                    -1].reshape(
                                                                        -1)
        heightmap_vertices[:, 1, 1] = height_data[1:, :-1].reshape(-1)
        heightmap_vertices[:, 2,
                           1] = heightmap_vertices[:, 3, 1] = height_data[
                               1:, 1:].reshape(-1)
        heightmap_vertices[:, 4, 1] = height_data[:-1, 1:].reshape(-1)

        heightmap_indices = numpy.array(numpy.mgrid[0:heightmap_face_count *
                                                    3],
                                        dtype=numpy.int32).reshape(-1, 3)

        mesh._vertices[0:(heightmap_vertices.size //
                          3), :] = heightmap_vertices.reshape(-1, 3)
        mesh._indices[0:(heightmap_indices.size // 3), :] = heightmap_indices

        mesh._vertex_count = heightmap_vertices.size // 3
        mesh._face_count = heightmap_indices.size // 3

        geo_width = width_minus_one * texel_width
        geo_height = height_minus_one * texel_height

        # bottom
        mesh.addFaceByPoints(0, 0, 0, 0, 0, geo_height, geo_width, 0,
                             geo_height)
        mesh.addFaceByPoints(geo_width, 0, geo_height, geo_width, 0, 0, 0, 0,
                             0)

        # north and south walls
        for n in range(0, width_minus_one):
            x = n * texel_width
            nx = (n + 1) * texel_width

            hn0 = height_data[0, n]
            hn1 = height_data[0, n + 1]

            hs0 = height_data[height_minus_one, n]
            hs1 = height_data[height_minus_one, n + 1]

            mesh.addFaceByPoints(x, 0, 0, nx, 0, 0, nx, hn1, 0)
            mesh.addFaceByPoints(nx, hn1, 0, x, hn0, 0, x, 0, 0)

            mesh.addFaceByPoints(x, 0, geo_height, nx, 0, geo_height, nx, hs1,
                                 geo_height)
            mesh.addFaceByPoints(nx, hs1, geo_height, x, hs0, geo_height, x, 0,
                                 geo_height)

        # west and east walls
        for n in range(0, height_minus_one):
            y = n * texel_height
            ny = (n + 1) * texel_height

            hw0 = height_data[n, 0]
            hw1 = height_data[n + 1, 0]

            he0 = height_data[n, width_minus_one]
            he1 = height_data[n + 1, width_minus_one]

            mesh.addFaceByPoints(0, 0, y, 0, 0, ny, 0, hw1, ny)
            mesh.addFaceByPoints(0, hw1, ny, 0, hw0, y, 0, 0, y)

            mesh.addFaceByPoints(geo_width, 0, y, geo_width, 0, ny, geo_width,
                                 he1, ny)
            mesh.addFaceByPoints(geo_width, he1, ny, geo_width, he0, y,
                                 geo_width, 0, y)

        mesh.calculateNormals(fast=True)

        scene_node.setMeshData(mesh.build())

        return scene_node
Exemple #36
0
    def _createNodeFromObject(self, object, name = ""):
        node = SceneNode()
        node.setName(name)
        mesh_builder = MeshBuilder()
        vertex_list = []

        components = object.find(".//3mf:components", self._namespaces)
        if components:
            for component in components:
                id = component.get("objectid")
                new_object = self._root.find("./3mf:resources/3mf:object[@id='{0}']".format(id), self._namespaces)
                new_node = self._createNodeFromObject(new_object, self._base_name + "_" + str(id))
                node.addChild(new_node)
                transform = component.get("transform")
                if transform is not None:
                    new_node.setTransformation(self._createMatrixFromTransformationString(transform))

        # for vertex in entry.mesh.vertices.vertex:
        for vertex in object.findall(".//3mf:vertex", self._namespaces):
            vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
            Job.yieldThread()

        xml_settings = list(object.findall(".//cura:setting", self._namespaces))

        # Add the setting override decorator, so we can add settings to this node.
        if xml_settings:
            node.addDecorator(SettingOverrideDecorator())

            global_container_stack = Application.getInstance().getGlobalContainerStack()
            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
                # Ensure that all extruder data is reset
                if not multi_extrusion:
                    default_stack_id = global_container_stack.getId()
                else:
                    default_stack = ExtruderManager.getInstance().getExtruderStack(0)
                    if default_stack:
                        default_stack_id = default_stack.getId()
                    else:
                        default_stack_id = global_container_stack.getId()
                node.callDecoration("setActiveExtruder", default_stack_id)

                # Get the definition & set it
                definition = QualityManager.getInstance().getParentMachineDefinition(global_container_stack.getBottom())
                node.callDecoration("getStack").getTop().setDefinition(definition)

            setting_container = node.callDecoration("getStack").getTop()
            for setting in xml_settings:
                setting_key = setting.get("key")
                setting_value = setting.text

                # Extruder_nr is a special case.
                if setting_key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance().getExtruderStack(int(setting_value))
                    if extruder_stack:
                        node.callDecoration("setActiveExtruder", extruder_stack.getId())
                    else:
                        Logger.log("w", "Unable to find extruder in position %s", setting_value)
                    continue
                setting_container.setProperty(setting_key,"value", setting_value)

        if len(node.getChildren()) > 0:
            group_decorator = GroupDecorator()
            node.addDecorator(group_decorator)

        triangles = object.findall(".//3mf:triangle", self._namespaces)
        mesh_builder.reserveFaceCount(len(triangles))

        for triangle in triangles:
            v1 = int(triangle.get("v1"))
            v2 = int(triangle.get("v2"))
            v3 = int(triangle.get("v3"))

            mesh_builder.addFaceByPoints(vertex_list[v1][0], vertex_list[v1][1], vertex_list[v1][2],
                                         vertex_list[v2][0], vertex_list[v2][1], vertex_list[v2][2],
                                         vertex_list[v3][0], vertex_list[v3][1], vertex_list[v3][2])

            Job.yieldThread()

        # TODO: We currently do not check for normals and simply recalculate them.
        mesh_builder.calculateNormals()
        mesh_builder.setFileName(name)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            node.setMeshData(mesh_data)

        node.setSelectable(True)
        return node
Exemple #37
0
    def _convertSavitarNodeToUMNode(
            self,
            savitar_node: Savitar.SceneNode,
            file_name: str = "") -> Optional[SceneNode]:
        """Convenience function that converts a SceneNode object (as obtained from libSavitar) to a scene node.

        :returns: Scene node.
        """
        try:
            node_name = savitar_node.getName()
            node_id = savitar_node.getId()
        except AttributeError:
            Logger.log(
                "e",
                "Outdated version of libSavitar detected! Please update to the newest version!"
            )
            node_name = ""
            node_id = ""

        if node_name == "":
            if file_name != "":
                node_name = os.path.basename(file_name)
            else:
                node_name = "Object {}".format(node_id)

        active_build_plate = CuraApplication.getInstance(
        ).getMultiBuildPlateModel().activeBuildPlate

        um_node = CuraSceneNode()  # This adds a SettingOverrideDecorator
        um_node.addDecorator(BuildPlateDecorator(active_build_plate))
        try:
            um_node.addDecorator(ConvexHullDecorator())
        except:
            pass
        um_node.setName(node_name)
        um_node.setId(node_id)
        transformation = self._createMatrixFromTransformationString(
            savitar_node.getTransformation())
        um_node.setTransformation(transformation)
        mesh_builder = MeshBuilder()

        data = numpy.fromstring(
            savitar_node.getMeshData().getFlatVerticesAsBytes(),
            dtype=numpy.float32)

        vertices = numpy.resize(data, (int(data.size / 3), 3))
        mesh_builder.setVertices(vertices)
        mesh_builder.calculateNormals(fast=True)
        if file_name:
            # The filename is used to give the user the option to reload the file if it is changed on disk
            # It is only set for the root node of the 3mf file
            mesh_builder.setFileName(file_name)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            um_node.setMeshData(mesh_data)

        for child in savitar_node.getChildren():
            child_node = self._convertSavitarNodeToUMNode(child)
            if child_node:
                um_node.addChild(child_node)

        if um_node.getMeshData() is None and len(um_node.getChildren()) == 0:
            return None

        settings = savitar_node.getSettings()

        # Add the setting override decorator, so we can add settings to this node.
        if settings:
            global_container_stack = CuraApplication.getInstance(
            ).getGlobalContainerStack()

            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                default_stack = ExtruderManager.getInstance().getExtruderStack(
                    0)

                if default_stack:
                    um_node.callDecoration("setActiveExtruder",
                                           default_stack.getId())

                # Get the definition & set it
                definition_id = ContainerTree.getInstance().machines[
                    global_container_stack.definition.getId(
                    )].quality_definition
                um_node.callDecoration("getStack").getTop().setDefinition(
                    definition_id)

            setting_container = um_node.callDecoration("getStack").getTop()
            known_setting_keys = um_node.callDecoration(
                "getStack").getAllKeys()
            for key in settings:
                setting_value = settings[key].value

                # Extruder_nr is a special case.
                if key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance(
                    ).getExtruderStack(int(setting_value))
                    if extruder_stack:
                        um_node.callDecoration("setActiveExtruder",
                                               extruder_stack.getId())
                    else:
                        Logger.log("w",
                                   "Unable to find extruder in position %s",
                                   setting_value)
                    continue
                if key in known_setting_keys:
                    setting_container.setProperty(key, "value", setting_value)
                else:
                    um_node.metadata[key] = settings[key]

        if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None:
            if len(um_node.getAllChildren()) == 1:
                # We don't want groups of one, so move the node up one "level"
                child_node = um_node.getChildren()[0]
                parent_transformation = um_node.getLocalTransformation()
                child_transformation = child_node.getLocalTransformation()
                child_node.setTransformation(
                    parent_transformation.multiply(child_transformation))
                um_node = cast(CuraSceneNode, um_node.getChildren()[0])
            else:
                group_decorator = GroupDecorator()
                um_node.addDecorator(group_decorator)
        um_node.setSelectable(True)
        if um_node.getMeshData():
            # Assuming that all nodes with mesh data are printable objects
            # affects (auto) slicing
            sliceable_decorator = SliceableObjectDecorator()
            um_node.addDecorator(sliceable_decorator)
        return um_node
Exemple #38
0
    def _createCapsule(self, size, nb , lg, He, lw):
        mesh = MeshBuilder()
        # Per-vertex normals require duplication of vertices
        r = size / 2
        # First layer length
        sup = -lg + He
        if self._Nb_Layer >1 :
            sup_c = -lg + (He * 2)
        else:
            sup_c = -lg + (He * 3)
        l = -lg
        rng = int(360 / nb)
        ang = math.radians(nb)

        r_sup=math.tan(math.radians(45))*(He * 3)+r
        # Top inside radius 
        ri=r_sup-(1.8*lw)
        # Top radius 
        rit=r-(1.8*lw)
            
        verts = []
        for i in range(0, rng):
            # Top
            verts.append([ri*math.cos(i*ang), sup_c, ri*math.sin(i*ang)])
            verts.append([r_sup*math.cos((i+1)*ang), sup_c, r_sup*math.sin((i+1)*ang)])
            verts.append([r_sup*math.cos(i*ang), sup_c, r_sup*math.sin(i*ang)])
            
            verts.append([ri*math.cos((i+1)*ang), sup_c, ri*math.sin((i+1)*ang)])
            verts.append([r_sup*math.cos((i+1)*ang), sup_c, r_sup*math.sin((i+1)*ang)])
            verts.append([ri*math.cos(i*ang), sup_c, ri*math.sin(i*ang)])

            #Side 1a
            verts.append([r_sup*math.cos(i*ang), sup_c, r_sup*math.sin(i*ang)])
            verts.append([r_sup*math.cos((i+1)*ang), sup_c, r_sup*math.sin((i+1)*ang)])
            verts.append([r*math.cos((i+1)*ang), l, r*math.sin((i+1)*ang)])
            
            #Side 1b
            verts.append([r*math.cos((i+1)*ang), l, r*math.sin((i+1)*ang)])
            verts.append([r*math.cos(i*ang), l, r*math.sin(i*ang)])
            verts.append([r_sup*math.cos(i*ang), sup_c, r_sup*math.sin(i*ang)])
 
            #Side 2a
            verts.append([rit*math.cos((i+1)*ang), sup, rit*math.sin((i+1)*ang)])
            verts.append([ri*math.cos((i+1)*ang), sup_c, ri*math.sin((i+1)*ang)])
            verts.append([ri*math.cos(i*ang), sup_c, ri*math.sin(i*ang)])
            
            #Side 2b
            verts.append([ri*math.cos(i*ang), sup_c, ri*math.sin(i*ang)])
            verts.append([rit*math.cos(i*ang), sup, rit*math.sin(i*ang)])
            verts.append([rit*math.cos((i+1)*ang), sup, rit*math.sin((i+1)*ang)])
                
            #Bottom Top
            verts.append([0, sup, 0])
            verts.append([rit*math.cos((i+1)*ang), sup, rit*math.sin((i+1)*ang)])
            verts.append([rit*math.cos(i*ang), sup, rit*math.sin(i*ang)])
            
            #Bottom 
            verts.append([0, l, 0])
            verts.append([r*math.cos(i*ang), l, r*math.sin(i*ang)])
            verts.append([r*math.cos((i+1)*ang), l, r*math.sin((i+1)*ang)]) 
            
            
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        # for every angle increment 24 Vertices
        tot = rng * 24
        for i in range(0, tot, 3): # 
            indices.append([i, i+1, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
Exemple #39
0
    def _rebuild(self):
        if not self._build_volume._width or not self._build_volume._height or not self._build_volume._depth:
            return

        if not self._build_volume._engine_ready:
            return

        if not self._build_volume._volume_outline_color:
            theme = Application.getInstance().getTheme()
            self._build_volume._volume_outline_color = Color(
                *theme.getColor("volume_outline").getRgb())
            self._build_volume._x_axis_color = Color(
                *theme.getColor("x_axis").getRgb())
            self._build_volume._y_axis_color = Color(
                *theme.getColor("y_axis").getRgb())
            self._build_volume._z_axis_color = Color(
                *theme.getColor("z_axis").getRgb())
            self._build_volume._disallowed_area_color = Color(
                *theme.getColor("disallowed_area").getRgb())
            self._build_volume._error_area_color = Color(
                *theme.getColor("error_area").getRgb())

        ### START PATCH
        # Get a dict from the machine metadata optionally overriding the build volume
        # Note that CuraEngine is blissfully unaware of this; it is just what the user is shown in Cura
        limit_buildvolume = self._build_volume._global_container_stack.getMetaDataEntry(
            "limit_buildvolume", {})
        if not isinstance(limit_buildvolume, dict):
            limit_buildvolume = {}

        min_w = limit_buildvolume.get("width",
                                      {}).get("minimum",
                                              -self._build_volume._width / 2)
        max_w = limit_buildvolume.get("width",
                                      {}).get("maximum",
                                              self._build_volume._width / 2)
        min_h = limit_buildvolume.get("height", {}).get("minimum", 0.0)
        max_h = limit_buildvolume.get("height",
                                      {}).get("maximum",
                                              self._build_volume._height)
        min_d = limit_buildvolume.get("depth",
                                      {}).get("minimum",
                                              -self._build_volume._depth / 2)
        max_d = limit_buildvolume.get("depth",
                                      {}).get("maximum",
                                              self._build_volume._depth / 2)
        ### END PATCH

        z_fight_distance = 0.2  # Distance between buildplate and disallowed area meshes to prevent z-fighting

        if self._build_volume._shape != "elliptic":
            # Outline 'cube' of the build volume
            mb = MeshBuilder()
            mb.addLine(Vector(min_w, min_h, min_d),
                       Vector(max_w, min_h, min_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, min_h, min_d),
                       Vector(min_w, max_h, min_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, max_h, min_d),
                       Vector(max_w, max_h, min_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(max_w, min_h, min_d),
                       Vector(max_w, max_h, min_d),
                       color=self._build_volume._volume_outline_color)

            mb.addLine(Vector(min_w, min_h, max_d),
                       Vector(max_w, min_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, min_h, max_d),
                       Vector(min_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, max_h, max_d),
                       Vector(max_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(max_w, min_h, max_d),
                       Vector(max_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)

            mb.addLine(Vector(min_w, min_h, min_d),
                       Vector(min_w, min_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(max_w, min_h, min_d),
                       Vector(max_w, min_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(min_w, max_h, min_d),
                       Vector(min_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)
            mb.addLine(Vector(max_w, max_h, min_d),
                       Vector(max_w, max_h, max_d),
                       color=self._build_volume._volume_outline_color)

            self._build_volume.setMeshData(mb.build())

            # Build plate grid mesh
            mb = MeshBuilder()
            mb.addQuad(Vector(min_w, min_h - z_fight_distance, min_d),
                       Vector(max_w, min_h - z_fight_distance, min_d),
                       Vector(max_w, min_h - z_fight_distance, max_d),
                       Vector(min_w, min_h - z_fight_distance, max_d))

            for n in range(0, 6):
                v = mb.getVertex(n)
                mb.setVertexUVCoordinates(n, v[0], v[2])
            self._build_volume._grid_mesh = mb.build()

        else:
            # Bottom and top 'ellipse' of the build volume
            aspect = 1.0
            scale_matrix = Matrix()
            if self._build_volume._width != 0:
                # Scale circular meshes by aspect ratio if width != height
                aspect = self._build_volume._depth / self._build_volume._width
                scale_matrix.compose(scale=Vector(1, 1, aspect))
            mb = MeshBuilder()
            mb.addArc(max_w,
                      Vector.Unit_Y,
                      center=(0, min_h - z_fight_distance, 0),
                      color=self._build_volume._volume_outline_color)
            mb.addArc(max_w,
                      Vector.Unit_Y,
                      center=(0, max_h, 0),
                      color=self._build_volume._volume_outline_color)
            self._build_volume.setMeshData(
                mb.build().getTransformed(scale_matrix))

            # Build plate grid mesh
            mb = MeshBuilder()
            mb.addVertex(0, min_h - z_fight_distance, 0)
            mb.addArc(max_w,
                      Vector.Unit_Y,
                      center=Vector(0, min_h - z_fight_distance, 0))
            sections = mb.getVertexCount(
            ) - 1  # Center point is not an arc section
            indices = []
            for n in range(0, sections - 1):
                indices.append([0, n + 2, n + 1])
            mb.addIndices(numpy.asarray(indices, dtype=numpy.int32))
            mb.calculateNormals()

            for n in range(0, mb.getVertexCount()):
                v = mb.getVertex(n)
                mb.setVertexUVCoordinates(n, v[0], v[2] * aspect)
            self._build_volume._grid_mesh = mb.build().getTransformed(
                scale_matrix)

        # Indication of the machine origin
        if self._build_volume._global_container_stack.getProperty(
                "machine_center_is_zero", "value"):
            origin = (Vector(min_w, min_h, min_d) +
                      Vector(max_w, min_h, max_d)) / 2
        else:
            origin = Vector(min_w, min_h, max_d)

        mb = MeshBuilder()
        mb.addCube(width=self._build_volume._origin_line_length,
                   height=self._build_volume._origin_line_width,
                   depth=self._build_volume._origin_line_width,
                   center=origin +
                   Vector(self._build_volume._origin_line_length / 2, 0, 0),
                   color=self._build_volume._x_axis_color)
        mb.addCube(width=self._build_volume._origin_line_width,
                   height=self._build_volume._origin_line_length,
                   depth=self._build_volume._origin_line_width,
                   center=origin +
                   Vector(0, self._build_volume._origin_line_length / 2, 0),
                   color=self._build_volume._y_axis_color)
        mb.addCube(width=self._build_volume._origin_line_width,
                   height=self._build_volume._origin_line_width,
                   depth=self._build_volume._origin_line_length,
                   center=origin -
                   Vector(0, 0, self._build_volume._origin_line_length / 2),
                   color=self._build_volume._z_axis_color)
        self._build_volume._origin_mesh = mb.build()

        disallowed_area_height = 0.1
        disallowed_area_size = 0
        if self._build_volume._disallowed_areas:
            mb = MeshBuilder()
            color = self._build_volume._disallowed_area_color
            for polygon in self._build_volume._disallowed_areas:
                points = polygon.getPoints()
                if len(points) == 0:
                    continue

                first = Vector(
                    self._build_volume._clamp(points[0][0], min_w, max_w),
                    disallowed_area_height,
                    self._build_volume._clamp(points[0][1], min_d, max_d))
                previous_point = Vector(
                    self._build_volume._clamp(points[0][0], min_w, max_w),
                    disallowed_area_height,
                    self._build_volume._clamp(points[0][1], min_d, max_d))
                for point in points:
                    new_point = Vector(
                        self._build_volume._clamp(point[0], min_w, max_w),
                        disallowed_area_height,
                        self._build_volume._clamp(point[1], min_d, max_d))
                    mb.addFace(first, previous_point, new_point, color=color)
                    previous_point = new_point

                # Find the largest disallowed area to exclude it from the maximum scale bounds.
                # This is a very nasty hack. This pretty much only works for UM machines.
                # This disallowed area_size needs a -lot- of rework at some point in the future: TODO
                if numpy.min(
                        points[:, 1]
                ) >= 0:  # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area.
                    size = abs(
                        numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
                else:
                    size = 0
                disallowed_area_size = max(size, disallowed_area_size)

            self._build_volume._disallowed_area_mesh = mb.build()
        else:
            self._build_volume._disallowed_area_mesh = None

        if self._build_volume._error_areas:
            mb = MeshBuilder()
            for error_area in self._build_volume._error_areas:
                color = self._build_volume._error_area_color
                points = error_area.getPoints()
                first = Vector(
                    self._build_volume._clamp(points[0][0], min_w, max_w),
                    disallowed_area_height,
                    self._build_volume._clamp(points[0][1], min_d, max_d))
                previous_point = Vector(
                    self._build_volume._clamp(points[0][0], min_w, max_w),
                    disallowed_area_height,
                    self._build_volume._clamp(points[0][1], min_d, max_d))
                for point in points:
                    new_point = Vector(
                        self._build_volume._clamp(point[0], min_w, max_w),
                        disallowed_area_height,
                        self._build_volume._clamp(point[1], min_d, max_d))
                    mb.addFace(first, previous_point, new_point, color=color)
                    previous_point = new_point
            self._build_volume._error_mesh = mb.build()
        else:
            self._build_volume._error_mesh = None

        self._build_volume._volume_aabb = AxisAlignedBox(
            minimum=Vector(min_w, min_h - 1.0, min_d),
            maximum=Vector(
                max_w, max_h - self._build_volume._raft_thickness -
                self._build_volume._extra_z_clearance, max_d))

        bed_adhesion_size = self._build_volume.getEdgeDisallowedSize()

        # As this works better for UM machines, we only add the disallowed_area_size for the z direction.
        # This is probably wrong in all other cases. TODO!
        # The +1 and -1 is added as there is always a bit of extra room required to work properly.
        scale_to_max_bounds = AxisAlignedBox(
            minimum=Vector(
                min_w + bed_adhesion_size + 1, min_h,
                min_d + disallowed_area_size - bed_adhesion_size + 1),
            maximum=Vector(
                max_w - bed_adhesion_size - 1,
                max_h - self._build_volume._raft_thickness -
                self._build_volume._extra_z_clearance,
                max_d - disallowed_area_size + bed_adhesion_size - 1))

        Application.getInstance().getController().getScene(
        )._maximum_bounds = scale_to_max_bounds

        self._build_volume.updateNodeBoundaryCheck()
Exemple #40
0
    def _createAbutment(self, size, maxs, height, top, dep, ydir):
    
        # Logger.log('d', 'Ydir : ' + str(ydir)) 
        mesh = MeshBuilder()

        s = size / 2
        sm = maxs / 2
        l = height 
        s_inf=math.tan(math.radians(dep))*(l+top)+(2*s)
        
        if sm>s and dep!=0:
            l_max=(sm-s) / math.tan(math.radians(dep))
        else :
            l_max=l
        
        # Difference between Standart Abutment and Abutment + max base size
        if l_max<l and l_max>0:
            nbv=40  
            if ydir == False :
                verts = [ # 10 faces with 4 corners each
                    [-s, -l_max,  sm], [-s,  top,  2*s], [ s,  top,  2*s], [ s, -l_max,  sm],
                    [-s,  top, -2*s], [-s, -l_max, -sm], [ s, -l_max, -sm], [ s,  top, -2*s],
                    [-s, -l,  sm], [-s,  -l_max,  sm], [ s,  -l_max,  sm], [ s, -l,  sm],
                    [-s,  -l_max, -sm], [-s, -l, -sm], [ s, -l, -sm], [ s,  -l_max, -sm],                  
                    [ s, -l, -sm], [-s, -l, -sm], [-s, -l,  sm], [ s, -l,  sm],
                    [-s,  top, -2*s], [ s,  top, -2*s], [ s,  top,  2*s], [-s,  top,  2*s],
                    [-s, -l_max,  sm], [-s, -l_max, -sm], [-s,  top, -2*s], [-s,  top,  2*s],
                    [ s, -l_max, -sm], [ s, -l_max,  sm], [ s,  top,  2*s], [ s,  top, -2*s],                   
                    [-s, -l,  sm], [-s, -l, -sm], [-s,  -l_max, -sm], [-s,  -l_max,  sm],
                    [ s, -l, -sm], [ s, -l,  sm], [ s,  -l_max,  sm], [ s,  -l_max, -sm]
                ]
            else:
                verts = [ # 10 faces with 4 corners each
                    [-sm, -l_max,  s], [-2*s,  top,  s], [ 2*s,  top,  s], [ sm, -l_max,  s],
                    [-2*s,  top, -s], [-sm, -l_max, -s], [ sm, -l_max, -s], [ 2*s,  top, -s],                
                    [-sm, -l,  s], [-sm,  -l_max,  s], [ sm,  -l_max,  s], [ sm, -l,  s],
                    [-sm,  -l_max, -s], [-sm, -l, -s], [ sm, -l, -s], [ sm,  -l_max, -s],                         
                    [ sm, -l, -s], [-sm, -l, -s], [-sm, -l,  s], [ sm, -l,  s],
                    [-2*s,  top, -s], [ 2*s,  top, -s], [ 2*s,  top,  s], [-2*s,  top,  s],             
                    [-sm, -l_max,  s], [-sm, -l_max, -s], [-2*s,  top, -s], [-2*s,  top,  s],
                    [ sm, -l_max, -s], [ sm, -l_max,  s], [ 2*s,  top,  s], [ 2*s,  top, -s],                                  
                    [-sm, -l,  s], [-sm, -l, -s], [-sm,  -l_max, -s], [-sm,  -l_max,  s],
                    [ sm, -l, -s], [ sm, -l,  s], [ sm,  -l_max,  s], [ sm,  -l_max, -s]
                ]             
        else:
            nbv=24        
            if ydir == False :
                verts = [ # 6 faces with 4 corners each
                    [-s, -l,  s_inf], [-s,  top,  2*s], [ s,  top,  2*s], [ s, -l,  s_inf],
                    [-s,  top, -2*s], [-s, -l, -s_inf], [ s, -l, -s_inf], [ s,  top, -2*s],
                    [ s, -l, -s_inf], [-s, -l, -s_inf], [-s, -l,  s_inf], [ s, -l,  s_inf],
                    [-s,  top, -2*s], [ s,  top, -2*s], [ s,  top,  2*s], [-s,  top,  2*s],
                    [-s, -l,  s_inf], [-s, -l, -s_inf], [-s,  top, -2*s], [-s,  top,  2*s],
                    [ s, -l, -s_inf], [ s, -l,  s_inf], [ s,  top,  2*s], [ s,  top, -2*s]
                ]
            else:
                verts = [ # 6 faces with 4 corners each
                    [-s_inf, -l,  s], [-2*s,  top,  s], [ 2*s,  top,  s], [ s_inf, -l,  s],
                    [-2*s,  top, -s], [-s_inf, -l, -s], [ s_inf, -l, -s], [ 2*s,  top, -s],
                    [ s_inf, -l, -s], [-s_inf, -l, -s], [-s_inf, -l,  s], [ s_inf, -l,  s],
                    [-2*s,  top, -s], [ 2*s,  top, -s], [ 2*s,  top,  s], [-2*s,  top,  s],
                    [-s_inf, -l,  s], [-s_inf, -l, -s], [-2*s,  top, -s], [-2*s,  top,  s],
                    [ s_inf, -l, -s], [ s_inf, -l,  s], [ 2*s,  top,  s], [ 2*s,  top, -s]
                ]        
        mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32))

        indices = []
        for i in range(0, nbv, 4): # All 6 quads (12 triangles)
            indices.append([i, i+2, i+1])
            indices.append([i, i+3, i+2])
        mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32))

        mesh.calculateNormals()
        return mesh
Exemple #41
0
    def _convertSavitarNodeToUMNode(self, savitar_node):
        self._object_count += 1
        node_name = "Object %s" % self._object_count

        active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate

        um_node = CuraSceneNode() # This adds a SettingOverrideDecorator
        um_node.addDecorator(BuildPlateDecorator(active_build_plate))
        um_node.setName(node_name)
        transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation())
        um_node.setTransformation(transformation)
        mesh_builder = MeshBuilder()

        data = numpy.fromstring(savitar_node.getMeshData().getFlatVerticesAsBytes(), dtype=numpy.float32)

        vertices = numpy.resize(data, (int(data.size / 3), 3))
        mesh_builder.setVertices(vertices)
        mesh_builder.calculateNormals(fast=True)
        mesh_data = mesh_builder.build()

        if len(mesh_data.getVertices()):
            um_node.setMeshData(mesh_data)

        for child in savitar_node.getChildren():
            child_node = self._convertSavitarNodeToUMNode(child)
            if child_node:
                um_node.addChild(child_node)

        if um_node.getMeshData() is None and len(um_node.getChildren()) == 0:
            return None

        settings = savitar_node.getSettings()

        # Add the setting override decorator, so we can add settings to this node.
        if settings:
            global_container_stack = Application.getInstance().getGlobalContainerStack()

            # Ensure the correct next container for the SettingOverride decorator is set.
            if global_container_stack:
                default_stack = ExtruderManager.getInstance().getExtruderStack(0)

                if default_stack:
                    um_node.callDecoration("setActiveExtruder", default_stack.getId())

                # Get the definition & set it
                definition_id = getMachineDefinitionIDForQualitySearch(global_container_stack.definition)
                um_node.callDecoration("getStack").getTop().setDefinition(definition_id)

            setting_container = um_node.callDecoration("getStack").getTop()

            for key in settings:
                setting_value = settings[key]

                # Extruder_nr is a special case.
                if key == "extruder_nr":
                    extruder_stack = ExtruderManager.getInstance().getExtruderStack(int(setting_value))
                    if extruder_stack:
                        um_node.callDecoration("setActiveExtruder", extruder_stack.getId())
                    else:
                        Logger.log("w", "Unable to find extruder in position %s", setting_value)
                    continue
                setting_container.setProperty(key, "value", setting_value)

        if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None:
            group_decorator = GroupDecorator()
            um_node.addDecorator(group_decorator)
        um_node.setSelectable(True)
        if um_node.getMeshData():
            # Assuming that all nodes with mesh data are printable objects
            # affects (auto) slicing
            sliceable_decorator = SliceableObjectDecorator()
            um_node.addDecorator(sliceable_decorator)
        return um_node
Exemple #42
0
    def _read(self, file_name):
        scene_node = None

        extension = os.path.splitext(file_name)[1]
        if extension.lower() in self._supported_extensions:
            vertex_list = []
            normal_list = []
            uv_list = []
            face_list = []
            scene_node = SceneNode()

            mesh_builder = MeshBuilder()
            mesh_builder.setFileName(file_name)
            previous_line_parts = []
            f = open(file_name, "rt", encoding="utf-8")
            for line in f:
                parts = previous_line_parts + line.split()
                previous_line_parts = []
                if len(parts) < 1:
                    continue
                if parts[-1] == "\\":
                    del parts[-1]
                    previous_line_parts = parts
                    continue
                if parts[0] == "f":
                    parts = [i for i in map(lambda p: p.split("/"), parts)]
                    for idx in range(1, len(parts) - 2):
                        data = self._toAbsoluteIndex(len(vertex_list), [
                            int(parts[1][0]),
                            int(parts[idx + 1][0]),
                            int(parts[idx + 2][0])
                        ])

                        if len(parts[1]) > 1 and parts[1][1] and parts[
                                idx + 1][1] and parts[idx + 2][1]:
                            data += self._toAbsoluteIndex(
                                len(normal_list), [
                                    int(parts[1][1]),
                                    int(parts[idx + 1][1]),
                                    int(parts[idx + 2][1])
                                ])
                        else:
                            data += [0, 0, 0]

                        if len(parts[1]) > 2:
                            data += self._toAbsoluteIndex(
                                len(uv_list), [
                                    int(parts[1][2]),
                                    int(parts[idx + 1][2]),
                                    int(parts[idx + 2][2])
                                ])
                        else:
                            data += [0, 0, 0]

                        face_list.append(data)
                elif parts[0] == "v":
                    vertex_list.append(
                        [float(parts[1]),
                         float(parts[3]), -float(parts[2])])
                elif parts[0] == "vn":
                    normal_list.append(
                        [float(parts[1]),
                         float(parts[3]), -float(parts[2])])
                elif parts[0] == "vt":
                    uv_list.append([float(parts[1]), float(parts[2])])
                Job.yieldThread()
            f.close()

            mesh_builder.reserveVertexCount(3 * len(face_list))
            num_vertices = len(vertex_list)

            for face in face_list:
                # Substract 1 from index, as obj starts counting at 1 instead of 0
                i = face[0] - 1
                j = face[1] - 1
                k = face[2] - 1

                ui = face[3] - 1
                uj = face[4] - 1
                uk = face[5] - 1

                ni = face[6] - 1
                nj = face[7] - 1
                nk = face[8] - 1

                if i < 0 or i >= num_vertices:
                    i = 0
                if j < 0 or j >= num_vertices:
                    j = 0
                if k < 0 or k >= num_vertices:
                    k = 0
                if ni != -1 and nj != -1 and nk != -1:
                    mesh_builder.addFaceWithNormals(
                        vertex_list[i][0], vertex_list[i][1],
                        vertex_list[i][2], normal_list[ni][0],
                        normal_list[ni][1], normal_list[ni][2],
                        vertex_list[j][0], vertex_list[j][1],
                        vertex_list[j][2], normal_list[nj][0],
                        normal_list[nj][1], normal_list[nj][2],
                        vertex_list[k][0], vertex_list[k][1],
                        vertex_list[k][2], normal_list[nk][0],
                        normal_list[nk][1], normal_list[nk][2])
                else:
                    mesh_builder.addFaceByPoints(
                        vertex_list[i][0], vertex_list[i][1],
                        vertex_list[i][2], vertex_list[j][0],
                        vertex_list[j][1], vertex_list[j][2],
                        vertex_list[k][0], vertex_list[k][1],
                        vertex_list[k][2])

                if ui != -1 and len(uv_list) > ui:
                    mesh_builder.setVertexUVCoordinates(
                        mesh_builder.getVertexCount() - 3, uv_list[ui][0],
                        uv_list[ui][1])

                if uj != -1 and len(uv_list) > uj:
                    mesh_builder.setVertexUVCoordinates(
                        mesh_builder.getVertexCount() - 2, uv_list[uj][0],
                        uv_list[uj][1])

                if uk != -1 and len(uv_list) > uk:
                    mesh_builder.setVertexUVCoordinates(
                        mesh_builder.getVertexCount() - 1, uv_list[uk][0],
                        uv_list[uk][1])

                Job.yieldThread()
            if not mesh_builder.hasNormals():
                mesh_builder.calculateNormals(fast=True)

            # make sure that the mesh data is not empty
            if mesh_builder.getVertexCount() == 0:
                Logger.log("d",
                           "File did not contain valid data, unable to read.")
                return None  # We didn't load anything.

            scene_node.setMeshData(mesh_builder.build())

        return scene_node