Пример #1
0
def test_addVertices():
    builder = MeshBuilder()
    builder.addVertices(numpy.zeros(3))
    assert builder.getVertexCount() == 3

    builder.addVertices(numpy.zeros(3))
    assert builder.getVertexCount() == 6
Пример #2
0
    def _read(self, file_name):
        """Decide if we need to use ascii or binary in order to read file"""

        mesh_builder = MeshBuilder()
        scene_node = SceneNode()

        self.load_file(file_name, mesh_builder, _use_numpystl = use_numpystl)

        mesh = mesh_builder.build()

        if use_numpystl:
            verts = mesh.getVertices()
            # In some cases numpy stl reads incorrectly and the result is that the Z values are all 0
            # Add new error cases if you find them.
            if numpy.amin(verts[:, 1]) == numpy.amax(verts[:, 1]):
                # Something may have gone wrong in numpy stl, start over without numpy stl
                Logger.log("w", "All Z coordinates are the same using numpystl, trying again without numpy stl.")
                mesh_builder = MeshBuilder()
                self.load_file(file_name, mesh_builder, _use_numpystl = False)
                mesh = mesh_builder.build()

                verts = mesh.getVertices()
                if numpy.amin(verts[:, 1]) == numpy.amax(verts[:, 1]):
                    Logger.log("e", "All Z coordinates are still the same without numpy stl... let's hope for the best")

        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)
        Logger.log("d", "Loaded a mesh with %s vertices", mesh_builder.getVertexCount())

        return scene_node
Пример #3
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()

        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)
        Logger.log("d", "Loaded a mesh with %s vertices", mesh_builder.getVertexCount())
        return scene_node
Пример #4
0
    def read(self, file_name):
        mesh_builder = MeshBuilder()
        scene_node = SceneNode()

        self.load_file(file_name, mesh_builder, _use_numpystl = use_numpystl)

        mesh = mesh_builder.build()

        if use_numpystl:
            verts = mesh.getVertices()
            # In some cases numpy stl reads incorrectly and the result is that the Z values are all 0
            # Add new error cases if you find them.
            if numpy.amin(verts[:, 1]) == numpy.amax(verts[:, 1]):
                # Something may have gone wrong in numpy stl, start over without numpy stl
                Logger.log("w", "All Z coordinates are the same using numpystl, trying again without numpy stl.")
                mesh_builder = MeshBuilder()
                self.load_file(file_name, mesh_builder, _use_numpystl = False)
                mesh = mesh_builder.build()

                verts = mesh.getVertices()
                if numpy.amin(verts[:, 1]) == numpy.amax(verts[:, 1]):
                    Logger.log("e", "All Z coordinates are still the same without numpy stl... let's hope for the best")

        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)
        Logger.log("d", "Loaded a mesh with %s vertices", mesh_builder.getVertexCount())

        return scene_node
Пример #5
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 = mesh_builder.build()
        Logger.log("d", "Loaded a mesh with %s vertices", mesh_builder.getVertexCount())
        scene_node.setMeshData(mesh)
        return scene_node
Пример #6
0
def test_reserveVertexCount():
    builder = MeshBuilder()
    builder.addVertex(1, 2, 3)

    builder.reserveVertexCount(10)
    # Reserving face count should reset the verts
    assert builder.getVertexCount() == 0
Пример #7
0
def test_addFaceWithNormals():
    builder = MeshBuilder()
    builder.addFaceWithNormals(0, 0, 0, 1, 0, 0, 10, 0, 0, 0, 1, 0, 10, 10, 0,
                               0, 0, 1)
    assert builder.getVertexCount() == 3
    assert builder.getFaceCount() == 1
    assert builder.hasNormals()
Пример #8
0
def test_addLine():
    builder = MeshBuilder()
    builder.addLine(Vector(0, 0, 0), Vector(10, 11, 12))

    assert builder.getVertexCount() == 2
    assert builder.getVertex(1)[0] == 10
    assert builder.getVertex(1)[1] == 11
    assert builder.getVertex(1)[2] == 12
