def write_visualsfm_file(
        cls, output_nvm_file_name, cameras, points, op=None
    ):
        """Write cameras and points as :code:`.nvm` file."""

        log_report("INFO", "Write NVM file: " + output_nvm_file_name, op)

        nvm_content = []
        nvm_content.append(
            cls._nvm_line(cls._create_nvm_first_line(cameras, op))
        )
        nvm_content.append(cls._nvm_line(""))
        amount_cameras = len(cameras)
        nvm_content.append(cls._nvm_line(str(amount_cameras)))
        log_report(
            "INFO",
            "Amount Cameras (Images in NVM file):" + str(amount_cameras),
            op,
        )

        # Write the camera section
        # From the VSFM docs:
        # <Camera> = <File name> <focal length> <quaternion WXYZ> <camera center> <radial distortion> 0

        for camera in cameras:
            quaternion = camera.get_rotation_as_quaternion()

            current_line = camera.get_relative_fp()
            current_line += "\t" + str(camera.get_calibration_mat()[0][0])
            current_line += " " + " ".join(list(map(str, quaternion)))
            current_line += " " + " ".join(
                list(map(str, camera.get_camera_center()))
            )
            current_line += " " + "0"  # TODO USE RADIAL DISTORTION
            current_line += " " + "0"
            nvm_content.append(current_line + " " + os.linesep)

        nvm_content.append(" " + os.linesep)
        number_points = len(points)
        nvm_content.append(str(number_points) + " " + os.linesep)
        log_report(
            "INFO", "Found " + str(number_points) + " object points", op
        )

        num_features = 2
        image_idx = 0
        feature_idx = 0
        x = 0.0
        y = 0.0

        for point in points:
            # From the VSFM docs:
            # <Point>  = <XYZ> <RGB> <number of measurements> <List of Measurements>
            current_line = " ".join(list(map(str, point.coord)))
            current_line += " " + " ".join(list(map(str, point.color)))

            # current_line += ' ' + str(len(point.measurements))
            # for measurement in point.measurements:
            #     current_line += ' ' + str(measurement)
            current_line += " " + str(num_features)
            for feature in range(num_features):
                current_line += (
                    " "
                    + str(image_idx)
                    + " "
                    + str(feature_idx)
                    + " "
                    + str(x)
                    + " "
                    + str(y)
                )

            nvm_content.append(current_line + " " + os.linesep)

        nvm_content.append(" " + os.linesep)
        nvm_content.append(" " + os.linesep)
        nvm_content.append(" " + os.linesep)
        nvm_content.append("0" + os.linesep)
        nvm_content.append(" " + os.linesep)
        nvm_content.append(
            "#the last part of NVM file points to the PLY files " + os.linesep
        )
        nvm_content.append(
            "#the first number is the number of associated PLY files "
            + os.linesep
        )
        nvm_content.append(
            "#each following number gives a model-index that has PLY "
            + os.linesep
        )
        nvm_content.append("0" + os.linesep)

        output_file = open(output_nvm_file_name, "wb")
        output_file.writelines([item.encode() for item in nvm_content])

        log_report("INFO", "Write NVM file: Done", op)
Write cameras and points as :code:`.nvm` file.
photogrammetry_importer/file_handlers/visualsfm_file_handler.py