text:
/**
 * @file pedersen_test.cc
 *
 * Analyze the performance of the model against the extreme downward refraction
 * N^2 linear test case developed by Pedersen and Gordon.  This is also the
 * test case that Weinberg and Keenan used to calibrate the minimum beam width
 * in GRAB. This test serves several important functions
 *
 *  - Compares the ray path locations, travel time, and D/E angles
 *    to analytic results.
 *  - Compares the total propagation loss to analytic results.
 *  - Analyzes the contribution of the phase change at the caustic.
 *
 * The Pedersen/Gordon paper focuses two test cases.
 *
 * - The shallow source portion analyzed an acoustic field for a downward
 *   refracting profile that had been fit to experimental velocity data.
 *   Propagation loss was studied in both the image interference zone
 *   and the shadow zone.
 * - The deep source test cases extended this analysis to a non-physical
 *   extreme that emphasizes the effects of the caustic.
 *
 * Pedersen/Gordon concludes that the pi/2 phase change should only occur
 * when the ray path touches the caustic and not when the ray passes through
 * a horizontal vertex.  This is consistent with the current implementation
 * of GRAB, but different than the original Weinberg/Keenan paper.
 *
 * Uses the MKS version of the parameters defined in Jensen et. al.
 * instead of the original yd/sec version defined by Pedersen.
 *
 *  - c0 = 1550 m/s, g0 = 1.2 1/s, f = 2000 Hz
 *  - shallow:
 *      - source: depth = 75 m, time inc=0.025, cs = 1467.149925 m/s
 *      - target: depth = 75 m, range = 500-1000 m
 *  - deep:
 *      - source: depth = 1000 m, time inc=0.1, cs = 970.954770 m/s
 *      - target: depth = 800 m, range = 3000-3100 m
 *
 * @xref M. A. Pedersen, D. F. Gordon, "Normal-Mode and Ray Theory Applied
 * to Underwater Acoustic conditions of Extreme Downward Refraction",
 * J. Acoust. Soc. Am. 51 (1B), 323-368 (June 1972).
 * @xref H. Weinberg, R. E. Keenan, “Gaussian ray bundles for modeling
 * high-frequency propagation loss under shallow-water conditions”,
 * J. Acoust. Soc. Am. 100 (3), 1421-1431, (Sept 1996).
 * @xref L. M. Brekhovskikh, Waves in Layered Media, 2nd Edition,
 * Academic Press Inc., 1980, Section 54.
 * @xref F. B. Jensen, W. A. Kuperman, M. B. Porter, and H. Schmidt,
 * Computational Ocean Acoustics (American Institute of Physics Press,
 * New York, 1994) pp. 162-166.
 */
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <usml/waveq3d/waveq3d.h>
#include <iostream>
#include <iomanip>
#include <fstream>

BOOST_AUTO_TEST_SUITE(pedersen_test)

using namespace boost::unit_test;
using namespace usml::waveq3d;

// Define analysis parameter constants.

static const double FREQ = 2000 ;   // Hz
static const double C0 = 1550.0 ;   // sound speed at surface (m/s)
static const double G0 = 1.2 ;      // speed gradient at surface (1/s)
static const double LAT_SOURCE = 45.0;  // source latitude (deg)
static const double LNG_SOURCE = -45.0; // source longitude (deg)

/**
 * Construct the ocean model from its constituant parts.
 *
 * - N^2 Linear Profile on a Flat Earth
 * - No Attenuation
 * - Default Sea Surface
 * - "Infinitely" deep bottom
 *
 * @return  Dynamically allocated ocean model.
 *          Calling routine responsible for cleanup.
 */
ocean_model* build_ocean() {
    wposition::compute_earth_radius(LAT_SOURCE);

    attenuation_model* attn = new attenuation_constant(0.0);
    profile_model* profile = new profile_n2( C0, G0, attn );
    profile->flat_earth(true);

    boundary_model* surface = new boundary_flat();
    boundary_model* bottom = new boundary_flat(30000.0);

    return new ocean_model(surface, bottom, profile);
}

/**
 * Tests the accuracy of the raytrace model against the analytic
 * solutions for N^2 linear test case developed by Pedersen/Gordon.
 * Limits this comparison to the portion of the propagation after
 * all the rays are heading down.
 *
 * @param   source_depth    Source depth (m)
 * @param   de              Source D/E angles (deg)
 * @param   time_threshold  Error tolerance for travel time (%)
 * @param   range_threshold Error tolerance for target range (%)
 * @param   de_threshold    Error tolerance for target D/E angle (%)
 * @param   ncfile          File used to store wavefront history
 * @param   csvfile         File used to store model/theory comparisons
 */
void analyze_raytrace(
    double source_depth, const seq_vector& de,
    double time_min, double time_inc, double time_max,
    double time_threshold, double range_threshold, double de_threshold,
    const char* ncfile, const char* csvfile )
{
    // initialize source information

    ocean_model* ocean = build_ocean() ;
    seq_log freq( FREQ, 1.0, 1 ) ;
    wposition1 pos( LAT_SOURCE, LNG_SOURCE, source_depth );
    seq_linear az(0.0,1.0,1);       // only 1 ray needed for ray trace

    // compute the ray trace and store wavefronts to disk

    wave_queue wave( *ocean, freq, pos, de, az, time_inc );
    cout << "writing wavefronts to " << ncfile << endl;
    wave.init_netcdf(ncfile); // open a log file for wavefront data
    wave.save_netcdf();     // write initial ray data to log file

    cout << "writing spreadsheets to " << csvfile << endl;
    std::ofstream os(csvfile);
    os << "DElaunch,Tmodel,Ttheory,Rmodel,Rtheory,DEmodel,DEtheory" << endl;
    os << std::setprecision(18);
    const double Cs = wave.curr()->sound_speed(0,0) ; // sound speed at source
    const double b = G0 * 2 / (C0*C0*C0) ;

    double time_max_error = 0.0 ;
    double range_max_error = 0.0 ;
    double de_max_error = 0.0 ;

    while ( wave.time() < time_max ) {
        wave.step();        // propagate by one time step
        wave.save_netcdf(); // write ray data to log file

        // compare to the analytic results once all the rays are heading down

        if ( wave.time() >= time_min  ) {
            for ( size_t d=0 ; d < wave.num_de() ; ++d ) {

                // find Cm = speed at which each ray becomes horizonal

                const double As = -to_radians(wave.source_de(d)); // angle at source
                const double Cm = Cs / cos(As) ;    // Pedersen's ray parameter

                // find A0 = the angle at which this ray will hit the surface
                // Pedersen eq. 9: cos(A0) = C0/Cm

                const int surface = wave.curr()->surface(d,0) ;
                const double A0 = (surface==0) ? NAN : acos(min(1.0,C0/Cm)) ;

                // find Ah = the angle at the target location
                // Pedersen eq. 9: cos(Ah) = Ch/Cm

                const double Ch = wave.curr()->sound_speed(d,0) ;
                const double Ah = acos(Ch/Cm) ;

                wvector1 ndir( wave.curr()->ndirection, d, 0 ) ;
                double DEmodel, AZmodel ;
                ndir.direction( &DEmodel, &AZmodel ) ;

                // find R = horizontal range to the ray at the target location
                // Pedersen eq. 11: R=2/(b Cm^2)[tan(Ah)-tan(As)-2 tan(A0)]

                const double tanAh = tan(Ah);
                const double tanAs = tan(As);
                const double tanA0 = (surface==0) ? 0.0 : tan(A0);

                const double R = (2/(b*Cm*Cm)) * ( tanAh - tanAs - 2*tanA0 ) ;

                const double Rmodel = wposition::earth_radius * to_radians(
                    wave.curr()->position.latitude(d,0) - LAT_SOURCE ) ;

                // find T = travel time to the ray at the target location
                // Pedersen eq. 12:
                // R = 2/(3b Cm^3)[tan^3(Ah)-tan^3(As)-2tan^3(A0)] + R/Cm

                const double T = (2/(3*b*Cm*Cm*Cm))
                    * ( tanAh*tanAh*tanAh - tanAs*tanAs*tanAs
                      - 2*tanA0*tanA0*tanA0 ) + R / Cm ;

                // write the results to a spreadsheet

                os << -to_degrees(As)
                   << "," << wave.time() << "," << T
                   << "," << Rmodel << "," << R
                   << "," << DEmodel << "," << -to_degrees(Ah)
                   << endl ;

                const double time_error = wave.time()-T ;
                const double range_error = Rmodel-R ;
                const double de_error = DEmodel+to_degrees(Ah) ;
                time_max_error = max( time_max_error, abs(time_error) ) ;
                range_max_error = max( range_max_error, abs(range_error) ) ;
                de_max_error = max( de_max_error, abs(de_error) ) ;
                BOOST_CHECK_SMALL( time_error, time_threshold ) ;
                BOOST_CHECK_SMALL( range_error, range_threshold ) ;
                BOOST_CHECK_SMALL( de_error, de_threshold ) ;
            }
        }
    }

    // clean up and exit

    wave.close_netcdf(); // close log file for wavefront data
    delete ocean ;
    cout << "max errors: time=" << time_max_error
         << " range=" << range_max_error
         << " de=" << de_max_error << endl ;
}

/**
 * Tests the accuracy of the raytrace model against the analytic
 * solution for N^2 linear, shallow source, test case used by Pedersen/Gordon.
 * Generates linearly spaced beams in a 0:0.5:25 degree fan
 * to match Figure 3.6 in Jensen et. al.  The critical ray for a source
 * at 75.0 meters is 18.82 degrees.
 *
 * Errors are automatically generated if the ray paths deviate from the
 * analytic results by more than 3 millisecs in time, 5.0 meters in range,
 * or 0.2 degrees in angle.
 */
BOOST_AUTO_TEST_CASE( pedersen_shallow_raytrace ) {
    cout << "=== pedersen_shallow_raytrace ===" << endl ;
    seq_linear de( 0.0, 0.02, 25.00 ) ;
    analyze_raytrace( -75.0, de,
        0.30, 0.01, 0.85,
        0.003, 5.0, 0.2,
        USML_STUDIES_DIR "/pedersen/pedersen_shallow_raytrace.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_shallow_raytrace.csv" ) ;
}

/**
 * Tests the accuracy of the raytrace model against the analytic
 * solution for N^2 linear test case used by Pedersen/Gordon.
 * Generates linearly spaced beams in a 20:1:60 degrees fan
 * to match Figure 3.8 in Jensen et. al.  The critical ray for a source
 * at 1000.0 meters is 51.21 degrees.
 *
 * Errors are automatically generated if the ray paths deviate from the
 * analytic results by more than 8 millisecs in time, 10 meters in range,
 * or 0.02 degrees in angle.
 */
BOOST_AUTO_TEST_CASE( pedersen_deep_raytrace ) {
    cout << "=== pedersen_deep_raytrace ===" << endl ;
    seq_linear de( 20.00, 0.2, 60.00 ) ;
    analyze_raytrace( -1000.0, de,
        2.0, 0.01, 3.5,
        0.008, 10.0, 0.03,
        USML_STUDIES_DIR "/pedersen/pedersen_deep_raytrace.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_deep_raytrace.csv" ) ;
}

/**
 * Tests the accuracy of the eigenray_collection model against the analytic
 * solution for N^2 linear test case developed by Pedersen/Gordon.
 *
 * @param   time_step       Size of the time step to used in model (sec)
 * @param   de              Source D/E angles (deg)
 * @param   frequency       Source frequency (Hz)
 * @param   source_depth    Source depth (m)
 * @param   target_depth    Target depth (m)
 * @param   target_range    List of target ranges (m)
 * @param   ncfile          File used to store eigenrays
 * @param   csvfile         File used to store model/theory comparisons
 */
void analyze_proploss(
    const seq_vector& de, double source_depth, double target_depth,
    const seq_vector& target_range, double time_inc, double time_max,

    const char* ncfile, const char* csvfile )
{
    // initialize source information

    ocean_model* ocean = build_ocean() ;
    seq_log freq( FREQ, 1.0, 1 ) ;
    wposition1 pos( LAT_SOURCE, LNG_SOURCE, source_depth );
    seq_linear az(-4.0,1.0,4.0);

    // build a series of targets at different ranges

    wposition target(target_range.size(),1,LAT_SOURCE,LNG_SOURCE,target_depth);
    for (size_t n = 0; n < target.size1(); ++n) {
        const double angle = target_range[n] / wposition::earth_radius ;
        target.latitude( n, 0, LAT_SOURCE + to_degrees(angle) );
    }

    eigenray_collection loss(freq, pos, de, az, time_inc, &target);

    wave_queue wave( *ocean, freq, pos, de, az, time_inc, &target ) ;

    // adding eigenray_collection listener
    wave.add_eigenray_listener(&loss);

    // compute the eigenray_collection and store eigenrays to disk

    cout << "propagate wavefronts" << endl;
    while ( wave.time() < time_max ) {
        wave.step();        // propagate by one time step
    }
    loss.sum_eigenrays();
    cout << "writing eigenrays to " << ncfile << endl;
    loss.write_netcdf(ncfile);

    // save results to spreadsheet for post-test analysis

    cout << "writing spreadsheets to " << csvfile << endl;
    std::ofstream os(csvfile);
    os << "range,model,first,second" << endl;
    os << std::setprecision(18);

    vector<double> tl_model(target.size1());
    for (size_t n = 0; n < target.size1(); ++n) {
        double tl_model = -loss.total(n,0)->intensity(0);
        os << target_range[n] << "," << tl_model ;

        const eigenray_list* raylist = loss.eigenrays(n, 0);
        for (eigenray_list::const_iterator iter = raylist->begin();
                iter != raylist->end(); ++iter) {
            const eigenray &ray = *iter;
            os << "," << (-ray.intensity(0));
        }
        os << endl;
    }

    // clean up and exit

    delete ocean ;
}

