def test_delete_point_cloud(projects_fixture): u1 = db_session.query(User).get(1) point_cloud = PointCloudService.create(projectId=projects_fixture.id, data=POINT_CLOUD_DATA, user=u1) PointCloudService.delete(pointCloudId=point_cloud.id) assert db_session.query(PointCloud).count() == 0 assert db_session.query(Feature).count() == 0 assert len(os.listdir(get_project_asset_dir(point_cloud.project_id))) == 0
def post(self, projectId: int, pointCloudId: int): u = request.current_user files = request.json["files"] logger.info("Import file(s) to a point cloud:{} in project:{} for user:{}: {}".format( pointCloudId, projectId, request.current_user.username, files)) for file in files: PointCloudService.check_file_extension(file["path"]) external_data.import_point_clouds_from_agave.delay(u.id, files, pointCloudId) return {"message": "accepted"}
def test_delete_point_cloud_feature(celery_task_always_eager, projects_fixture, point_cloud_fixture, lidar_las1pt2_file_fixture): PointCloudService.fromFileObj(point_cloud_fixture.id, lidar_las1pt2_file_fixture, lidar_las1pt2_file_fixture.name) point_cloud = db_session.query(PointCloud).get(1) feature_asset_path = get_asset_path(point_cloud.feature.assets[0].path) FeaturesService.delete(point_cloud.feature.id) assert db_session.query(PointCloud).count() == 1 assert db_session.query(PointCloud).get(1).feature is None assert db_session.query(Feature).count() == 0 assert db_session.query(FeatureAsset).count() == 0 assert os.path.exists( get_asset_path(point_cloud.path, PointCloudService.ORIGINAL_FILES_DIR)) assert not os.path.exists(feature_asset_path)
def wrapper(*args, **kwargs): point_cloud_id = kwargs.get("pointCloudId") point_cloud = PointCloudService.get(point_cloud_id) if point_cloud.task \ and point_cloud.task.status not in ["FINISHED", "FAILED"]: logger.info("point cloud:{} is not in terminal state".format( point_cloud_id)) abort(404, "Point cloud is currently being updated") return fn(*args, **kwargs)
def post(self, projectId: int, pointCloudId: int): """ :raises InvalidCoordinateReferenceSystem: in case file missing coordinate reference system """ f = request.files['file'] file_name = secure_filename(f.filename) logger.info("Add a file to a point cloud:{} in project:{} for user:{}: {}".format( pointCloudId, projectId, request.current_user.username, file_name)) pc_task = PointCloudService.fromFileObj(pointCloudId, f, file_name) return pc_task
def test_update_point_cloud(projects_fixture, point_cloud_fixture, convert_to_potree_mock): data = { 'description': "new description", 'conversion_parameters': "--scale 5.0" } point_cloud = PointCloudService.update(point_cloud_fixture.id, data=data) convert_to_potree_mock.apply_async.assert_called_once() assert point_cloud.description == "new description" assert point_cloud.conversion_parameters == "--scale 5.0"
def test_add_point_cloud(projects_fixture): u1 = db_session.query(User).get(1) point_cloud = PointCloudService.create(projectId=projects_fixture.id, data=POINT_CLOUD_DATA, user=u1) assert point_cloud.description == "description" assert point_cloud.conversion_parameters == "--scale 2.0" assert not point_cloud.feature assert point_cloud.project_id == projects_fixture.id assert db_session.query(PointCloud).count() == 1
def wrapper(*args, **kwargs): projectId = kwargs.get("projectId") proj = ProjectsService.get(projectId) if not proj: abort(404, "No project found") pointCloudId = kwargs.get("pointCloudId") point_cloud = PointCloudService.get(pointCloudId) if not point_cloud: abort(404, "No point cloud found!") if point_cloud.project_id != projectId: abort(404, "Point cloud not part of project") return fn(*args, **kwargs)
def get_point_cloud_info(pointCloudId: int) -> dict: """ Get info on las files :param pointCloudId: int :return: None """ from geoapi.services.point_cloud import PointCloudService point_cloud = PointCloudService.get(pointCloudId) path_to_original_point_clouds = get_asset_path( point_cloud.path, PointCloudService.ORIGINAL_FILES_DIR) input_files = get_point_cloud_files(path_to_original_point_clouds) return [{'name': os.path.basename(f)} for f in input_files]
def test_add_point_cloud_file(projects_fixture, point_cloud_fixture, lidar_las1pt2_file_fixture, convert_to_potree_mock, check_point_cloud_mock, get_point_cloud_info_mock): filename = os.path.basename(lidar_las1pt2_file_fixture.name) task = PointCloudService.fromFileObj(point_cloud_fixture.id, lidar_las1pt2_file_fixture, filename) assert task.status == "RUNNING" assert point_cloud_fixture.task_id == task.id # load updated point cloud point_cloud = db_session.query(PointCloud).get(1) las_files = os.listdir( get_asset_path(point_cloud.path, PointCloudService.ORIGINAL_FILES_DIR)) assert len(las_files) == 1 assert las_files[0] == os.path.basename(filename) original_file_size = os.fstat(lidar_las1pt2_file_fixture.fileno()).st_size asset_file_path = os.path.join( get_asset_path(point_cloud.path, PointCloudService.ORIGINAL_FILES_DIR), filename) assert os.path.getsize(asset_file_path) == original_file_size # run conversion tool (that we had mocked) _, convert_kwargs = convert_to_potree_mock.apply_async.call_args assert projects_fixture.id == convert_kwargs['args'][0] convert_to_potree(projects_fixture.id) # load updated point cloud point_cloud = db_session.query(PointCloud).get(1) assert point_cloud.task.status == "FINISHED" assert db_session.query(Feature).count() == 1 assert db_session.query(FeatureAsset).count() == 1 assert len(os.listdir(get_project_asset_dir(point_cloud.project_id))) == 2 assert len(os.listdir(get_asset_path(point_cloud.feature.assets[0].path)) ) == 5 # index.html, preview.html, pointclouds, libs, logo assert os.path.isfile( os.path.join(get_asset_path(point_cloud.feature.assets[0].path), "preview.html")) with open( os.path.join(get_asset_path(point_cloud.feature.assets[0].path), "preview.html"), 'r+') as f: preview = f.read() assert "nsf_logo" not in preview assert "$('.potree_menu_toggle').hide()" in preview
def point_cloud_fixture(): u1 = db_session.query(User).filter(User.username == "test1").first() data = {"description": "description"} point_cloud = PointCloudService.create(projectId=1, data=data, user=u1) yield point_cloud
def convert_to_potree(self, pointCloudId: int) -> None: """ Use the potree converter to convert a LAS/LAZ file to potree format :param pointCloudId: int :return: None """ from geoapi.models import Feature, FeatureAsset from geoapi.services.point_cloud import PointCloudService point_cloud = PointCloudService.get(pointCloudId) path_to_original_point_clouds = get_asset_path( point_cloud.path, PointCloudService.ORIGINAL_FILES_DIR) path_temp_processed_point_cloud_path = get_asset_path( point_cloud.path, PointCloudService.PROCESSED_DIR) input_files = [ get_asset_path(path_to_original_point_clouds, file) for file in os.listdir(path_to_original_point_clouds) if pathlib.Path(file).suffix.lstrip('.').lower() in PointCloudService.LIDAR_FILE_EXTENSIONS ] outline = get_bounding_box_2d(input_files) command = [ "PotreeConverter", "--verbose", "-i", path_to_original_point_clouds, "-o", path_temp_processed_point_cloud_path, "--overwrite", "--generate-page", "index" ] if point_cloud.conversion_parameters: command.extend(point_cloud.conversion_parameters.split()) logger.info("Processing point cloud (#{}): {}".format( pointCloudId, " ".join(command))) subprocess.run(command, check=True, capture_output=True, text=True) # Create preview viewer html (with no menu and now nsf logo) with open( os.path.join(path_temp_processed_point_cloud_path, "preview.html"), 'w+') as preview: with open( os.path.join(path_temp_processed_point_cloud_path, "index.html"), 'r') as viewer: content = viewer.read() content = re.sub(r"<div class=\"nsf_logo\"(.+?)</div>", '', content, flags=re.DOTALL) content = content.replace("viewer.toggleSidebar()", "$('.potree_menu_toggle').hide()") preview.write(content) if point_cloud.feature_id: feature = point_cloud.feature else: feature = Feature() feature.project_id = point_cloud.project_id asset_uuid = uuid.uuid4() base_filepath = make_project_asset_dir(point_cloud.project_id) asset_path = os.path.join(base_filepath, str(asset_uuid)) fa = FeatureAsset(uuid=asset_uuid, asset_type="point_cloud", path=get_asset_relative_path(asset_path), feature=feature) feature.assets.append(fa) point_cloud.feature = feature feature.the_geom = from_shape(geometries.convert_3D_2D(outline), srid=4326) point_cloud.task.status = "FINISHED" point_cloud.task.description = "" point_cloud_asset_path = get_asset_path(feature.assets[0].path) shutil.rmtree(point_cloud_asset_path, ignore_errors=True) shutil.move(path_temp_processed_point_cloud_path, point_cloud_asset_path) try: db_session.add(point_cloud) db_session.add(feature) db_session.commit() except: db_session.rollback() raise
def get(self, projectId: int): return PointCloudService.list(projectId)
def test_update_point_cloud_without_changing_conversion_parameters( projects_fixture, point_cloud_fixture, convert_to_potree_mock): data = {'description': "new description"} point_cloud = PointCloudService.update(point_cloud_fixture.id, data=data) convert_to_potree_mock.apply_async.assert_not_called() assert point_cloud.description == "new description"
def delete(self, projectId: int, pointCloudId: int): logger.info("Delete point cloud:{} in project:{} for user:{}".format( pointCloudId, projectId, request.current_user.username)) return PointCloudService.delete(pointCloudId)
def put(self, projectId: int, pointCloudId: int): # TODO consider adding status to point cloud as we aren't returning task return PointCloudService.update(pointCloudId=pointCloudId, data=api.payload)
def get(self, projectId: int, pointCloudId: int): return PointCloudService.get(pointCloudId)
def post(self, projectId: int): logger.info("Add point cloud to project:{} for user:{}".format( projectId, request.current_user.username)) return PointCloudService.create(projectId=projectId, user=request.current_user, data=api.payload)