/*
 *******************************************************************************
 *
 *  Copyright 2025 RIEGL Laser Measurement Systems
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  SPDX-License-Identifier: Apache-2.0
 *
 *******************************************************************************
 */
/*!
 *******************************************************************************
 *
 * \file    rdb-example-01-create-database.cpp
 * \author  RIEGL LMS GmbH, Austria
 * \brief   RDB example 1: Create new database
 * \version 2015-10-14/AW: Initial version
 * \version 2016-01-20/AW: Point attribute storage class definition added
 * \version 2016-11-29/AW: Shortcut for built-in RIEGL point attributes added
 * \version 2018-07-10/AW: Show usage of RIEGL default point attributes
 * \version 2019-01-15/AW: Add CreateSettings::chunkMode parameter
 *
 *  This example shows how to create a new RDB point cloud database and define
 *  some point attributes.
 *
 *  Build instructions see "interface/cpp/riegl/README.TXT".
 *
 *******************************************************************************
 */

#include <iostream>
#include <exception>

#include <riegl/rdb.hpp>
#include <riegl/rdb/default.hpp>

int main()
{
    try
    {
        // New RDB library context
        riegl::rdb::Context context;

        // New database instance
        riegl::rdb::Pointcloud rdb(context);

        // Step 1: Create new point cloud database
        {
            // This object contains all settings that are required
            // to create a new RDB point cloud database.
            riegl::rdb::pointcloud::CreateSettings settings;

            // Define primary point attribute, usually the point coordinates
            // details see class riegl::rdb::pointcloud::PointAttribute
            settings.primaryAttribute.name         = "riegl.xyz";
            settings.primaryAttribute.title        = "XYZ";
            settings.primaryAttribute.description  = "Cartesian point coordinates";
            settings.primaryAttribute.unitSymbol   = "m";
            settings.primaryAttribute.length       =  3;
            settings.primaryAttribute.resolution   =  0.00025;
            settings.primaryAttribute.minimumValue = -535000.0; // minimum,
            settings.primaryAttribute.maximumValue = +535000.0; //   maximum and
            settings.primaryAttribute.defaultValue =       0.0; //     default in m
            settings.primaryAttribute.storageClass = riegl::rdb::pointcloud::PointAttribute::VARIABLE;

            // Define database settings
            settings.chunkMode = riegl::rdb::pointcloud::CreateSettings::POINT_COUNT;
            settings.chunkSize = 50000; // maximum number of points per chunk
            settings.compressionLevel = 10; // 10% compression rate

            // Finally create new database
            rdb.create("pointcloud.rdbx", settings);
        }

        // Step 2: Define some additional point attributes
        //         Please note that there is also a shortcut for built-in
        //         RIEGL default point attributes which we use to define
        //         the "riegl.class" attribute at the end of this block.
        {
            // Before we can modify the database, we must start a transaction
            riegl::rdb::pointcloud::TransactionScope transaction(rdb,
                "Initialization",      // transaction title
                "Example program v1.0" // software name
            );

            // Target surface reflectance
            {
                riegl::rdb::pointcloud::PointAttribute attribute;
                //
                attribute.name         = "riegl.reflectance";
                attribute.title        = "Reflectance";
                attribute.description  = "Target surface reflectance";
                attribute.unitSymbol   = "dB";
                attribute.length       =  1;
                attribute.resolution   =    0.010;
                attribute.minimumValue = -100.000; // minimum,
                attribute.maximumValue = +100.000; //   maximum and
                attribute.defaultValue =    0.000; //     default in dB
                attribute.storageClass = riegl::rdb::pointcloud::PointAttribute::CONSTANT;
                //
                rdb.pointAttribute().add(attribute);
            }
            // Point color
            {
                riegl::rdb::pointcloud::PointAttribute attribute;
                //
                attribute.name         = "riegl.rgba";
                attribute.title        = "True Color";
                attribute.description  = "Point color acquired by camera";
                attribute.unitSymbol   = ""; // has no unit
                attribute.length       =   4;
                attribute.resolution   =   1.000;
                attribute.minimumValue =   0.000;
                attribute.maximumValue = 255.000;
                attribute.defaultValue = 255.000;
                attribute.storageClass = riegl::rdb::pointcloud::PointAttribute::VARIABLE;
                //
                rdb.pointAttribute().add(attribute);
            }
            // Point classification - by using a shortcut for built-in RIEGL attributes:
            {
                rdb.pointAttribute().add("riegl.class");
            }
            // Echo amplitude - by using the constant from "riegl/rdb/default.hpp"
            {
                rdb.pointAttribute().add(riegl::rdb::pointcloud::RDB_RIEGL_AMPLITUDE);
            }

            // Finally commit transaction
            transaction.commit();
        }

        // Success
        return 0;
    }
    catch(const riegl::rdb::Error &error)
    {
        std::cerr << error.what() << " (" << error.details() << ")" << std::endl;
        return 1; // error
    }
    catch(const std::exception &error)
    {
        std::cerr << error.what() << std::endl;
        return 1; // error
    }
}