/**
 * Tests the accuracy of the eigenray_collection model against the analytic solution for
 * the shallow source, N^2 linear test case developed by Pedersen and Gordon.
 * The source is located at a depth of 75 meters. Receivers have a depth of
 * 75 meters and ranges from 500 to 1000 yds. Uses rays from 0 to 30 degrees at
 * a very a tight 0.025 deg spacing.  Such tight spacing is needed to capture
 * the portion of the surface reflected path just inside of the critical ray.
 *
 * This configuration tests the model's ability to produce accurate propagation
 * loss, phase, travel times, and eigneray angles at the edge of a shadow zone.
 * Eigenrays are written out in both netCDF and CSV format so that they can be
 * compared to other models off-line.
 */
BOOST_AUTO_TEST_CASE( pedersen_shallow_proploss ) {
    cout << "=== pedersen_shallow_proploss ===" << endl ;
    seq_linear ranges(500.0,1.0,1000.0) ;
    seq_linear de( 0.0, 0.025, 25.0 ) ;
    analyze_proploss( de, -75.0, -75.0, ranges,
        0.01, 0.85,
        USML_STUDIES_DIR "/pedersen/pedersen_shallow_proploss.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_shallow_proploss.csv" ) ;
}

/**
 * Tests the accuracy of the eigenray_collection model against the analytic solution for
 * the deep source, N^2 linear test case developed by Pedersen and Gordon.
 * The source is located at a depth of 1000 meters. Receivers have a depth of
 * 800 meters and ranges from 3000 to 3120 meters. Uses rays from 20
 * to 60 degrees at a 0.25 deg spacing.
 *
 * We found that tangent spaced beams did not work very well for this
 * scenario.  Several combinations of parameters lead to artifacts in the
 * shadow zone from an imperfect cancellation of the direct and caustic paths.
 * We believe that this is caused the accumulation of small cell width
 * and target range errors over hundreds of contributing beams.
 *
 * This configuration tests the model's ability to produce accurate propagation
 * loss, phase, travel times, and eigneray angles in an area where a caustic
 * causes rays to cross at the edge of a shadow zone.  Eigenrays are written
 * out in both netCDF and CSV format so that they can be  compared to other
 * models off-line.
 */
BOOST_AUTO_TEST_CASE( pedersen_deep_proploss ) {
    cout << "=== pedersen_deep_proploss ===" << endl ;
    seq_linear ranges(3000.0,0.25,3120.0) ;
    seq_linear de( 20.0, 0.25, 60.0 ) ;
    analyze_proploss( de, -1000.0, -800.0, ranges,
        0.01, 3.5,
        USML_STUDIES_DIR "/pedersen/pedersen_deep_proploss.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_deep_proploss.csv" ) ;
}

/**
 * Tests the sensitivity of the eigenray_collection model the D/E angular resolution
 * near the caustic. The source is located at a depth of 1000 yds. Receivers
 * have a depth of 800 yds and ranges from 3100 to 3180 yds. Uses a ray fan
 * from +40 to +51 degrees with increments of 0.025, 0.05, 0.10, and 0.20
 * degrees. This configuration test the models sensitivity to ray spacing
 * near the caustic.
 *
 * The N^2 linear test case developed by Pedersen and Gordon was specifically
 * chosen because we expect it to be very sensitive to the ray geometry near
 * the caustic.  This sensitivity is especially true for the deep source
 * varient, because the profile below 200 meters is more extreme than those
 * found in the real world.
 */