Пример #9
0
    def run(self) -> None:
        layer_data = None
        for node in DepthFirstIterator(self._scene.getRoot()):  # type: ignore
            layer_data = node.callDecoration("getLayerData")
            if layer_data:
                break

        if self._cancel or not layer_data:
            return

        layer_mesh = MeshBuilder()
        for i in range(self._solid_layers):
            layer_number = self._layer_number - i
            if layer_number < 0:
                continue

            try:
                layer = layer_data.getLayer(layer_number).createMesh()
            except Exception:
                Logger.logException(
                    "w", "An exception occurred while creating layer mesh.")
                return

            if not layer or layer.getVertices() is None:
                continue

            layer_mesh.addIndices(layer_mesh.getVertexCount() +
                                  layer.getIndices())
            layer_mesh.addVertices(layer.getVertices())

            # Scale layer color by a brightness factor based on the current layer number
            # This will result in a range of 0.5 - 1.0 to multiply colors by.
            brightness = numpy.ones(
                (1, 4), dtype=numpy.float32) * (2.0 -
                                                (i / self._solid_layers)) / 2.0
            brightness[0, 3] = 1.0
            layer_mesh.addColors(layer.getColors() * brightness)

            if self._cancel:
                return

            Job.yieldThread()

        if self._cancel:
            return

        Job.yieldThread()
        jump_mesh = layer_data.getLayer(self._layer_number).createJumps()
        if not jump_mesh or jump_mesh.getVertices() is None:
            jump_mesh = None

        self.setResult({"layers": layer_mesh.build(), "jumps": jump_mesh})
Пример #10
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
Пример #11
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
Пример #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
Пример #13
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
Пример #14
0
    def run(self):
        layer_data = None
        for node in DepthFirstIterator(self._scene.getRoot()):
            layer_data = node.callDecoration("getLayerData")
            if layer_data:
                break

        if self._cancel or not layer_data:
            return

        layer_mesh = MeshBuilder()
        for i in range(self._solid_layers):
            layer_number = self._layer_number - i
            if layer_number < 0:
                continue

            try:
                layer = layer_data.getLayer(layer_number).createMesh()
            except Exception:
                Logger.logException("w", "An exception occurred while creating layer mesh.")
                return

            if not layer or layer.getVertices() is None:
                continue

            layer_mesh.addIndices(layer_mesh.getVertexCount() + layer.getIndices())
            layer_mesh.addVertices(layer.getVertices())

            # Scale layer color by a brightness factor based on the current layer number
            # This will result in a range of 0.5 - 1.0 to multiply colors by.
            brightness = numpy.ones((1, 4), dtype=numpy.float32) * (2.0 - (i / self._solid_layers)) / 2.0
            brightness[0, 3] = 1.0
            layer_mesh.addColors(layer.getColors() * brightness)

            if self._cancel:
                return

            Job.yieldThread()

        if self._cancel:
            return

        Job.yieldThread()
        jump_mesh = layer_data.getLayer(self._layer_number).createJumps()
        if not jump_mesh or jump_mesh.getVertices() is None:
            jump_mesh = None

        self.setResult({"layers": layer_mesh.build(), "jumps": jump_mesh})
Пример #15
0
def test_addVertexWithNormal():
    builder = MeshBuilder()
    builder.addVertexWithNormal(10, 20, 30, -1, -2, -3)

    assert builder.getVertex(0)[0] == 10
    assert builder.getVertex(0)[1] == 20
    assert builder.getVertex(0)[2] == 30

    assert builder.hasNormals()  # We just added a vert with a normal, so we should have em
    assert builder.getNormals()[0][0] == -1
    assert builder.getNormals()[0][1] == -2
    assert builder.getNormals()[0][2] == -3

    assert builder.getVertexCount() == 1
    # There is only one vertex, so we should get None back
    assert builder.getVertex(22) is None
Пример #16
0
def test_addFace():
    builder = MeshBuilder()
    builder.addFaceByPoints(0, 0, 0, 10, 0, 0, 10, 10, 0)

    assert builder.getVertexCount() == 3
    assert builder.getFaceCount() == 1
    assert not builder.hasNormals()
    # Check if all the data ended up where it should be
    assert builder.getVertex(0)[0] == 0
    assert builder.getVertex(0)[1] == 0
    assert builder.getVertex(0)[2] == 0

    assert builder.getVertex(1)[0] == 10
    assert builder.getVertex(1)[1] == 0
    assert builder.getVertex(1)[2] == 0

    assert builder.getVertex(2)[0] == 10
    assert builder.getVertex(2)[1] == 10
    assert builder.getVertex(2)[2] == 0
Пример #17
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
Пример #18
0
def test_setVertices():
    builder = MeshBuilder()
    builder.setVertices(numpy.zeros(3))
    assert builder.getVertexCount() == 1
    assert builder.getVertices()[0] == 0
Пример #19
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()
Пример #20
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
Пример #21
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
Пример #22
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