code: def filter_points3D(
      self,
      min_track_len=0,
      max_error=np.inf,
      min_tri_angle=0,
      max_tri_angle=180,
      image_set=set(),
  ):
      image_set = set(image_set)
  
      check_triangulation_angles = (
          min_tri_angle > 0 or max_tri_angle < 180
      )
      if check_triangulation_angles:
          max_tri_prod = np.cos(np.radians(min_tri_angle))
          min_tri_prod = np.cos(np.radians(max_tri_angle))
  
      iter_point3D_id_to_point3D_idx = (
          self.point3D_id_to_point3D_idx.items()
      )
  
      image_ids = []
  
      for point3D_id, point3D_idx in iter_point3D_id_to_point3D_idx:
          if point3D_idx == SceneManager.INVALID_POINT3D:
              continue
  
          if image_set or min_track_len > 0:
              image_ids = set(
                  self.point3D_id_to_images[point3D_id][:, 0]
              )
  
          # check if error and min track length are sufficient, or if none of
          # the selected cameras see the point
          if (
              len(image_ids) < min_track_len
              or self.point3D_errors[point3D_idx] > max_error
              or image_set
              and image_set.isdisjoint(image_ids)
          ):
              self.point3D_id_to_point3D_idx[
                  point3D_id
              ] = SceneManager.INVALID_POINT3D
  
          # find dot product between all camera viewing rays
          elif check_triangulation_angles:
              xyz = self.points3D[point3D_idx, :]
              tvecs = np.array(
                  [
                      (self.images[image_id].tvec - xyz)
                      for image_id in image_ids
                  ]
              )
              tvecs /= np.linalg.norm(tvecs, axis=-1)[:, np.newaxis]
  
              cos_theta = np.array(
                  [u.dot(v) for u, v in combinations(tvecs, 2)]
              )
  
              # min_prod = cos(maximum viewing angle), and vice versa
              # if maximum viewing angle is too small or too large,
              # don't add this point
              if (
                  np.min(cos_theta) > max_tri_prod
                  or np.max(cos_theta) < min_tri_prod
              ):
                  self.point3D_id_to_point3D_idx[
                      point3D_id
                  ] = SceneManager.INVALID_POINT3D
  
      # apply the filters to the image point3D_ids
      for image in self.images.values():
          mask = np.array(
              [
                  self.point3D_id_to_point3D_idx.get(point3D_id, 0)
                  == SceneManager.INVALID_POINT3D
                  for point3D_id in image.point3D_ids
              ]
          )
          image.point3D_ids[mask] = SceneManager.INVALID_POINT3D
  
imports: from collections import OrderedDict, defaultdict
  from io import StringIO
  from itertools import combinations
  import os
  import struct
  from .camera import Camera
  from .image import Image
  import numpy
  from .rotation import Quaternion
label_desc: Use image node_id 33 for calling the SceneManager obj's underlying member method code with example usage: obj.filter_points3D(min_track_len, max_error, min_tri_angle, max_tri_angle, image_set) without return types