BOOST_AUTO_TEST_CASE( pedersen_deep_sensitivity ) {
    cout << "=== pedersen_deep_sensitivity ===" << endl ;
    seq_linear ranges(3000.0,0.25,3120.0) ;

    seq_rayfan de( -90.0, 90.0, 181, 51.21 ) ;
    analyze_proploss( de, -1000, -800.0, ranges, 0.01, 3.5,
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_tan.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_tan.csv" ) ;

    seq_linear de1000( 40.00, 0.100, 60.00 ) ;
    analyze_proploss( de1000, -1000, -800.0, ranges, 0.01, 3.5,
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_1000.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_1000.csv" ) ;

    seq_linear de0500( 40.00, 0.05000, 60.00 ) ;
    analyze_proploss( de0500, -1000, -800.0, ranges, 0.01, 3.5,
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_0500.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_0500.csv" ) ;

    seq_linear de0250( 40.00, 0.0250, 60.00 ) ;
    analyze_proploss( de0250, -1000, -800.0, ranges, 0.01, 3.5,
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_0250.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_0250.csv" ) ;

    seq_linear de0125( 40.00, 0.0125, 60.00 ) ;
    analyze_proploss( de0125, -1000, -800.0, ranges, 0.01, 3.5,
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_0125.nc",
        USML_STUDIES_DIR "/pedersen/pedersen_deep_sensitivity_0125.csv" ) ;
}

/// @}

BOOST_AUTO_TEST_SUITE_END()

ext: cc

max_stars_repo_name: fraclipe/UnderSeaModelingLibrary

max_issues_repo_name: Wolframy-NUDT/UnderSeaModelingLibrary

max_forks_repo_name: Wolframy-NUDT/UnderSeaModelingLibrary


text:
//
// $Id$
//
//
// Original author: Robert Burke <robert.burke@proteowizard.org>
//
// Copyright 2009 Spielberg Family Center for Applied Proteomics
//   University of Southern California, Los Angeles, California  90033
//
// 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.
//

#ifndef _IDENTDATA_HPP_
#define _IDENTDATA_HPP_

#include "pwiz/utility/misc/Export.hpp"
#include "pwiz/utility/misc/Exception.hpp"
#include "pwiz/data/proteome/Digestion.hpp"
#include "pwiz/data/common/ParamTypes.hpp"
#include "boost/logic/tribool_io.hpp"
#include <vector>
#include <string>
#include <map>

#ifdef USE_RAW_PTR
#define TYPEDEF_SHARED_PTR(type) typedef type* type##Ptr
#define BOOST_FOREACH(a, b) a;
#else
#include <boost/foreach.hpp>
#define TYPEDEF_SHARED_PTR(type) typedef boost::shared_ptr<type> type##Ptr
#endif

namespace pwiz {
namespace identdata {

using namespace pwiz::cv;
using namespace pwiz::data;

/// returns a default list of CVs used in an IdentData document;
/// currently includes PSI-MS, Unit Ontology, and UNIMOD
PWIZ_API_DECL std::vector<CV> defaultCVList();

/// Parent class representing extensions of the IdentifiableType from
/// the mzIdentML schema.
///
/// Other classes in the model can be specified as sub-classes,
/// inheriting from Identifiable. Identifiable gives classes a unique
/// identifier within the scope and a name that need not be unique.
struct PWIZ_API_DECL Identifiable
{
    Identifiable(const std::string& id_ = "",
                 const std::string& name_ = "");
    virtual ~Identifiable() {}

    std::string id;
    std::string name;

    virtual bool empty() const;
};

/// Parent class of all Identifiable objects that have ParamGroups.
///
/// Represents bibliographic references.
struct PWIZ_API_DECL IdentifiableParamContainer : public ParamContainer
{
    IdentifiableParamContainer(const std::string& id_ = "",
                 const std::string& name_ = "");
    virtual ~IdentifiableParamContainer() {}

    std::string id;
    std::string name;

    virtual bool empty() const;
};

/// Implementation for the BibliographicReferenceType tag in the
/// mzIdentML schema.
///
/// Represents bibliographic references.
struct PWIZ_API_DECL BibliographicReference : public Identifiable
{
    BibliographicReference();

    std::string authors;
    std::string publication;
    std::string publisher;
    std::string editor;
    int year;
    std::string volume;
    std::string issue;
    std::string pages;
    std::string title;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(BibliographicReference);

/// Implementation of ContactType from mzIdentML.
///
/// A contact is either a person or an organization.
struct PWIZ_API_DECL Contact : public IdentifiableParamContainer
{
    Contact(const std::string& id_ = "",
            const std::string& name_ = "");
    virtual ~Contact() {}

    virtual bool empty() const;
};

TYPEDEF_SHARED_PTR(Contact);

/// \brief Implementation of AbstractOrganizationType from the
/// mzIdentML schema.
///
/// Organizations are entities like companies, universities,
/// government agencies. Any additional information such as the
/// address, email etc. should be supplied either as CV parameters or
/// as user parameters.
struct PWIZ_API_DECL Organization : public Contact
{
    Organization(const std::string& id_ = "",
                 const std::string& name_ = "");

    boost::shared_ptr<Organization> parent;

    virtual bool empty() const;
};

TYPEDEF_SHARED_PTR(Organization);

/// Implementation of PersonType from the mzIdentML schema.
///
/// A person's name and contact details. Any additional information
/// such as the address, contact email etc. should be supplied using
/// CV parameters or user parameters.
struct PWIZ_API_DECL Person : public Contact
{
    Person(const std::string& id_ = "",
           const std::string& name_ = "");

    std::string lastName;
    std::string firstName;
    std::string midInitials;

    std::vector<OrganizationPtr> affiliations;

    virtual bool empty() const;
};

TYPEDEF_SHARED_PTR(Person);

/// Implementation of ContactRoleType from the mzIdentML schema.
///
/// The role that a Contact plays in an organization or with respect
/// to the associating class. A Contact may have several Roles within
/// scope, and as such, associations to ContactRole allow the use of a
/// Contact in a certain manner. Examples might include a provider, or
/// a data analyst.
struct PWIZ_API_DECL ContactRole : public CVParam
{
    ContactRole(CVID role_ = CVID_Unknown,
                const ContactPtr& contactPtr_ = ContactPtr());

    ContactPtr contactPtr;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(ContactRole);

/// Implementation of the SampleType from the mzIdentML schema.
///
/// A description of the sample analysed by mass spectrometry using
/// CVParams or UserParams. If a composite sample has been analysed, a
/// parent sample should be defined, which references subsamples. This
/// represents any kind of substance used in an experimental workflow,
/// such as whole organisms, cells, DNA, solutions, compounds and
/// experimental substances (gels, arrays etc.).
struct PWIZ_API_DECL Sample : public IdentifiableParamContainer
{
    Sample(const std::string& id_ = "",
           const std::string& name_ = "");

    std::vector<ContactRolePtr> contactRole;
    std::vector<boost::shared_ptr<Sample> > subSamples;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Sample);

/// Implementation of AnalysisSoftwareType from the mzIdentML schema.
///
/// The software used for performing the analyses.
struct PWIZ_API_DECL AnalysisSoftware : public Identifiable
{
    AnalysisSoftware(const std::string& id_ = "",
                     const std::string& name_ = "");

    // SoftwareType attributes
    std::string version;
    std::string URI;
    std::string customizations;

    // SoftwareType elements
    ContactRolePtr contactRolePtr;
    ParamContainer softwareName;

    virtual bool empty() const;
};

TYPEDEF_SHARED_PTR(AnalysisSoftware);

/// Implementation of ProviderType from the mzIdentML schema.
///
/// The provider of the document in terms of the Contact and the
/// software the produced the document instance.
struct PWIZ_API_DECL Provider : public Identifiable
{
    Provider(const std::string id_ = "",
             const std::string name_ = "");

    ContactRolePtr contactRolePtr;
    AnalysisSoftwarePtr analysisSoftwarePtr;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Provider);

// TODO find example document w/ this in it and determine best
// representation for data model

/// Implementation of AnalysisSampleCollectionType from mzIdentML
/// schema.
///
/// The samples analysed can optionally be recorded using CV terms for
/// descriptions. If a composite sample has been analysed, the
/// subsample association can be used to build a hierarchical
/// description.
struct PWIZ_API_DECL AnalysisSampleCollection
{
    std::vector<SamplePtr> samples;

    bool empty() const;
};

/// Implementation of SearchDatabaseType from the mzIdentML schema.
///
/// A database for searching mass spectra. Examples include a set of
/// amino acid sequence entries, or annotated spectra libraries.
struct PWIZ_API_DECL SearchDatabase : public IdentifiableParamContainer
{
    SearchDatabase(const std::string& id_ = "",
                   const std::string& name_ = "");

    std::string location;
    std::string version;
    std::string releaseDate;
    long numDatabaseSequences;
    long numResidues;

    CVParam fileFormat;
    ParamContainer databaseName;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SearchDatabase);

/// Implementation of DBSequenceType from the mzIdentML schema.
///
/// A database sequence from the specified SearchDatabase (nucleic
/// acid or amino acid). If the sequence is nucleic acid, the source
/// nucleic acid sequence should be given in the seq attribute rather
/// than a translated sequence.
struct PWIZ_API_DECL DBSequence : public IdentifiableParamContainer
{
    DBSequence(const std::string id_ = "",
               const std::string name_ = "");

    int length;
    std::string accession;
    SearchDatabasePtr searchDatabasePtr;

    std::string seq;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(DBSequence);

/// Implementation of ModificationType from the mzIdentML schema.
///
/// A molecule modification specification. If n modifications have
/// been found on a peptide, there should be n instances of
/// Modification. If multiple modifications are provided as cvParams,
/// it is assumed that the modification is ambiguous i.e. one
/// modification or another. A cvParam must be provided with the
/// identification of the modification sourced from a suitable CV
/// e.g. UNIMOD. If the modification is not present in the CV (and
/// this will be checked by the semantic validator within a given
/// tolerance window), there is a â€œunknown modificationâ€ CV
/// term that must be used instead. A neutral loss should be defined
/// as an additional CVParam within Modification. If more complex
/// information should be given about neutral losses (such as
/// presence/absence on particular product ions), this can
/// additionally be encoded within the FragmentationArray.
struct PWIZ_API_DECL Modification : public ParamContainer
{
    Modification();

    int location;
    std::vector<char> residues;
    double avgMassDelta;
    double monoisotopicMassDelta;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Modification);

/// Implementation of SubstitutionModificationType from the mzIdentML
/// schema.
///
/// A modification where one residue is substituted by another (amino
/// acid change).
struct PWIZ_API_DECL SubstitutionModification
{
    SubstitutionModification();

    char originalResidue;
    char replacementResidue;
    int location;
    double avgMassDelta;
    double monoisotopicMassDelta;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SubstitutionModification);

/// Implementation of PeptideType from the mzIdentML schema.
///
/// One (poly)peptide (a sequence with modifications). The combination
/// of Peptide sequence and modifications must be unique in the file.
struct PWIZ_API_DECL Peptide : public IdentifiableParamContainer
{
    Peptide(const std::string& id="",
            const std::string& name="");

    std::string peptideSequence;
    std::vector<ModificationPtr> modification;
    std::vector<SubstitutionModificationPtr> substitutionModification;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Peptide);

/// Implementation of SearchModificationType from the mzIdentML schema.
///
/// Filters applied to the search database. The filter must include at
/// least one of Include and Exclude. If both are used, it is assumed
/// that inclusion is performed first.
struct PWIZ_API_DECL SearchModification : public ParamContainer
{
    SearchModification();

    bool fixedMod;
    double massDelta;
    std::vector<char> residues;
    CVParam specificityRules;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SearchModification);

/// Implementation of EnzymeType from the mzIdentML schema.
///
/// The details of an individual cleavage enzyme should be provided by
/// giving a regular expression or a CV term if a "standard" enzyme
/// cleavage has been performed.
struct PWIZ_API_DECL Enzyme : public Identifiable
{
    Enzyme(const std::string& id = "",
           const std::string& name = "");

    std::string nTermGain;
    std::string cTermGain;
    proteome::Digestion::Specificity terminalSpecificity;
    int missedCleavages;
    int minDistance;

    std::string siteRegexp;
    ParamContainer enzymeName;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Enzyme);

/// Implementation of EnzymesType from the mzIdentML schema.
///
/// The list of enzymes used in experiment.
struct PWIZ_API_DECL Enzymes
{
    boost::logic::tribool independent;

    std::vector<EnzymePtr> enzymes;

    bool empty() const;
};

/// Implementation of ResidueType from the mzIdentML schema.
///
/// Representation of the Residue tags that holds a letter code and
/// residue mass in Daltons (not including any fixed modifications).
struct PWIZ_API_DECL Residue
{
    Residue();

    char code;
    double mass;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Residue);

/// Implementation of AmbiguousResidueType from the mzIdentML schema.
///
/// Ambiguous residues e.g. X can be specified by the Code attribute
/// and a set of parameters for example giving the different masses
/// that will be used in the search.
struct PWIZ_API_DECL AmbiguousResidue : public ParamContainer
{
    AmbiguousResidue();

    char code;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(AmbiguousResidue);

/// Implementation of MassTableType from the mzIdentML schema.
///
/// Ambiguous residues e.g. X can be specified by the Code attribute
/// and a set of parameters for example giving the different masses
/// that will be used in the search.
struct PWIZ_API_DECL MassTable
{
    MassTable(const std::string id = "");

    std::string id;
    std::vector<int> msLevel;

    std::vector<ResiduePtr> residues;
    std::vector<AmbiguousResiduePtr> ambiguousResidue;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(MassTable);

/// Implementation of FilterType from the mzIdentML schema.
///
/// Filters applied to the search database. The filter must include at
/// least one of Include and Exclude. If both are used, it is assumed
/// that inclusion is performed first.
struct PWIZ_API_DECL Filter
{
    ParamContainer filterType;
    ParamContainer include;
    ParamContainer exclude;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Filter);

/// Implementation of TranslationTableType from the mzIdentML schema.
///
/// The table used to translate codons into nucleic acids e.g. by
/// reference to the NCBI translation table.
struct PWIZ_API_DECL TranslationTable : public IdentifiableParamContainer
{
    TranslationTable(const std::string& id = "",
                     const std::string& name = "");
};

TYPEDEF_SHARED_PTR(TranslationTable);

/// Implementation of DatabaseTranslationType from the mzIdentML schema.
///
/// A specification of how a nucleic acid sequence database was
/// translated for searching.
struct PWIZ_API_DECL DatabaseTranslation
{
    std::vector<int> frames;
    std::vector<TranslationTablePtr> translationTable;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(DatabaseTranslation);

/// Implementation of SpectrumIdentificationProtocolType from the
/// mzIdentML schema.
///
/// The parameters and settings of a SpectrumIdentification analysis.
struct PWIZ_API_DECL SpectrumIdentificationProtocol : public Identifiable
{
    SpectrumIdentificationProtocol(const std::string& id_ = "",
                                   const std::string& name_ = "");

    AnalysisSoftwarePtr analysisSoftwarePtr;

    CVParam searchType;
    ParamContainer additionalSearchParams;
    std::vector<SearchModificationPtr> modificationParams;
    Enzymes enzymes;
    std::vector<MassTablePtr> massTable;
    ParamContainer fragmentTolerance;
    ParamContainer parentTolerance;
    ParamContainer threshold;
    std::vector<FilterPtr> databaseFilters;
    DatabaseTranslationPtr databaseTranslation;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SpectrumIdentificationProtocol);

/// Implementation of MeasureType from the mzIdentML schema.
///
/// References to CV terms defining the measures about product ions to
/// be reported in SpectrumIdentificationItem.
struct PWIZ_API_DECL Measure : public IdentifiableParamContainer
{
    Measure(const std::string id = "",
            const std::string name = "");

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Measure);

/// Implementation of FragmentArrayType from the mzIdentML schema.
///
/// Contains the types of measures that will be reported in generic
/// arrays for each SpectrumIdentificationItem e.g. product ion m/z,
/// product ion intensity, product ion m/z error
struct PWIZ_API_DECL FragmentArray
{
    std::vector<double> values;
    MeasurePtr measurePtr;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(FragmentArray);

/// Implementation of IonTypeType from the mzIdentML schema.
///
/// IonType defines the index of fragmentation ions being reported,
/// importing a CV term for the type of ion e.g. b ion. Example: if b3
/// b7 b8 and b10 have been identified, the index attribute will
/// contain 3 7 8 10, and the corresponding values will be reported in
/// parallel arrays below
struct PWIZ_API_DECL IonType : public CVParam
{
    IonType();

    std::vector<int> index;
    int charge;
    std::vector<FragmentArrayPtr> fragmentArray;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(IonType);

/// Implementation of PeptideEvidenceType from the mzIdentML schema.
///
/// PeptideEvidence links a specific Peptide element to a specific
/// position in a DBSequence. There must only be one PeptideEvidence
/// item per Peptide-to-DBSequence-position.
struct PWIZ_API_DECL PeptideEvidence : public IdentifiableParamContainer
{
    PeptideEvidence(const std::string& id = "",
                    const std::string& name = "");

    PeptidePtr peptidePtr;
    DBSequencePtr dbSequencePtr;
    int start;
    int end;
    char pre;
    char post;
    TranslationTablePtr translationTablePtr;
    int frame;
    bool isDecoy;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(PeptideEvidence);

/// Implementation of SequenceCollectionType from the mzIdentML schema.
///
/// The collection of sequences (DBSequence or Peptide) identified and
/// their relationship between each other (PeptideEvidence) to be
/// referenced elsewhere in the results.
struct PWIZ_API_DECL SequenceCollection
{
    std::vector<DBSequencePtr> dbSequences;
    std::vector<PeptidePtr> peptides;
    std::vector<PeptideEvidencePtr> peptideEvidence;
    bool empty() const;
};

/// Implementation of SpectrumIdentificationItemType from the
/// mzIdentML schema.
///
/// An identification of a single (poly)peptide, resulting from
/// querying an input spectra, along with the set of confidence values
/// for that identification.  PeptideEvidence elements should be given
/// for all mappings of the corresponding Peptide sequence within
/// protein sequences.
struct PWIZ_API_DECL SpectrumIdentificationItem : public IdentifiableParamContainer
{
    SpectrumIdentificationItem(const std::string& id = "",
                               const std::string& name = "");

    int chargeState;
    double experimentalMassToCharge;
    double calculatedMassToCharge;
    double calculatedPI;
    PeptidePtr peptidePtr;
    int rank;
    bool passThreshold;
    MassTablePtr massTablePtr;
    SamplePtr samplePtr;

    std::vector<PeptideEvidencePtr> peptideEvidencePtr;
    std::vector<IonTypePtr> fragmentation;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SpectrumIdentificationItem);

/// Implementation of SpectraDataType from the mzIdentML schema.
///
/// A data set containing spectra data (consisting of one or more
/// spectra).
struct PWIZ_API_DECL SpectraData : public Identifiable
{
    SpectraData(const std::string id = "",
                const std::string name = "");

    std::string location;

    std::vector<std::string> externalFormatDocumentation;
    CVParam fileFormat;
    CVParam spectrumIDFormat;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SpectraData);

/// Implementation of SpectrumIdentificationResultType from the
/// mzIdentML schema.
///
/// All identifications made from searching one spectrum. For PMF
/// data, all peptide identifications will be listed underneath as
/// SpectrumIdentificationItems. For MS/MS data, there will be ranked
/// SpectrumIdentificationItems corresponding to possible different
/// peptide IDs.
struct PWIZ_API_DECL SpectrumIdentificationResult : public IdentifiableParamContainer
{
    SpectrumIdentificationResult(const std::string& id_ = "",
                                 const std::string& name_ = "");

    std::string spectrumID;
    SpectraDataPtr spectraDataPtr;

    std::vector<SpectrumIdentificationItemPtr> spectrumIdentificationItem;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SpectrumIdentificationResult);

/// Implementation of SpectrumIdentificationListType from the
/// mzIdentML schema.
///
/// Represents the set of all search results from
/// SpectrumIdentification.
struct PWIZ_API_DECL SpectrumIdentificationList : public IdentifiableParamContainer
{
    SpectrumIdentificationList(const std::string& id_ = "",
                               const std::string& name_ = "");

    long numSequencesSearched;

    std::vector<MeasurePtr> fragmentationTable;
    std::vector<SpectrumIdentificationResultPtr> spectrumIdentificationResult;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SpectrumIdentificationList);

/// Implementation of SpectrumIdentificationType from the mzIdentML schema.
///
/// An Analysis which tries to identify peptides in input spectra,
/// referencing the database searched, the input spectra, the output
/// results and the protocol that is run.
struct PWIZ_API_DECL SpectrumIdentification : public Identifiable
{
    SpectrumIdentification(const std::string& id_ = "",
                           const std::string& name_ = "");

    SpectrumIdentificationProtocolPtr spectrumIdentificationProtocolPtr;
    SpectrumIdentificationListPtr spectrumIdentificationListPtr;
    std::string activityDate;

    std::vector<SpectraDataPtr> inputSpectra;
    std::vector<SearchDatabasePtr> searchDatabase;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SpectrumIdentification);

/// Implementation of ProteinDetectionProtocolType from the mzIdentML
/// schema.
///
/// The parameters and settings of a ProteinDetection process.
struct PWIZ_API_DECL ProteinDetectionProtocol : public Identifiable
{
    ProteinDetectionProtocol(const std::string& id_ = "",
                             const std::string& name_ = "");

    AnalysisSoftwarePtr analysisSoftwarePtr;

    ParamContainer analysisParams;
    ParamContainer threshold;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(ProteinDetectionProtocol);

/// Implementation of PeptideHypothesisType from the mzIdentML schema.
///
/// Peptide evidence on which this ProteinHypothesis is based by
/// reference to a PeptideEvidence element.
struct PWIZ_API_DECL PeptideHypothesis
{
    PeptideEvidencePtr peptideEvidencePtr;
    std::vector<SpectrumIdentificationItemPtr> spectrumIdentificationItemPtr;

    bool empty() const;
};

/// Implementation of ProteinDetectionHypothesisType from the
/// mzIdentML schema.
///
/// A single result of the ProteinDetection analysis (i.e. a protein).
struct PWIZ_API_DECL ProteinDetectionHypothesis : public IdentifiableParamContainer
{
    ProteinDetectionHypothesis(const std::string& id_ = "",
                               const std::string& name_ = "");

    DBSequencePtr dbSequencePtr;
    bool passThreshold;
    std::vector<PeptideHypothesis> peptideHypothesis;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(ProteinDetectionHypothesis);

/// Implementation of ProteinAmbiguityGroupType from the mzIdentML schema.
///
/// A set of logically related results from a protein detection, for
/// example to represent conflicting assignments of peptides to
/// proteins.
struct PWIZ_API_DECL ProteinAmbiguityGroup : public IdentifiableParamContainer
{
    ProteinAmbiguityGroup(const std::string& id_ = "",
                          const std::string& name_ = "");

    std::vector<ProteinDetectionHypothesisPtr> proteinDetectionHypothesis;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(ProteinAmbiguityGroup);

/// Implementation of ProteinDetectionListType from the mzIdentML schema.
///
/// The protein list resulting from a protein detection process.
struct PWIZ_API_DECL ProteinDetectionList : public IdentifiableParamContainer
{
    ProteinDetectionList(const std::string& id_ = "",
                         const std::string& name_ = "");

    std::vector<ProteinAmbiguityGroupPtr> proteinAmbiguityGroup;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(ProteinDetectionList);

/// Implementation of ProteinDetectionType from the mzIdentML schema.
///
/// An Analysis which assembles a set of peptides (e.g. from a spectra
/// search analysis) to proteins.
struct PWIZ_API_DECL ProteinDetection : public Identifiable
{
    ProteinDetection(const std::string id_ = "",
                     const std::string name_ = "");

    ProteinDetectionProtocolPtr proteinDetectionProtocolPtr;
    ProteinDetectionListPtr proteinDetectionListPtr;
    std::string activityDate;

    std::vector<SpectrumIdentificationListPtr> inputSpectrumIdentifications;

    virtual bool empty() const;
};

TYPEDEF_SHARED_PTR(ProteinDetection);

/// Implementation of AnalysisCollectionType from the mzIdentML schema
///
/// The analyses performed to get the results, which map the input and
/// output data sets. Analyses are for example: SpectrumIdentification
/// (resulting in peptides) or ProteinDetection (assemble proteins
/// from peptides).
struct PWIZ_API_DECL AnalysisCollection
{
    std::vector<SpectrumIdentificationPtr> spectrumIdentification;
    ProteinDetection proteinDetection;

    bool empty() const;
};

/// Implementation of AnalysisProtocolCollectionType from the
/// mzIdentML schema.
///
/// The collection of protocols which include the parameters and
/// settings of the performed analyses.
struct PWIZ_API_DECL AnalysisProtocolCollection
{
    std::vector<SpectrumIdentificationProtocolPtr> spectrumIdentificationProtocol;
    std::vector<ProteinDetectionProtocolPtr> proteinDetectionProtocol;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(AnalysisProtocolCollection);

/// Implementation of SourceFileType from the mzIdentML schema.
///
/// A file from which this mzIdentML instance was created.
struct PWIZ_API_DECL SourceFile : public IdentifiableParamContainer
{
    std::string location;
    CVParam fileFormat;

    std::vector<std::string> externalFormatDocumentation;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(SourceFile);

/// Implementation of the InputsType from the mzIdentML schema.
///
/// The inputs to the analyses including the databases searched, the
/// spectral data and the source file converted to mzIdentML.
///
/// Input element. Contains 0+ of SourceFile, SearchDatabase,
/// SpectraData
struct PWIZ_API_DECL Inputs
{
    // Replace these 3 members w/ their types
    std::vector<SourceFilePtr> sourceFile;
    std::vector<SearchDatabasePtr> searchDatabase;
    std::vector<SpectraDataPtr> spectraData;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(Inputs);

/// Implementation of AnalysisDataType from the mzIdentML schema.
///
/// Data sets generated by the analyses, including peptide and protein
/// lists.
struct PWIZ_API_DECL AnalysisData
{
    std::vector<SpectrumIdentificationListPtr> spectrumIdentificationList;
    ProteinDetectionListPtr proteinDetectionListPtr;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(AnalysisData);

/// Implementation of DataCollectionType from the mzIdentML schema.
///
/// The collection of input and output data sets of the analyses.
struct PWIZ_API_DECL DataCollection
{
    Inputs inputs;
    AnalysisData analysisData;

    bool empty() const;
};

TYPEDEF_SHARED_PTR(DataCollection);

namespace IO {struct HandlerIdentData;} // forward declaration for friend

/// Implementation of the MzIdentMLType from the mzIdentML schema.
///
/// The upper-most hierarchy level of mzIdentML with sub-containers
/// for example describing software, protocols and search results
/// (spectrum identifications or protein detection results).
struct PWIZ_API_DECL IdentData : public Identifiable
{
    IdentData(const std::string& id_ = "",
              const std::string& creationDate_ = "");

    // attributes included in the IdentData schema
    std::string creationDate;

    ///////////////////////////////////////////////////////////////////////
    // Elements

    std::vector<CV> cvs;

    std::vector<AnalysisSoftwarePtr> analysisSoftwareList;

    Provider provider;

    std::vector<ContactPtr> auditCollection;

    AnalysisSampleCollection analysisSampleCollection;

    SequenceCollection sequenceCollection;

    AnalysisCollection analysisCollection;

    AnalysisProtocolCollection analysisProtocolCollection;

    DataCollection dataCollection;

    std::vector<BibliographicReferencePtr> bibliographicReference;

    bool empty() const;

    /// returns the version of this mzIdentML document;
    /// for a document created programmatically, the version is the current release version of mzIdentML;
    /// for a document created from a file/stream, the version is the schema version read from the file/stream
    const std::string& version() const;

    protected:
    std::string version_; // schema version read from the file/stream
    friend struct IO::HandlerIdentData;
};

TYPEDEF_SHARED_PTR(IdentData);

/// given a protocol and a PeptideEvidence instance, returns the PeptideEvidence as a DigestedPeptide instance
PWIZ_API_DECL proteome::DigestedPeptide digestedPeptide(const SpectrumIdentificationProtocol& sip, const PeptideEvidence& peptideEvidence);

/// given a protocol and a SpectrumIdentificationItem, builds a set of DigestedPeptides
PWIZ_API_DECL std::vector<proteome::DigestedPeptide> digestedPeptides(const SpectrumIdentificationProtocol& sip, const SpectrumIdentificationItem& sii);

/// creates a proteome::Peptide from an identdata::Peptide
PWIZ_API_DECL proteome::Peptide peptide(const Peptide& peptide);

/// creates a proteome::Modification from an identdata::Modification
PWIZ_API_DECL proteome::Modification modification(const Modification& mod);

/// returns a cleavage agent CVID for an identdata::Enzyme
PWIZ_API_DECL CVID cleavageAgent(const Enzyme& ez);

/// returns a list of cleavage agent CVIDs for an identdata::Enzymes instance
PWIZ_API_DECL std::vector<CVID> cleavageAgents(const Enzymes& enzymes);

/// returns a regular expression for an identdata::Enzyme
PWIZ_API_DECL std::string cleavageAgentRegex(const Enzyme& ez);

/// returns a list of regular expressions for an identdata::Enzymes instance
PWIZ_API_DECL std::vector<std::string> cleavageAgentRegexes(const Enzymes& enzymes);

/// sets Unimod CV terms (if possible) for all SearchModifications and Modification elements
PWIZ_API_DECL void snapModificationsToUnimod(const SpectrumIdentification& si);

} // namespace identdata
} // namespace pwiz

#endif // _IDENTDATA_HPP_

ext: hpp

max_stars_repo_name: vagisha/pwiz

max_issues_repo_name: vagisha/pwiz

max_forks_repo_name: vagisha/pwiz


text:
/*
 * $Id: vecio.cc,v 1.4 2006/06/01 01:20:41 julianc Exp $
 *
 * Copyright (C) 1997 Todd Veldhuizen <tveldhui@oonumerics.org>
 * All rights reserved.  Please see <blitz/blitz.h> for terms and
 * conditions of use.
 *
 */

#ifndef BZ_VECIO_CC
#define BZ_VECIO_CC

#ifndef BZ_VECTOR_H
 #include <blitz/vector.h>
#endif

BZ_NAMESPACE(blitz)

// This version of operator<< is provided as a temporary measure
// only.  It will be revised in a future release.
// NEEDS_WORK

template<typename P_numtype>
ostream& operator<<(ostream& os, const Vector<P_numtype>& x)
{
    os << x.length() << endl << "[ ";
    for (int i=0; i < x.length(); ++i)
    {
        os << x[i] << " ";
    }
    os << "]";
    return os;
}

template<typename P_expr>
ostream& operator<<(ostream& os, _bz_VecExpr<P_expr> expr)
{
    Vector<_bz_typename P_expr::T_numtype> result(expr);
    os << result;
    return os;
}

template<typename P_numtype>
istream& operator>>(istream& is, Vector<P_numtype>& x)
{
    int length;
    char sep;

    is >> length;
    BZPRECHECK(!is.bad(), "Premature end of input while scanning Vector");
    x.resize(length);

    is >> sep;
    BZPRECHECK(sep == '[', "Format error while scanning input \
Vector \n (expected '[' before beginning of Vector data)");
    for (int i=0; i < x.length(); ++i) {
        BZPRECHECK(!is.bad(), "Premature end of input while scanning Vector");
        is >> x(i);
    }

    is >> sep;
    BZPRECHECK(sep == ']', "Format error while scanning input \
Vector \n (expected ']' after end of Vector data)");
    return is;
}

BZ_NAMESPACE_END

#endif // BZ_VECIO_CC


text:
/*
 * Copyright 2016 The Cartographer Authors
 *
 * 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.
 */

#include "cartographer/io/pcd_intensity_writing_points_processor.h"

#include <iomanip>
#include <sstream>
#include <iostream>
#include <string>
#include <algorithm>

#include <Eigen/Dense>
#include <Eigen/Core>

#include "absl/memory/memory.h"
#include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/io/points_batch.h"
#include "glog/logging.h"

namespace cartographer {
namespace io {

namespace {

// Writes the PCD header claiming 'num_points' will follow it into
// 'output_file'.
// https://pointclouds.org/documentation/tutorials/pcd_file_format.html
void WriteBinaryPcdIntensityHeader(const bool has_color, const bool has_intensity, const bool has_reflectivity,
                            const bool has_ambient, const bool has_range, const bool has_ring, const int64 num_points,
                          FileWriter* const file_writer) {
  std::cerr << "has_color " << has_color << std::endl;
  std::cerr << "has_intensity " << has_intensity << std::endl;
  std::cerr << "has_reflectivity " << has_reflectivity << std::endl;
  std::cerr << "has_ambient " << has_ambient << std::endl;
  std::cerr << "has_range " << has_range << std::endl;
  std::cerr << "has_ring " << has_ring << std::endl;

  std::string color_header_field = !has_color ? "" : " rgb";
  std::string color_header_type = !has_color ? "" : " U";
  std::string color_header_size = !has_color ? "" : " 4";
  std::string color_header_count = !has_color ? "" : " 1";

  std::string intensity_header_field = !has_intensity ? "" : " intensity";
  std::string intensity_header_type = !has_intensity ? "" : " U";
  std::string intensity_header_size = !has_intensity ? "" : " 4";
  std::string intensity_header_count = !has_intensity ? "" : " 1";

  std::string reflectivity_header_field = !has_reflectivity ? "" : " reflectivity";
  std::string reflectivity_header_type = !has_reflectivity ? "" : " U";
  std::string reflectivity_header_size = !has_reflectivity ? "" : " 2";
  std::string reflectivity_header_count = !has_reflectivity ? "" : " 1";

  std::string ambient_header_field = !has_ambient ? "" : " ambient";
  std::string ambient_header_type = !has_ambient ? "" : " U";
  std::string ambient_header_size = !has_ambient ? "" : " 4";
  std::string ambient_header_count = !has_ambient ? "" : " 1";

  std::string range_header_field = !has_range ? "" : " range";
  std::string range_header_type = !has_range ? "" : " U";
  std::string range_header_size = !has_range ? "" : " 4";
  std::string range_header_count = !has_range ? "" : " 1";

  std::string ring_header_field = !has_ring ? "" : " ring";
  std::string ring_header_type = !has_ring ? "" : " U";
  std::string ring_header_size = !has_ring ? "" : " 2";
  std::string ring_header_count = !has_ring ? "" : " 1";

  std::ostringstream stream;
  stream << "# generated by Cartographer\n"
         << "VERSION .7\n"
         << "FIELDS x y z"  << color_header_field << intensity_header_field << reflectivity_header_field << ambient_header_field << range_header_field << ring_header_field << " frame" << "\n"
         << "SIZE 4 4 4"    << color_header_size  << intensity_header_size  << reflectivity_header_size  << ambient_header_size  << range_header_size  << ring_header_size  << " 4" << "\n"
         << "TYPE F F F"    << color_header_type  << intensity_header_type  << reflectivity_header_type  << ambient_header_type  << range_header_type  << ring_header_type  << " F"  << "\n"
         << "COUNT 1 1 1"   << color_header_count << intensity_header_count << reflectivity_header_count << ambient_header_count << range_header_count << ring_header_count << " 1" << "\n"
         << "WIDTH " << std::setw(15) << std::setfill('0') << num_points << "\n"
         << "HEIGHT 1\n"
         << "VIEWPOINT 0 0 0 1 0 0 0\n"
         << "POINTS " << std::setw(15) << std::setfill('0') << num_points
         << "\n"
         << "DATA binary\n";
  const std::string out = stream.str();
  file_writer->WriteHeader(out.data(), out.size());
}

void WriteBinaryPcdIntensityPointCoordinate(const Eigen::Vector3f& point,
                                   FileWriter* const file_writer) {
//  unsigned int u_intensity = (unsigned int)intensity;
  char buffer[12];
  memcpy(buffer, &point[0], sizeof(float));
  memcpy(buffer + 4, &point[1], sizeof(float));
  memcpy(buffer + 8, &point[2], sizeof(float));
//  memcpy(buffer + 12, &u_intensity, sizeof(unsigned int));
  CHECK(file_writer->Write(buffer, 12));
}

void WriteBinaryFloat(const float& value,
                                   FileWriter* const file_writer) {
  char buffer[4];
  memcpy(buffer, &value, sizeof(float));
  CHECK(file_writer->Write(buffer, 4));
}

void WriteUInt16_fieldsize_2(const uint16_t& value,
                                   FileWriter* const file_writer) {
  char buffer[2];
  memcpy(buffer, &value, sizeof(uint16_t));
  CHECK(file_writer->Write(buffer, 2));
}

void WriteUInt8_fieldsize_2(const uint8_t& value,
                                   FileWriter* const file_writer) {
  char buffer[2];
  memcpy(buffer, &value, sizeof(uint8_t));
  CHECK(file_writer->Write(buffer, 2));
}

void WriteUInt16_fieldsize_4(const uint16_t& value,
                                   FileWriter* const file_writer) {
  char buffer[4];
  memcpy(buffer, &value, sizeof(uint16_t));
  CHECK(file_writer->Write(buffer, 4));
}

void WriteUInt32_with_fieldsize_4(const uint32_t& value,
                                   FileWriter* const file_writer) {
  char buffer[4];
  memcpy(buffer, &value, sizeof(uint32_t));
  CHECK(file_writer->Write(buffer, 4));
}

void WriteBinaryFloatAsUnsignedInt(const float& value,
                                   FileWriter* const file_writer) {
  unsigned int u_value = (unsigned int)value;
  char buffer[4];
  memcpy(buffer, &u_value, sizeof(unsigned int));
  CHECK(file_writer->Write(buffer, 4));
}

void WriteBinaryInteger(const int& value,
                                   FileWriter* const file_writer) {
  char buffer[4];
  memcpy(buffer, &value, sizeof(int));
  CHECK(file_writer->Write(buffer, 4));
}
void WriteBinaryChar(const char& value,
                                   FileWriter* const file_writer) {
  char buffer[1];
  memcpy(buffer, &value, sizeof(char));
  CHECK(file_writer->Write(buffer, 1));
}

void WriteBinaryPcdPointColor(const Uint8Color& color,
                              FileWriter* const file_writer) {
  char buffer[4];
  buffer[0] = color[2];
  buffer[1] = color[1];
  buffer[2] = color[0];
  buffer[3] = 0;
  CHECK(file_writer->Write(buffer, 4));
}

}  // namespace

std::unique_ptr<PcdIntensityWritingPointsProcessor>
PcdIntensityWritingPointsProcessor::FromDictionary(
    FileWriterFactory file_writer_factory,
    common::LuaParameterDictionary* const dictionary,
    PointsProcessor* const next) {
  return absl::make_unique<PcdIntensityWritingPointsProcessor>(
      file_writer_factory(dictionary->GetString("filename")), dictionary->GetString("export_fields"), next);
}

PcdIntensityWritingPointsProcessor::PcdIntensityWritingPointsProcessor(
    std::unique_ptr<FileWriter> file_writer, std::string export_fields, PointsProcessor* const next)
    : next_(next),
      num_points_(0),
      has_colors_(false),
      has_intensity_(false),
      has_reflectivity_(false),
      has_ambient_(false),
      has_range_(false),
      has_ring_(false),
      export_fields_(export_fields),
      file_writer_(std::move(file_writer)) {
        std::cerr << "export_fields_: " << export_fields_ << std::endl;
        if (!export_fields_.empty()) {
          export_reflectivity_ = export_fields_.find("reflectivity") != std::string::npos;
          export_ambient_ = export_fields_.find("ambient") != std::string::npos;
          export_range_ = export_fields_.find("range") != std::string::npos;
          export_ring_ = export_fields_.find("ring") != std::string::npos;
        } else {
          export_reflectivity_ = true;
          export_ambient_ = true;
          export_range_ = true;
          export_ring_ = true;
        }
        std::cerr << "export reflectivity: " << export_reflectivity_ << std::endl;
        std::cerr << "export ambient: " << export_ambient_ << std::endl;
        std::cerr << "export range: " << export_range_ << std::endl;
        std::cerr << "export ring: " << export_ring_ << std::endl;
      }

PointsProcessor::FlushResult PcdIntensityWritingPointsProcessor::Flush() {
  WriteBinaryPcdIntensityHeader(
    has_colors_,
    has_intensity_,
    has_reflectivity_ && export_reflectivity_,
    has_ambient_ && export_ambient_,
    has_range_ && export_range_,
    has_ring_ && export_ring_,
    num_points_,
    file_writer_.get()
  );
  CHECK(file_writer_->Close());

  switch (next_->Flush()) {
    case FlushResult::kFinished:
      return FlushResult::kFinished;

    case FlushResult::kRestartStream:
      LOG(FATAL) << "PCD generation must be configured to occur after any "
                    "stages that require multiple passes.";
  }
  LOG(FATAL);
}

void PcdIntensityWritingPointsProcessor::Process(std::unique_ptr<PointsBatch> batch) {
  if (batch->points.empty()) {
    next_->Process(std::move(batch));
    return;
  }

  auto it = std::find(registered_frame_ids_.begin(), registered_frame_ids_.end(), batch->frame_id);
  if (it == registered_frame_ids_.end()) {
    registered_frame_ids_.push_back(batch->frame_id);
    it = std::find(registered_frame_ids_.begin(), registered_frame_ids_.end(), batch->frame_id);
  }
  float internal_frame_id = static_cast<float>(it - registered_frame_ids_.begin());

  if (num_points_ == 0) {
    has_colors_ = !batch->colors.empty();
    has_intensity_ = !batch->intensities.empty();
    has_reflectivity_ = !batch->reflectivities.empty();
    has_ambient_ = !batch->ambients.empty();
    has_range_ = !batch->ranges.empty();
    has_ring_ = !batch->rings.empty();
    WriteBinaryPcdIntensityHeader(
       has_colors_,
       has_intensity_,
       has_reflectivity_ && export_reflectivity_,
       has_ambient_ && export_ambient_,
       has_range_ && export_range_,
       has_ring_ && export_ring_,
       0,
       file_writer_.get());
  }

  std::vector<uint32_t> range_values = batch->ranges;
  Eigen::Matrix<uint32_t, Eigen::Dynamic, 1> eigen_range_values = Eigen::Map<Eigen::Matrix<uint32_t, Eigen::Dynamic, 1>, Eigen::Unaligned>(range_values.data(), range_values.size());
  Eigen::VectorXf float_eigen_range_values = eigen_range_values.cast <float> ();

//<< color_header_field << intensity_header_field << reflectivity_header_field << ambient_header_field << range_header_field << ring_header_field
  for (size_t i = 0; i < batch->points.size(); ++i) {
    WriteBinaryPcdIntensityPointCoordinate(batch->points[i].position,
                                  file_writer_.get());
    if (!batch->colors.empty()) {
      WriteBinaryPcdPointColor(ToUint8Color(batch->colors[i]),
                               file_writer_.get());
    }
    if (!batch->intensities.empty()) {
      WriteBinaryFloatAsUnsignedInt(batch->intensities[i], file_writer_.get());
    }
    if (!batch->reflectivities.empty() && export_reflectivity_) {
      uint16_t reflectivity_value = (uint16_t)batch->reflectivities[i];
      WriteUInt16_fieldsize_2(reflectivity_value, file_writer_.get());
    }
    if (!batch->ambients.empty() && export_ambient_) {
      uint16_t ambient_value = (uint16_t)batch->ambients[i];
      WriteUInt16_fieldsize_4(ambient_value, file_writer_.get());
    }
    if (!batch->ranges.empty() && export_range_) {
      WriteBinaryFloatAsUnsignedInt(float_eigen_range_values[i], file_writer_.get());
//      uint32_t range_value = batch->ranges[i];
//      WriteUInt32_with_fieldsize_4(range_value, file_writer_.get());
    }
    if (!batch->rings.empty() && export_ring_) {
      uint8_t ring_value = (uint8_t)batch->rings[i];
      WriteBinaryFloat(ring_value, file_writer_.get());
    }
    // write the internal frame_id of the given view
//    WriteBinaryChar(internal_frame_id, file_writer_.get());
   // std::cout << "[" << batch->frame_id << "] " << "internal frame id: " << internal_frame_id << " as integer: " << (int)internal_frame_id << " as float: " << (float)internal_frame_id << " frame_id: " << batch->frame_id << std::endl;
    WriteBinaryFloat((float)internal_frame_id, file_writer_.get());
 //    std::cout << "############################################################" << std::endl;
    ++num_points_;
  }
  next_->Process(std::move(batch));
}

}  // namespace io
}  // namespace cartographer

max_stars_repo_name: meyerjo/cartographer

max_issues_repo_name: meyerjo/cartographer

max_forks_repo_name: meyerjo/cartographer


text:
#include "HoloSession.hpp"
#include <holoutils/HoloUtils.hpp>

#include <vector>
#include <chrono>
#include <ctime>
#include <future>

#include <boost/smart_ptr.hpp>

#include <pcl/filters/approximate_voxel_grid.h>

using namespace holo;
using namespace holo::net;

HoloSession::HoloSession()
{

}

HoloSession::HoloSession(std::unique_ptr<holo::capture::IHoloCapture> && capture,
	std::unique_ptr<holo::capture::IHoloCaptureAudio> && audioCapture,
	std::unique_ptr<holo::input::IHoloInputDevice> && inputDevice,
	std::unique_ptr<holo::codec::IHoloCodec<holo::HoloRGBAZMat>> && encoderRGBAZ,
	std::unique_ptr<holo::codec::IHoloCodec<holo::HoloRGBAZMat>> && decoderRGBAZ,
	std::unique_ptr<holo::codec::IHoloCodec<holo::HoloCloud>> && encoderCloud,
	std::unique_ptr<holo::codec::IHoloCodec<holo::HoloCloud>> && decoderCloud,
	std::unique_ptr<holo::codec::IHoloCodec<std::vector<uchar>>> && audioEncoder,
	std::unique_ptr<holo::codec::IHoloCodec<std::vector<uchar>>> && audioDecoder,
	boost::shared_ptr<holo::render::IHoloRender> && render,
	std::unique_ptr<holo::render::IHoloRenderAudio> && audioRender,
	std::shared_ptr<holo::net::HoloNetSession> netSession, holo::net::HoloNetProtocolHandshake remoteInfo,
	bool enableVisualFeedback
	) :
	shouldCallback_(false),
	shouldCapture_(false),
	shouldEncode_(false),
	shouldDecode_(false),
	shouldRender_(false),
	isRunning_(false),
	remoteInfo_(remoteInfo),
	worldConvertCache_(),
	localCloudCallback_(nullptr),
	localRGBAZCallback_(nullptr),
	localAudioCallback_(nullptr),
	remoteCloudCallback_(nullptr),
	remoteRGBAZCallback_(nullptr),
	remoteAudioCallback_(nullptr),
	enableVisualFeedback_(enableVisualFeedback)
{
	logger_ = log4cxx::Logger::getLogger("edu.mit.media.obmg.holosuite.session");

	capture_ = std::move(capture);
	audioCapture_ = std::move(audioCapture);
	inputDevice_ = std::move(inputDevice);
	rgbazDecoder_ = std::move(decoderRGBAZ);
	rgbazEncoder_ = std::move(encoderRGBAZ);
	cloudDecoder_ = std::move(decoderCloud);
	cloudEncoder_ = std::move(encoderCloud);
	audioEncoder_ = std::move(audioEncoder);
	audioDecoder_ = std::move(audioDecoder);
	netSession_ = netSession;
	render_ = std::move(render);
	audioRender_ = std::move(audioRender);

	LOG4CXX_DEBUG(logger_, "HoloSession object instantiated with custom objects");
}

bool HoloSession::start()
{
	LOG4CXX_INFO(logger_, "Starting session threads...");
	std::future<void> objectTrackerFuture;

	objectTracker_ = boost::shared_ptr<holo::render::HoloRenderObjectTracker>(new holo::render::HoloRenderObjectTracker);

	objectTrackerFuture =
		std::async(std::launch::async,
		[&]()
	{
		objectTracker_->Populate3DObjects(boost::filesystem::current_path().string());
	});

	haveLocalCloud_ = false;
	haveLocalRGBAZ_ = false;
	haveRemoteCloud_ = false;
	haveRemoteCloudCompressed_ = false;
	haveRemoteAudio_ = false;
	haveRemoteAudioCompressed_ = false;
	haveRemoteRGBAZ_ = false;
	haveRemoteRGBAZCompressed_ = false;

	//allocate and setup remote cloud
	remoteCloud_ = HoloCloudPtr(new HoloCloud(remoteInfo_.rgbazWidth, remoteInfo_.rgbazHeight));
	remoteCloud_->is_dense = false;
	remoteCloud_->sensor_origin_.setZero();
	remoteCloud_->sensor_orientation_.setIdentity();

	//create convert cache for remote cloud so we can reproject to real-world coordinates
	worldConvertCache_.xzFactor = tan((remoteInfo_.captureHOV * M_PI / 180.0f) / 2) * 2;
	worldConvertCache_.yzFactor = tan((remoteInfo_.captureVOV * M_PI / 180.0f) / 2) * 2;
	worldConvertCache_.resolutionX = remoteInfo_.rgbazWidth;
	worldConvertCache_.resolutionY = remoteInfo_.rgbazHeight;
	worldConvertCache_.halfResX = worldConvertCache_.resolutionX / 2;
	worldConvertCache_.halfResY = worldConvertCache_.resolutionY / 2;
	worldConvertCache_.coeffX = worldConvertCache_.resolutionX / worldConvertCache_.xzFactor;
	worldConvertCache_.coeffY = worldConvertCache_.resolutionY / worldConvertCache_.yzFactor;

	shouldCapture_ = capture_ ? true : false;
	shouldRender_ = render_ ? true : false;
	shouldInteract_ = inputDevice_ ? true : false;

	shouldEncode_ = rgbazEncoder_ || cloudEncoder_ ? true : false;
	shouldDecode_ = rgbazDecoder_ || cloudDecoder_ ? true : false;

	shouldRecv_ = netSession_ ? true : false;

	shouldCaptureAudio_ = audioCapture_ ? true : false;
	shouldEncodeAudio_ = shouldCaptureAudio_.load();

	shouldRenderAudio_ = audioRender_ ? true : false;
	shouldDecodeAudio_ = shouldRenderAudio_.load();

	shouldCallback_ = localAudioCallback_ || localCloudCallback_ || localRGBAZCallback_ || remoteAudioCallback_ || remoteCloudCallback_ || remoteRGBAZCallback_ ? true : false;

	if (shouldCapture_)
		captureThread_ = std::thread(&HoloSession::captureLoop, this);

	if (shouldInteract_)
		interactionThread_ = std::thread(&HoloSession::interactionLoop, this);

	if (shouldEncode_)
		encodeThread_ = std::thread(&HoloSession::encodeLoop, this);

	if (shouldDecode_)
		decodeThread_ = std::thread(&HoloSession::decodeLoop, this);

	if (shouldRender_)
		renderThread_ = std::thread(&HoloSession::renderLoop, this);

	if (shouldRecv_)
		netRecvThread_ = std::thread(&HoloSession::netRecvLoop, this);

	if (shouldCaptureAudio_)
		captureAudioThread_ = std::thread(&HoloSession::captureAudioLoop, this);

	if (shouldEncodeAudio_)
		encodeAudioThread_ = std::thread(&HoloSession::encodeAudioLoop, this);

	if (shouldRenderAudio_)
		renderAudioThread_ = std::thread(&HoloSession::renderAudioLoop, this);

	if (shouldDecodeAudio_)
		decodeAudioThread_ = std::thread(&HoloSession::decodeAudioLoop, this);

	if (shouldCallback_)
	{
		if (remoteCloudCallback_)
			remoteCloudCallbackThread_ = std::thread(std::bind(&HoloSession::callbackLoop, this, HOLO_SESSION_CALLBACK_REMOTE_CLOUD));
		if (localCloudCallback_)
			localCloudCallbackThread_ = std::thread(std::bind(&HoloSession::callbackLoop, this, HOLO_SESSION_CALLBACK_LOCAL_CLOUD));
		if (localRGBAZCallback_)
			localRGBAZCallbackThread_ = std::thread(std::bind(&HoloSession::callbackLoop, this, HOLO_SESSION_CALLBACK_LOCAL_RGBAZ));
		if (remoteRGBAZCallback_)
			remoteRGBAZCallbackThread_ = std::thread(std::bind(&HoloSession::callbackLoop, this, HOLO_SESSION_CALLBACK_REMOTE_RGBAZ));
		if (localAudioCallback_)
			localAudioCallbackThread_ = std::thread(std::bind(&HoloSession::callbackLoop, this, HOLO_SESSION_CALLBACK_LOCAL_AUDIO));
		if (remoteAudioCallback_)
			remoteAudioCallbackThread_ = std::thread(std::bind(&HoloSession::callbackLoop, this, HOLO_SESSION_CALLBACK_REMOTE_AUDIO));
	}

	if (capture_ && netSession_)
	{
		objectTrackerFuture.wait();
		sendAllObjects();
	}

	shouldTrackObjects_ = true;

	if (shouldTrackObjects_)
		objectTrackerThread_ = std::thread(&HoloSession::objectTrackerLoop, this);

	isRunning_ = true;

	return isRunning();
}

void HoloSession::stop()
{

	std::unique_lock<std::mutex> stoppingLock(stoppingMutex_);
	//stoppingMutex_.lock();

	//if (isRunning_)
	//{

		//isRunning_ = false;

		if (shouldCapture_)
		{
			shouldCapture_ = false;
			captureThread_.join();
		}

		if (shouldInteract_)
		{
			shouldInteract_ = false;
			interactionThread_.join();
		}

		if (shouldTrackObjects_)
		{
			shouldTrackObjects_ = false;
			objectTrackerThread_.join();
		}

		if (shouldRecv_)
		{
			shouldRecv_ = false;
			netRecvThread_.join();
		}

		if (shouldRender_)
		{
			shouldRender_ = false;
			renderThread_.join();
		}

		if (shouldDecode_)
		{
			shouldDecode_ = false;
			decodeThread_.join();
		}

		if (shouldEncode_)
		{
			shouldEncode_ = false;
			encodeThread_.join();
		}

		if (shouldCaptureAudio_)
		{
			shouldCaptureAudio_ = false;
			captureAudioThread_.join();
		}

		if (shouldEncodeAudio_)
		{
			shouldEncodeAudio_ = false;
			encodeAudioThread_.join();
		}

		if (shouldDecodeAudio_)
		{
			shouldDecodeAudio_ = false;
			decodeAudioThread_.join();
		}

		if (shouldRenderAudio_)
		{
			shouldRenderAudio_ = false;
			renderAudioThread_.join();
		}

		if (shouldCallback_)
		{
			shouldCallback_ = false;
			if (localRGBAZCallback_)
				localRGBAZCallbackThread_.join();
			if (localCloudCallback_)
				localCloudCallbackThread_.join();
			if (localAudioCallback_)
				localAudioCallbackThread_.join();
			if (remoteRGBAZCallback_)
				remoteRGBAZCallbackThread_.join();
			if (remoteCloudCallback_)
				remoteCloudCallbackThread_.join();
			if (remoteAudioCallback_)
				remoteAudioCallbackThread_.join();
		}

		////workaround to stop all threads when destructor calls stop()
		////only threads with send/recv socket functions can call stop()
		////in that case need to set these variables to true so when destroctor of HoloSession
		////is called, it will close these threads appropriately because apparently returning from
		////a thread function does not close the thread properly in C++ 11
		//if (callingThread == encodeThread_.get_id())
		//{
		//	shouldEncode_ = true;
		//}
		//else if (callingThread == netRecvThread_.get_id())
		//{
		//	shouldRecv_ = true;
		//}
		//else if (callingThread == encodeAudioThread_.get_id())
		//{
		//	shouldEncodeAudio_ = true;
		//}

	//}

	stoppingLock.unlock();

	isRunning_ = false;
}

bool HoloSession::isRunning()
{
	return isRunning_.load();
}

bool HoloSession::isConnected()
{
	return netSession_->isConnected();
}

HoloSession::~HoloSession()
{
	LOG4CXX_DEBUG(logger_, "Destroying HoloSession object...");
	//stop();
	LOG4CXX_DEBUG(logger_, "Destroyed HoloSession object");
}

void HoloSession::objectTrackerLoop()
{

	//objectTracker_->Add3DObject(holo::render::HoloRender3DObject::CreateSimpleObject("pointer", holo::render::SIMPLE_OBJECT_POINTER));

	while (shouldTrackObjects_)
	{
		std::unique_lock<std::mutex> ulObjectTracker(remoteObjectDataMutex_);
		if (!haveRemoteObjectData_)
		{
			if (std::cv_status::timeout == haveRemoteCloudCompressedCV_.wait_for(ulObjectTracker, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;
		}

		for (const auto t : remoteObjectStateData_)
			objectTracker_->Update3DObjectTransform(t);

		remoteObjectStateData_.clear();

		ulObjectTracker.unlock();
	}
}

void HoloSession::netRecvLoop()
{
	boost::shared_ptr<HoloNetPacket> recvPacket;

	while (shouldRecv_)
	{

		try{
			netSession_->recvPacket(recvPacket);
		}
		catch (boost::system::system_error error)
		{
			//shouldRecv_ = false;
			if (isRunning())
				std::async(std::launch::async, &HoloSession::stop, this);
			return;
		}

		if (recvPacket)
		{
			switch (recvPacket->GetPacketType())
			{
			case HOLO_NET_PACKET_TYPE_HANDSHAKE:
				remoteInfo_ = holo::net::HoloNetSession::GetHandshakeFromPacket(recvPacket);
				break;
			case HOLO_NET_PACKET_TYPE_GRACEFUL_DISCONNECT:
				//shouldRecv_ = false;
				//if (isRunning())
					std::async(std::launch::async, &HoloSession::stop, this);
				return;
			case HOLO_NET_PACKET_TYPE_OCTREE_COMPRESSED:
			{
				std::unique_lock<std::mutex> rccLock(remoteCloudCompressedMutex_);
				if (remoteCloudCompressed_.size() < HOLO_NET_PACKET_BUFFER_SIZE)
					remoteCloudCompressed_.push(boost::make_shared <std::vector<uchar>>(recvPacket->GetPacketValue(), recvPacket->GetPacketValue()+recvPacket->GetPacketLength()));
				else
					LOG4CXX_WARN(logger_, "Dropping compressed point cloud packets from receive function")
				//remoteCloudCompressed_ = boost::shared_ptr<std::vector<uchar>>(new std::vector<uchar>(recvPacket->value));
				rccLock.unlock();
				haveRemoteCloudCompressed_ = true;
				haveRemoteCloudCompressedCV_.notify_all();
				break;
			}
			case HOLO_NET_PACKET_TYPE_AUDIO_COMPRESSED:
			{
				std::unique_lock<std::mutex> racLock(remoteAudioCompressedMutex_);
				//*remoteAudioCompressed_ = recvPacket->value;
				if (remoteAudioCompressed_.size() < HOLO_NET_PACKET_BUFFER_SIZE)
					remoteAudioCompressed_.push(boost::make_shared<std::vector<uchar>>(recvPacket->GetPacketValue(), recvPacket->GetPacketValue() + recvPacket->GetPacketLength()));
				else
					LOG4CXX_WARN(logger_, "Dropping compressed audio packets from receive function")
				racLock.unlock();
				haveRemoteAudioCompressed_ = true;
				haveRemoteAudioCompressedCV_.notify_all();
				break;
			}
			case HOLO_NET_PACKET_TYPE_RGBZ_FRAME_COMPRESSED:
			{
				std::unique_lock<std::mutex> rgbazLock(remoteRGBAZCompressedMutex_);
				if (remoteRGBAZCompressed_.size() < HOLO_NET_PACKET_BUFFER_SIZE)
					remoteRGBAZCompressed_.push(boost::make_shared<std::vector<uchar>>(recvPacket->GetPacketValue(), recvPacket->GetPacketValue() + recvPacket->GetPacketLength()));
				else
					LOG4CXX_WARN(logger_, "Dropping compressed RGBAZ packets from receive function")
				rgbazLock.unlock();
				haveRemoteRGBAZCompressed_ = true;
				haveRemoteRGBAZCompressedCV_.notify_all();
				break;
			}
			case HOLO_NET_PACKET_TYPE_OBJECT_ADD:
			{
				auto obj = boost::shared_ptr<holo::render::HoloRender3DObject>(new holo::render::HoloRender3DObject(recvPacket));
				objectTracker_->Add3DObject(obj);
				break;
			}
			case HOLO_NET_PACKET_TYPE_OBJECT_DEL:
			{
				throw std::exception();
				break;
			}
			case HOLO_NET_PACKET_TYPE_OBJECT_CHANGE_OWNER:
			{
				std::string objectName;
				bool amOwner;
				std::tie(objectName, amOwner) = holo::render::HoloRender3DObject::GetChangeOwnerInfoFromPacket(recvPacket);
				objectTracker_->SetObjectOwner(objectName, amOwner);
				break;
			}
			case HOLO_NET_PACKET_TYPE_OBJECT_UPDATE:
			{
				std::unique_lock<std::mutex> objUpdateLock(remoteObjectDataMutex_);
				remoteObjectStateData_.push_back(holo::render::HoloRender3DObject::GetTransformFromPacket(recvPacket));
				objUpdateLock.unlock();
				haveRemoteObjectData_ = true;
				haveRemoteObjectDataCV_.notify_all();
				break;
			}
			case HOLO_NET_PACKET_TYPE_UNKNOWN:
			default:
				LOG4CXX_ERROR(logger_, "Unknown network packet type received")
				break;
			}
		}
	}
}

void HoloSession::captureLoop()
{
	if (rgbazEncoder_)
	{
		localRGBAZ_ = boost::shared_ptr<HoloRGBAZMat>(new HoloRGBAZMat);
		localRGBAZ_->rgba = cv::Mat(remoteInfo_.rgbazHeight, remoteInfo_.rgbazWidth, CV_8UC4);
		localRGBAZ_->z = cv::Mat(remoteInfo_.rgbazHeight, remoteInfo_.rgbazWidth, CV_16UC1);
	}

	auto localCaptureInfo = capture_->getCaptureInfo();

	HoloCloudPtr localCloud;
	holo::capture::WorldConvertCache wc;

	wc.xzFactor = tan(localCaptureInfo.rgbHOV / 2) * 2;
	wc.yzFactor = tan(localCaptureInfo.rgbVOV / 2) * 2;
	wc.resolutionX = localCaptureInfo.zWidth;
	wc.resolutionY = localCaptureInfo.zHeight;
	wc.halfResX = wc.resolutionX / 2;
	wc.halfResY = wc.resolutionY / 2;
	wc.coeffX = wc.resolutionX / wc.xzFactor;
	wc.coeffY = wc.resolutionY / wc.yzFactor;

	while (shouldCapture_)
	{
		//std::future<void> localCloudFuture;

		if (rgbazEncoder_)
		{
			std::unique_lock<std::mutex> ulLocalPixMaps(localRGBAZMutex_);
			capture_->waitAndGetNextFrame(localRGBAZ_->rgba, localRGBAZ_->z);
			ulLocalPixMaps.unlock();
			haveLocalRGBAZ_ = true;
			haveLocalRGBAZCV_.notify_all();

			if (render_ && enableVisualFeedback_)
			{
				localCloud = HoloCloudPtr(new HoloCloud(localCaptureInfo.zWidth, localCaptureInfo.zHeight));
				localCloud->is_dense = false;
				localCloud->sensor_origin_.setZero();
				localCloud->sensor_orientation_.setIdentity();

				utils::ReprojectToRealWorld(localCloud, *localRGBAZ_, wc);
				render_->updateLocalPointCloud(std::move(localCloud));
			}
		}
		else if (cloudEncoder_)
		{
			capture_->waitAndGetNextPointCloud(localCloud);
			std::unique_lock<std::mutex> ulLocalCloud(localCloudMutex_);
			localCloud_ = localCloud;
			ulLocalCloud.unlock();
			haveLocalCloud_ = true;
			haveLocalCloudCV_.notify_all();
		}
		else
		{
			std::unique_lock<std::mutex> ulRemoteCloud(remoteCloudMutex_);
			capture_->waitAndGetNextPointCloud(remoteCloud_);

			ulRemoteCloud.unlock();

			haveRemoteCloud_ = true;

			haveRemoteCloudCV_.notify_all();
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}

void HoloSession::interactionLoop()
{

	bool firstRightPinch = true;
	bool firstLeftPinch = true;

	HoloVec3f rightHandOffset = {};
	HoloVec3f rightHandRotationOffset = {};

	HoloVec3f leftHandOffset = {};
	HoloVec3f leftHandRotationOffset = {};

	while (shouldInteract_)
	{
		std::list<holo::input::HoloInputData> localInteractionData;
		std::unique_lock<std::mutex> liLock(localInteractionDataMutex_);
		if (inputDevice_->getInputData(localInteractionData))
		{
			localInteractionData_ = localInteractionData;
			haveLocalInteractionData_ = true;
			haveLocalInteractionDataCV_.notify_all();
		}

		liLock.unlock();

		for (auto interactionSample : localInteractionData)
		{
			//if (interactionSample.haveLeftHand)
			//{
			//	holo::render::HoloTransform pointerTranslation = objectTracker_->Get3DObjects().find("pointer")->second->GetTransform();
			//	pointerTranslation.translate.x = interactionSample.leftHand.index.bones[3].center.x;
			//	pointerTranslation.translate.y = interactionSample.leftHand.index.bones[3].center.y - .24f;
			//	pointerTranslation.translate.z = interactionSample.leftHand.index.bones[3].center.z + .12f;
			//
			//	objectTracker_->Update3DObjectTransform(std::make_tuple("pointer", pointerTranslation));

			//	if (interactionSample.leftHand.gesture == holo::input::GESTURE_TYPE_SCREEN_TAP)
			//	{
			//		objectTracker_->setDesignModeEnabled(!objectTracker_->getDesignModeEnabled());
			//	}

			//	if (objectTracker_->getDesignModeEnabled())
			//	{

			//		if (interactionSample.leftHand.gesture == holo::input::GESTURE_TYPE_CIRCLE)
			//		{
			//			auto obj = holo::render::HoloRender3DObject::CreateSimpleObject("circle", holo::render::SIMPLE_OBJECT_CIRCLE);
			//			objectTracker_->Add3DObject(obj);

			//			if (netSession_)
			//			{
			//				auto packet = obj->CreateNetPacket();
			//				netSession_->sendPacketAsync(std::move(packet));
			//			}
			//		}

			//		if (interactionSample.leftHand.pinchStrength > 0.6f)
			//		{
			//			for (auto obj : objectTracker_->Get3DObjects())
			//			{
			//				if (obj.second->GetAmOwner())
			//				{
			//					auto trans = obj.second->GetTransform();

			//					if (firstLeftPinch)
			//					{
			//						leftHandOffset = interactionSample.leftHand.palmPosition;
			//						leftHandOffset.x *= 30.f;
			//						leftHandOffset.y *= 30.f;
			//						leftHandOffset.z *= 30.f;
			//						leftHandOffset.x -= trans.scale.x;
			//						leftHandOffset.y -= trans.scale.y;
			//						leftHandOffset.z -= trans.scale.z;
			//						leftHandRotationOffset.x = trans.rotation.x;
			//						leftHandRotationOffset.y = trans.rotation.y;
			//						leftHandRotationOffset.z = trans.rotation.z;
			//						firstLeftPinch = false;
			//					}

			//					//trans.scale.z = floor(interactionSample.leftHand.palmPosition.z * 30.f - leftHandOffset.z);

			//					trans.scale.z = std::max<float>(interactionSample.leftHand.palmPosition.z * 30.f - leftHandOffset.z, 0.01f);

			//					obj.second->SetTransform(trans);

			//					if (netSession_)
			//					{
			//						auto packet = obj.second->CreateNetPacketFromTransform(std::tuple<std::string, holo::render::HoloTransform>(obj.second->GetObjectName(), trans));
			//						netSession_->sendPacketAsync(std::move(packet));
			//					}
			//				}
			//			}
			//		}
			//		else
			//		{
			//			firstLeftPinch = true;
			//			leftHandOffset = {};
			//			leftHandRotationOffset = {};
			//		}
			//	}
			//}

			if (interactionSample.haveRightHand && !objectTracker_->getDesignModeEnabled())
			{
				if (interactionSample.rightHand.gesture == holo::input::GESTURE_TYPE_SCREEN_TAP)
				for (auto obj : objectTracker_->Get3DObjects())
				{
					auto trans = obj.second->GetTransform();

					//LOG4CXX_DEBUG(logger_, "Got screen tap from input device")
					if (netSession_)
					{
						auto isLocal = obj.second->GetIsLocal();
						auto amOwner = obj.second->GetAmOwner();
						auto changeOwnerPacket = obj.second->ToggleOwnerAndGetOwnerChangePacket();

						trans.rotation.y = -trans.rotation.y;
						trans.translate.z = amOwner ? .1f : -trans.translate.z;
						trans.translate.x = -trans.translate.x;

						auto packet = obj.second->CreateNetPacketFromTransform(std::tuple<std::string, holo::render::HoloTransform>(obj.second->GetObjectName(), trans));
						netSession_->sendPacketAsync(std::move(packet));
						netSession_->sendPacketAsync(std::move(changeOwnerPacket));

						obj.second->SetTransform(trans);
					}
				}

				if (interactionSample.rightHand.pinchStrength > 0.6f)
				{
					for (auto obj : objectTracker_->Get3DObjects())
					{
						if (obj.second->GetAmOwner())
						{
							auto trans = obj.second->GetTransform();

							if (firstRightPinch)
							{
								rightHandOffset = interactionSample.rightHand.palmPosition;
								rightHandOffset.x -= trans.translate.x;
								rightHandOffset.y -= trans.translate.y;
								rightHandOffset.z -= trans.translate.z;
								rightHandRotationOffset.x = trans.rotation.x;
								rightHandRotationOffset.y = trans.rotation.y;
								rightHandRotationOffset.z = trans.rotation.z;
								firstRightPinch = false;
							}

							trans.translate.x = (interactionSample.rightHand.palmPosition.x - rightHandOffset.x);
							trans.translate.y = (interactionSample.rightHand.palmPosition.y - rightHandOffset.y);
							trans.translate.z = (interactionSample.rightHand.palmPosition.z - rightHandOffset.z);

							trans.rotation.y = (interactionSample.rightHand.palmNormal.z + rightHandRotationOffset.y);

							obj.second->SetTransform(trans);

							if (netSession_)
							{
								auto packet = obj.second->CreateNetPacketFromTransform(std::tuple<std::string, holo::render::HoloTransform>(obj.second->GetObjectName(), trans));
								netSession_->sendPacketAsync(std::move(packet));
							}
						}
					}
				}
				else
				{
					firstRightPinch = true;
					rightHandOffset = {};
					rightHandRotationOffset = {};
				}
			}
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
}

void HoloSession::decodeLoop()
{
	while (shouldDecode_)
	{
		if (rgbazDecoder_)
		{
			std::unique_lock<std::mutex> ulRemoteRGBAZCompressed(remoteRGBAZCompressedMutex_);
			if (!haveRemoteRGBAZCompressed_)
			{
				if (std::cv_status::timeout == haveRemoteRGBAZCompressedCV_.wait_for(ulRemoteRGBAZCompressed, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
					continue;
			}

			boost::shared_ptr<HoloRGBAZMat> decodedMats;

			auto compressedData = remoteRGBAZCompressed_.front();
			remoteRGBAZCompressed_.pop();
			haveRemoteRGBAZCompressed_ = remoteRGBAZCompressed_.size() == 0 ? false : true;
			ulRemoteRGBAZCompressed.unlock();

			rgbazDecoder_->decode(compressedData, decodedMats);

			if (decodedMats)
			{
				std::unique_lock<std::mutex> ulRemoteRGBAZ(remoteRGBAZMutex_);
				remoteRGBAZ_ = decodedMats;
				haveRemoteRGBAZ_ = true;
				ulRemoteRGBAZ.unlock();
				haveRemoteRGBAZCV_.notify_all();
			}
		}
		else if (cloudDecoder_)
		{
			std::unique_lock<std::mutex> ulRemoteCloudCompressed(remoteCloudCompressedMutex_);
			if (!haveRemoteCloudCompressed_)
			{
				if (std::cv_status::timeout == haveRemoteCloudCompressedCV_.wait_for(ulRemoteCloudCompressed, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
					continue;
			}

			auto compressedData = remoteCloudCompressed_.front();
			remoteCloudCompressed_.pop();
			haveRemoteCloudCompressed_ = remoteCloudCompressed_.size() == 0 ? false : true;
			ulRemoteCloudCompressed.unlock();

			auto remoteCloud = boost::shared_ptr<HoloCloud>(new HoloCloud);
			cloudDecoder_->decode(compressedData, remoteCloud);

			std::unique_lock<std::mutex> ulRemoteCloud(remoteCloudMutex_);
			remoteCloud_ = remoteCloud;

			ulRemoteCloud.unlock();

			haveRemoteCloud_ = true;

			haveRemoteCloudCV_.notify_all();
		}
	}
}

void HoloSession::encodeLoop()
{

	while(shouldEncode_)
	{

		if (rgbazEncoder_)
		{
			std::unique_lock<std::mutex> ulLocalRGBAZ(localRGBAZMutex_);
			if (!haveLocalRGBAZ_)
			{
				if (std::cv_status::timeout == haveLocalRGBAZCV_.wait_for(ulLocalRGBAZ, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
					continue;
			}

			boost::shared_ptr<std::vector<uchar>> encodedData;
			rgbazEncoder_->encode(localRGBAZ_, encodedData);

			haveLocalRGBAZ_ = false;
			ulLocalRGBAZ.unlock();

			if (encodedData)
			{
				auto packet = boost::shared_ptr<HoloNetPacket>(new HoloNetPacket(HOLO_NET_PACKET_TYPE_RGBZ_FRAME_COMPRESSED, encodedData->size()));
				std::copy(encodedData->begin(), encodedData->end(), packet->GetPacketValue());
				//packet->type = HOLO_NET_PACKET_TYPE_RGBZ_FRAME_COMPRESSED;
				//packet->length = encodedData->size();
				//packet->value = *encodedData;

				try{
					netSession_->sendPacketAsync(std::move(packet));
				}
				catch (boost::system::system_error error)
				{
					//shouldEncode_ = false;
					//if (isRunning())
						std::async(std::launch::async, &HoloSession::stop, this);
					return;
				}
			}
		}
		else if (cloudEncoder_)
		{
			std::unique_lock<std::mutex> ulLocalCloud(localCloudMutex_);
			if (!haveLocalCloud_)
			{
				if (std::cv_status::timeout == haveLocalCloudCV_.wait_for(ulLocalCloud, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
					continue;
			}

			boost::shared_ptr<std::vector<uchar>> encodedData;
			cloudEncoder_->encode(localCloud_, encodedData);

			haveLocalCloud_ = false;

			ulLocalCloud.unlock();

			auto packet = boost::shared_ptr<HoloNetPacket>(new HoloNetPacket(HOLO_NET_PACKET_TYPE_OCTREE_COMPRESSED, encodedData->size()));
			std::copy(encodedData->begin(), encodedData->end(), packet->GetPacketValue());
			//packet->type = HOLO_NET_PACKET_TYPE_OCTREE_COMPRESSED;
			//packet->length = encodedData->size();
			//packet->value = *encodedData;

			try{
				netSession_->sendPacketAsync(std::move(packet));
			}
			catch (boost::system::system_error error)
			{
				//shouldEncode_ = false;
				//if (isRunning())
					std::async(std::launch::async, &HoloSession::stop, this);
				continue;
			}
		}
	}
}

void HoloSession::renderLoop()
{
	while (shouldRender_)
	{
		if (objectTracker_)
			render_->addObjectTracker(objectTracker_);

		if (rgbazDecoder_)
		{
			std::unique_lock<std::mutex> ulRemoteRGBAZData(remoteRGBAZMutex_);
			if (!haveRemoteRGBAZ_)
			{
				if (std::cv_status::timeout == haveRemoteRGBAZCV_.wait_for(ulRemoteRGBAZData, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
					continue;
			}

			std::unique_lock<std::mutex> ulRemoteCloud(remoteCloudMutex_);
			holo::utils::ReprojectToRealWorld(remoteCloud_, *remoteRGBAZ_, worldConvertCache_);

			haveRemoteRGBAZ_ = false;
			ulRemoteRGBAZData.unlock();

			HoloCloudPtr renderCloud = HoloCloudPtr(new HoloCloud((const HoloCloud)*remoteCloud_));
			ulRemoteCloud.unlock();

			render_->updateRemotePointCloud(std::move(renderCloud));
		}
		else
		{
			std::unique_lock<std::mutex> ulRemoteCloud(remoteCloudMutex_);
			if (!haveRemoteCloud_)
			{
				if(std::cv_status::timeout == haveRemoteCloudCV_.wait_for(ulRemoteCloud, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
					continue;
			}

			//HoloCloudPtr renderCloud = HoloCloudPtr(new HoloCloud((const HoloCloud)*remoteCloud_));

			render_->updateRemotePointCloud(std::move(remoteCloud_));

			haveRemoteCloud_ = false;
			ulRemoteCloud.unlock();

		}

	}
}

void HoloSession::captureAudioLoop()
{
	localAudio_ = boost::shared_ptr<std::vector<unsigned char>>(new std::vector<unsigned char>);

	while (shouldCaptureAudio_)
	{
		std::unique_lock<std::mutex> ulLocalAudio(localAudioMutex_);
		audioCapture_->waitAndGetNextChunk(*localAudio_);
		ulLocalAudio.unlock();
		haveLocalAudio_ = true;
		haveLocalAudioCV_.notify_all();
		//std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}

void HoloSession::encodeAudioLoop()
{
	auto encData = boost::shared_ptr<std::vector<unsigned char>>(new std::vector<unsigned char>);

	while (shouldEncodeAudio_)
	{
		std::unique_lock<std::mutex> ulLocalAudio(localAudioMutex_);
		if (!haveLocalAudio_)
		{
			if (std::cv_status::timeout == haveLocalAudioCV_.wait_for(ulLocalAudio, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;
		}

		auto rawData = boost::shared_ptr<std::vector<unsigned char>>(localAudio_);

		audioEncoder_->encode(rawData, encData);

		haveLocalAudio_ = false;
		ulLocalAudio.unlock();

		auto packet = boost::shared_ptr<HoloNetPacket>(new HoloNetPacket(HOLO_NET_PACKET_TYPE_AUDIO_COMPRESSED, encData->size()));
		std::copy(encData->begin(), encData->end(), packet->GetPacketValue());
		//packet->type = HOLO_NET_PACKET_TYPE_AUDIO_COMPRESSED;
		//packet->length = encData->size();
		//packet->value = *encData;

		try
		{
			netSession_->sendPacketAsync(std::move(packet));
		}
		catch (boost::system::system_error error)
		{
			//shouldEncodeAudio_ = false;
			//if (isRunning())
				std::async(std::launch::async, &HoloSession::stop, this);
			continue;
		}
	}

}

void HoloSession::decodeAudioLoop()
{
	remoteAudio_ = boost::shared_ptr<std::vector<uchar>>(new std::vector<uchar>());

	while (shouldDecodeAudio_)
	{
		std::unique_lock<std::mutex> ulRemoteAudioCompressed(remoteAudioCompressedMutex_);
		if (!haveRemoteAudioCompressed_)
		{
			if (std::cv_status::timeout == haveRemoteAudioCompressedCV_.wait_for(ulRemoteAudioCompressed, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;
		}

		std::unique_lock<std::mutex> ulRemoteAudio(remoteAudioMutex_);
		auto rawData = remoteAudioCompressed_.front();
		remoteAudioCompressed_.pop();
		haveRemoteAudioCompressed_ = remoteAudioCompressed_.size() == 0 ? false : true;
		ulRemoteAudioCompressed.unlock();

		audioDecoder_->decode(rawData, remoteAudio_);

		haveRemoteAudio_ = true;
		ulRemoteAudio.unlock();
		haveRemoteAudioCV_.notify_all();
	}
}

void HoloSession::renderAudioLoop()
{
	while (shouldRenderAudio_)
	{
		std::unique_lock<std::mutex> ulRemoteAudioData(remoteAudioMutex_);
		if (!haveRemoteAudio_)
		{
			if (std::cv_status::timeout == haveRemoteAudioCV_.wait_for(ulRemoteAudioData, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;
		}

		audioRender_->playSoundBuffer(std::move(remoteAudio_));

		haveRemoteAudio_ = false;
		ulRemoteAudioData.unlock();
	}
}

void HoloSession::sendAllObjects()
{
	for (auto obj : objectTracker_->Get3DObjects())
	{
		auto packet = obj.second->CreateNetPacket();
		netSession_->sendPacketAsync(std::move(packet));
	}
}

//callbacks
void HoloSession::setLocalCloudCallback(CloudCallback cloudCallback)
{
	localCloudCallback_ = cloudCallback;
}

void HoloSession::setLocalRGBAZCallback(RGBAZCallback rgbazCallback)
{
	localRGBAZCallback_ = rgbazCallback;
}

void HoloSession::setLocalAudioCallback(AudioCallback audioCallback)
{
	localAudioCallback_ = audioCallback;
}

void HoloSession::setRemoteCloudCallback(CloudCallback cloudCallback)
{
	remoteCloudCallback_ = cloudCallback;
}

void HoloSession::setRemoteRGBAZCallback(RGBAZCallback rgbazCallback)
{
	remoteRGBAZCallback_ = rgbazCallback;
}

void HoloSession::setRemoteAudioCallback(AudioCallback audioCallback)
{
	remoteAudioCallback_ = audioCallback;
}

void HoloSession::callbackLoop(HoloSessionCallbackType type)
{
	holo::HoloAudioFormat localAudioFormat = { 0 };
	holo::HoloAudioFormat remoteAudioFormat = { 0 };
	holo::capture::HoloCaptureInfo localCaptureInfo = { 0 };
	holo::capture::HoloCaptureInfo remoteCaptureInfo = { 0 };

	if (capture_)
	{
		localCaptureInfo = capture_->getCaptureInfo();
		remoteCaptureInfo = {
			remoteInfo_.rgbazWidth,
			remoteInfo_.rgbazWidth,
			remoteInfo_.rgbazHeight,
			remoteInfo_.rgbazHeight,
			remoteInfo_.captureFPS,
			remoteInfo_.captureFPS,
			remoteInfo_.captureHOV,
			remoteInfo_.captureHOV,
			remoteInfo_.captureVOV,
			remoteInfo_.captureVOV
		};
	}

	if (audioCapture_)
	{
		localAudioFormat = audioCapture_->getAudioFormat();
		remoteAudioFormat = { static_cast<unsigned int>(remoteInfo_.audioFreq), static_cast<unsigned int>(remoteInfo_.audioNumChan), static_cast<unsigned int>(remoteInfo_.audioBitDepth) };
	}

	while (shouldCallback_)
	{
		switch (type)
		{
		case holo::HoloSession::HOLO_SESSION_CALLBACK_LOCAL_RGBAZ:
		{
			std::unique_lock<std::mutex> ulLocalRGBAZ(localRGBAZMutex_);
			if (std::cv_status::timeout == haveLocalRGBAZCV_.wait_for(ulLocalRGBAZ, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;

			localRGBAZCallback_(localRGBAZ_->rgba.data, (unsigned short*)localRGBAZ_->z.data, &localCaptureInfo);
		}
			break;
		case holo::HoloSession::HOLO_SESSION_CALLBACK_LOCAL_CLOUD:
		{
			std::unique_lock<std::mutex> ulLocalCloud(localCloudMutex_);
			if (std::cv_status::timeout == haveLocalCloudCV_.wait_for(ulLocalCloud, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;

			localCloudCallback_(localCloud_->points.data(), localCloud_->points.size());

		}
			break;
		case holo::HoloSession::HOLO_SESSION_CALLBACK_LOCAL_MESH:
			break;
		case holo::HoloSession::HOLO_SESSION_CALLBACK_LOCAL_AUDIO:
		{
			std::unique_lock<std::mutex> ulLocalAudio(localAudioMutex_);
			if (std::cv_status::timeout == haveLocalAudioCV_.wait_for(ulLocalAudio, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;

		}
			break;
		case holo::HoloSession::HOLO_SESSION_CALLBACK_REMOTE_RGBAZ:
		{
			std::unique_lock<std::mutex> ulRemoteRGBAZData(remoteRGBAZMutex_);
			if (std::cv_status::timeout == haveRemoteRGBAZCV_.wait_for(ulRemoteRGBAZData, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;

			remoteRGBAZCallback_(remoteRGBAZ_->rgba.data, (unsigned short*)remoteRGBAZ_->z.data, &remoteCaptureInfo);
		}
			break;
		case holo::HoloSession::HOLO_SESSION_CALLBACK_REMOTE_CLOUD:
		{
			std::unique_lock<std::mutex> ulRemoteCloud(remoteCloudMutex_);
			if (std::cv_status::timeout == haveRemoteCloudCV_.wait_for(ulRemoteCloud, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;

			remoteCloudCallback_(remoteCloud_->points.data(), remoteCloud_->points.size());
		}
			break;
		case holo::HoloSession::HOLO_SESSION_CALLBACK_REMOTE_MESH:
			break;
		case holo::HoloSession::HOLO_SESSION_CALLBACK_REMOTE_AUDIO:
		{
			std::unique_lock<std::mutex> ulRemoteAudioData(remoteAudioMutex_);
			if (std::cv_status::timeout == haveRemoteAudioCV_.wait_for(ulRemoteAudioData, std::chrono::milliseconds(HOLO_SESSION_CV_WAIT_TIMEOUT_MS)))
				continue;

			remoteAudioCallback_(remoteAudio_->data(), remoteAudio_->size());
		}
			break;
		default:
			break;
		}
	}
}

ext: cpp

max_stars_repo_name: itsermo/holosuite

max_issues_repo_name: itsermo/holosuite

max_forks_repo_name: itsermo/holosuite