<commit_before>/*=========================================================================
 *
 *  Copyright Leiden University Medical Center, Erasmus University Medical
 *  Center and contributors
 *
 *  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.txt
 *
 *  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 "selxSuperElastixFilterCustomComponents.h"
#include "selxItkDisplacementFieldSourceComponent.h"
#include "selxItkDisplacementFieldSinkComponent.h"
#include "selxItkMeshSourceComponent.h"
#include "selxItkMeshSinkComponent.h"
#include "itkMeshFileReader.h"
#include "itkMeshFileWriter.h"
#include "selxDisplacementFieldMeshWarperComponent.h"

#include "gtest/gtest.h"
#include "selxDataManager.h"

namespace selx {

class DisplacementFieldMeshWarperComponentTest : public ::testing::Test {
public:

  typedef itk::VectorImage< float, 2 >            VectorImageType;
  typedef typename VectorImageType::Pointer       VectorImagePointer;
  typedef itk::ImageFileReader< VectorImageType > VectorImageReaderType;
  typedef typename VectorImageReaderType::Pointer VectorImageReaderPointer;
  typedef itk::ImageFileWriter< VectorImageType > VectorImageWriterType;
  typedef typename VectorImageWriterType::Pointer VectorImageWriterPointer;

  typedef itk::Mesh< float, 2 >                   MeshType;
  typedef typename MeshType::Pointer              MeshPointer;
  typedef itk::MeshFileReader< MeshType >         MeshReaderType;
  typedef typename MeshReaderType::Pointer        MeshReaderPointer;
  typedef itk::MeshFileWriter< MeshType >         MeshWriterType;
  typedef typename MeshWriterType::Pointer        MeshWriterPointer;

  typedef Blueprint::Pointer BlueprintPointer;

  typedef TypeList<
    ItkDisplacementFieldSourceComponent< 2, float >,
    ItkDisplacementFieldSinkComponent< 2, float >,
    ItkMeshSourceComponent< 2, float >,
    ItkMeshSinkComponent< 2, float >,
    ItkDisplacementFieldMeshWarperComponent< 2, float, float > > TestComponents;

  typedef SuperElastixFilterCustomComponents< TestComponents > SuperElastixFilterType;
  typedef typename SuperElastixFilterType::Pointer SuperElastixFilterPointer;

  DataManager::Pointer dataManager = DataManager::New();
};

TEST_F( DisplacementFieldMeshWarperComponentTest, SinkAndSource )
{
  BlueprintPointer blueprint = Blueprint::New();
  using ParameterMapType = Blueprint::ParameterMapType;

  ParameterMapType displacementFieldSourceParameters;
  displacementFieldSourceParameters[ "NameOfClass" ]    = { "ItkDisplacementFieldSourceComponent" };
  displacementFieldSourceParameters[ "Dimensionality" ] = { "2" };
  blueprint->SetComponent( "DisplacementFieldSource", displacementFieldSourceParameters );

  ParameterMapType meshSourceParameters;
  meshSourceParameters[ "NameOfClass" ]    = { "ItkMeshSourceComponent" };
  meshSourceParameters[ "Dimensionality" ] = { "2" };
  blueprint->SetComponent( "MeshSource", meshSourceParameters );

  ParameterMapType meshSinkParameters;
  meshSinkParameters[ "NameOfClass" ]    = { "ItkMeshSinkComponent" };
  meshSinkParameters[ "Dimensionality" ] = { "2" };
  blueprint->SetComponent( "MeshSink", meshSinkParameters );

  ParameterMapType displacementFieldMeshWarperParameters;
  displacementFieldMeshWarperParameters[ "NameOfClass" ]    = { "ItkDisplacementFieldMeshWarperComponent" };
  displacementFieldMeshWarperParameters[ "Dimensionality" ] = { "2" };
  blueprint->SetComponent( "DisplacementFieldMeshWarper", displacementFieldMeshWarperParameters );

  SuperElastixFilterPointer superElastixFilter = SuperElastixFilterType::New();
  superElastixFilter->SetBlueprint(blueprint);

  MeshReaderPointer meshReader = MeshReaderType::New();
  meshReader->SetFileName( this->dataManager->GetInputFile( "2dSquare.vtk" ) );

  superElastixFilter->SetInput( "MeshSource", meshReader->GetOutput() );
}

} // namespace selx<commit_msg>WIP: DisplacementieldMeshWarperTest<commit_after>/*=========================================================================
 *
 *  Copyright Leiden University Medical Center, Erasmus University Medical
 *  Center and contributors
 *
 *  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.txt
 *
 *  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 "selxSuperElastixFilterCustomComponents.h"
#include "selxItkDisplacementFieldSourceComponent.h"
#include "selxItkDisplacementFieldSinkComponent.h"
#include "selxItkMeshSourceComponent.h"
#include "selxItkMeshSinkComponent.h"
#include "itkMeshFileReader.h"
#include "itkMeshFileWriter.h"
#include "selxDisplacementFieldMeshWarperComponent.h"

#include "gtest/gtest.h"
#include "selxDataManager.h"

namespace selx {

class DisplacementFieldMeshWarperComponentTest : public ::testing::Test {
public:

  typedef ItkDisplacementFieldMeshWarperComponent< 2, float, float >::ItkDisplacementFieldType DisplacementFieldType;
  typedef typename DisplacementFieldType::Pointer DisplacementFieldPointer;
  typedef itk::ImageFileReader< DisplacementFieldType > DisplacementFieldReaderType;
  typedef typename DisplacementFieldReaderType::Pointer DisplacementFieldReaderPointer;
  typedef itk::ImageFileWriter< DisplacementFieldType > DisplacementFieldWriterType;
  typedef typename DisplacementFieldWriterType::Pointer DisplacementFieldWriterPointer;

  typedef itk::Mesh< float, 2 > MeshType;
  typedef typename MeshType::Pointer MeshPointer;
  typedef itk::MeshFileReader< MeshType > MeshReaderType;
  typedef typename MeshReaderType::Pointer MeshReaderPointer;
  typedef itk::MeshFileWriter< MeshType > MeshWriterType;
  typedef typename MeshWriterType::Pointer MeshWriterPointer;

  typedef Blueprint::Pointer BlueprintPointer;

  typedef TypeList<
    ItkDisplacementFieldSourceComponent< 2, float >,
    ItkDisplacementFieldSinkComponent< 2, float >,
    ItkMeshSourceComponent< 2, float >,
    ItkMeshSinkComponent< 2, float >,
    ItkDisplacementFieldMeshWarperComponent< 2, float, float > > TestComponents;

  typedef SuperElastixFilterCustomComponents< TestComponents > SuperElastixFilterType;
  typedef typename SuperElastixFilterType::Pointer SuperElastixFilterPointer;

  DataManager::Pointer dataManager = DataManager::New();
};

TEST_F( DisplacementFieldMeshWarperComponentTest, SinkAndSource )
{

  DisplacementFieldPointer displacementField = DisplacementFieldType::New();
  displacementField->SetRegions(DisplacementFieldType::Superclass::SizeType({{3, 3}}));
  displacementField->Allocate();

  DisplacementFieldType::Superclass::IndexType index00, index01, index02,
                                               index10, index11, index12,
                                               index20, index21, index22;

  index00[0] = 0; index00[1] = 0;
  index01[0] = 0; index01[1] = 1;
  index02[0] = 0; index02[1] = 2;
  index10[0] = 1; index10[1] = 0;
  index11[0] = 1; index11[1] = 1;
  index12[0] = 1; index12[1] = 2;
  index20[0] = 2; index20[1] = 0;
  index21[0] = 2; index21[1] = 1;
  index22[0] = 2; index22[1] = 2;

  typedef itk::Vector<float, 2> VectorType;
  VectorType displacement00, displacement01, displacement10, displacement11, displacementminus11;
  displacement00[0] = 0.;
  displacement00[1] = 0.;

  displacement01[0] = 0.;
  displacement01[1] = 1.;

  displacement10[0] = 1.;
  displacement10[1] = 0.;

  displacement11[0] = 1.;
  displacement11[1] = 1.;

  displacementminus11[0] = -1.;
  displacementminus11[1] = -1.;

  displacementField->SetPixel(index00, displacement01);
  displacementField->SetPixel(index01, displacement10);
  displacementField->SetPixel(index02, displacement00);
  displacementField->SetPixel(index10, displacement10);
  displacementField->SetPixel(index11, displacement11);
  displacementField->SetPixel(index12, displacement00);
  displacementField->SetPixel(index20, displacement00);
  displacementField->SetPixel(index21, displacement00);
  displacementField->SetPixel(index22, displacementminus11);

  Logger::Pointer logger = Logger::New();
  logger->AddStream( "cout", std::cout );
  logger->SetLogLevel( LogLevel::TRC );

  BlueprintPointer blueprint = Blueprint::New();
  using ParameterMapType = Blueprint::ParameterMapType;

  ParameterMapType displacementFieldSourceParameters;
  displacementFieldSourceParameters[ "NameOfClass" ]    = { "ItkDisplacementFieldSourceComponent" };
  displacementFieldSourceParameters[ "Dimensionality" ] = { "2" };
  blueprint->SetComponent( "DisplacementFieldSource", displacementFieldSourceParameters );

  ParameterMapType meshSourceParameters;
  meshSourceParameters[ "NameOfClass" ]    = { "ItkMeshSourceComponent" };
  meshSourceParameters[ "Dimensionality" ] = { "2" };
  blueprint->SetComponent( "MeshSource", meshSourceParameters );

  ParameterMapType meshSinkParameters;
  meshSinkParameters[ "NameOfClass" ]    = { "ItkMeshSinkComponent" };
  meshSinkParameters[ "Dimensionality" ] = { "2" };
  blueprint->SetComponent( "MeshSink", meshSinkParameters );

  ParameterMapType displacementFieldMeshWarperParameters;
  displacementFieldMeshWarperParameters[ "NameOfClass" ]    = { "ItkDisplacementFieldMeshWarperComponent" };
  displacementFieldMeshWarperParameters[ "Dimensionality" ] = { "2" };
  blueprint->SetComponent( "DisplacementFieldMeshWarper", displacementFieldMeshWarperParameters );

  ParameterMapType connection0;
  connection0[ "NameOfInterface" ] = { "itkMeshInterface" };
  blueprint->SetConnection( "MeshSource", "ItkDisplacementFieldMeshWarperComponent", connection0 );

  ParameterMapType connection1;
  connection0[ "NameOfInterface" ] = { "itkDisplacementFieldInterface" };
  blueprint->SetConnection( "DisplacementFieldSource", "ItkDisplacementFieldMeshWarperComponent", connection1 );

  ParameterMapType connection2;
  connection0[ "NameOfInterface" ] = { "itkMeshInterface" };
  blueprint->SetConnection( "ItkDisplacementFieldMeshWarperComponent", "MeshSink", connection2 );

  SuperElastixFilterPointer superElastixFilter = SuperElastixFilterType::New();
  superElastixFilter->SetBlueprint(blueprint);
  superElastixFilter->SetLogger(logger);

  MeshReaderPointer meshReader = MeshReaderType::New();
  meshReader->SetFileName( this->dataManager->GetInputFile( "2dSquare.vtk" ) );

  superElastixFilter->SetInput( "DisplacementFieldSource", displacementField );
  superElastixFilter->SetInput( "MeshSource", meshReader->GetOutput() );

  MeshWriterPointer meshWriter = MeshWriterType::New();
  meshWriter->SetFileName( this->dataManager->GetOutputFile( "DisplacementFieldMeshWarperComponentTest.SinkAndSource.WarpedMesh.vtk" ) );
  meshWriter->SetInput( superElastixFilter->GetOutput< MeshType >( "MeshSink" ) );
  meshWriter->Update();
}

} // namespace selx<|endoftext|>


<commit_before>inline
cov_mat_kth::cov_mat_kth( const std::string in_path,
			  const std::string in_actionNames,
			  const int in_scale_factor,
			  const int in_shift,
			  const int in_scene, //only for kth
			  const int in_segment_length
)
:path(in_path), actionNames(in_actionNames), scale_factor(in_scale_factor), shift(in_shift), total_scenes(in_scene), segment_length(in_segment_length)
{
  actions.load( actionNames );
}

inline
void
cov_mat_kth::calculate( field<string> in_all_people, int  in_dim  )
{
  all_people = in_all_people;
  dim = in_dim;
  int n_actions = actions.n_rows;
  int n_peo =  all_people.n_rows;
  //all_people.print("people");

  for (int sc = 4; sc<=total_scenes; ++sc) //scene
  {
    for (int pe = 0; pe< n_peo; ++pe)
    {
      for (int act=0; act<n_actions; ++act)
      {

	std::stringstream load_folder;
	std::stringstream load_feat_video_i;
	std::stringstream load_labels_video_i;

	//cout << "Loading.." << endl;
	load_folder << path << "/kth-features/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	load_feat_video_i << load_folder.str() << "/" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";
	load_labels_video_i << load_folder.str() << "/lab_" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

	//For one Video
	if(  !( ( sc==3 && pe==12) && act==1) ) //person13_handclapping_d3
	{
	cov_mat_kth::one_video(load_feat_video_i.str(),	 load_labels_video_i.str(), sc, pe, act );
	}
	//getchar();

      }
    }
  }
}

inline
void
cov_mat_kth::one_video( std::string load_feat_video_i,	std::string load_labels_video_i, int sc, int pe, int act )
{
  cout << load_feat_video_i << endl;
  mat mat_features_video_i;
  vec lab_video_i;

  mat_features_video_i.load( load_feat_video_i, hdf5_binary );
  lab_video_i.load( load_labels_video_i, hdf5_binary );
  int n_vec = lab_video_i.n_elem;
  int last = lab_video_i( n_vec - 1 );
  //cout << last << endl;

  int s = 0;

  std::stringstream save_folder;
  save_folder << "./kth-cov-mat/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;

  for (int l=2; l<last-segment_length; l = l+4 )
  {
    running_stat_vec<rowvec> stat_seg(true);
    //int k =0;

    //cout << " " << l;

    for (int j=l; j< l + segment_length; ++j)
    {
      //k++;
      //cout << " " << j;
      uvec indices = find(lab_video_i == j);
      mat tmp_feat = mat_features_video_i.cols(indices);
      //cout << "row&col " << tmp_feat.n_rows << " & " << tmp_feat.n_cols << endl;
      for (int v=0; v < tmp_feat.n_cols; ++v)
      {
	vec sample = tmp_feat.col(v);
	stat_seg (sample);

      }

    }

    //cout << endl;
    //cout << " " << stat_seg.count();

    if (stat_seg.count()>100) // Cuando en el segmento hay mas de 100 vectores
    {
    std::stringstream save_cov_seg;
    save_cov_seg << save_folder.str() << "/cov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

    std::stringstream save_LogMcov_seg;
    save_LogMcov_seg << save_folder.str() << "/LogMcov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

    double THRESH = 0.000001;
    mat cov_seg_i = stat_seg.cov();

    //Following Mehrtash suggestions as per email dated June26th 2014
    cov_seg_i = 0.5*(cov_seg_i + cov_seg_i.t());
    vec D;
    mat V;
    eig_sym(D, V, cov_seg_i);
    uvec q1 = find(D < THRESH);

    if (q1.n_elem>0)
    {
      for (uword pos = 0; pos < q1.n_elem; ++pos)
      {
	D( q1(pos) ) = THRESH;

      }

      cov_seg_i = V*diagmat(D)*V.t();

    }
    //end suggestion

     eig_sym(D, V, cov_seg_i);
     mat log_M = V*diagmat( log(D) )*V.t();
     cov_seg_i.save( save_cov_seg.str(), hdf5_binary );
     log_M.save( save_LogMcov_seg.str(), hdf5_binary );
//      cov_seg_i.print("cov_seg_i");
//      log_M.print("log_M");
//      getchar();

    s++;
    }
    else {
     //cout << " " << stat_seg.count();
     //getchar();

    }

  }

  std::stringstream save_seg;
  vec total_seg;
  total_seg.zeros(1);
  total_seg( 0 ) = s;
  save_seg << save_folder.str() << "/num_seg_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
  total_seg.save( save_seg.str(), raw_ascii );
  cout << "Total # of segments " << s << endl;
  //cout << "press a key " ;
  //getchar();

}

<commit_msg> Bug with unexisting video<commit_after>inline
cov_mat_kth::cov_mat_kth( const std::string in_path,
			  const std::string in_actionNames,
			  const int in_scale_factor,
			  const int in_shift,
			  const int in_scene, //only for kth
			  const int in_segment_length
)
:path(in_path), actionNames(in_actionNames), scale_factor(in_scale_factor), shift(in_shift), total_scenes(in_scene), segment_length(in_segment_length)
{
  actions.load( actionNames );
}

inline
void
cov_mat_kth::calculate( field<string> in_all_people, int  in_dim  )
{
  all_people = in_all_people;
  dim = in_dim;
  int n_actions = actions.n_rows;
  int n_peo =  all_people.n_rows;
  //all_people.print("people");

  for (int sc = 3; sc<=total_scenes; ++sc) //scene
  {
    for (int pe = 0; pe< n_peo; ++pe)
    {
      for (int act=0; act<n_actions; ++act)
      {

	std::stringstream load_folder;
	std::stringstream load_feat_video_i;
	std::stringstream load_labels_video_i;

	//cout << "Loading.." << endl;
	load_folder << path << "/kth-features/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;
	load_feat_video_i << load_folder.str() << "/" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";
	load_labels_video_i << load_folder.str() << "/lab_" << all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

	//For one Video
	if(  !( ( sc==3 && pe==12) && act==1) ) //person13_handclapping_d3
	{
	cov_mat_kth::one_video(load_feat_video_i.str(),	 load_labels_video_i.str(), sc, pe, act );
	}
	//getchar();

      }
    }
  }
}

inline
void
cov_mat_kth::one_video( std::string load_feat_video_i,	std::string load_labels_video_i, int sc, int pe, int act )
{
  cout << load_feat_video_i << endl;
  mat mat_features_video_i;
  vec lab_video_i;

  mat_features_video_i.load( load_feat_video_i, hdf5_binary );
  lab_video_i.load( load_labels_video_i, hdf5_binary );
  int n_vec = lab_video_i.n_elem;
  int last = lab_video_i( n_vec - 1 );
  //cout << last << endl;

  int s = 0;

  std::stringstream save_folder;
  save_folder << "./kth-cov-mat/sc" << sc << "/scale" << scale_factor << "-shift"<< shift ;

  for (int l=2; l<last-segment_length; l = l+4 )
  {
    running_stat_vec<rowvec> stat_seg(true);
    //int k =0;

    //cout << " " << l;

    for (int j=l; j< l + segment_length; ++j)
    {
      //k++;
      //cout << " " << j;
      uvec indices = find(lab_video_i == j);
      mat tmp_feat = mat_features_video_i.cols(indices);
      //cout << "row&col " << tmp_feat.n_rows << " & " << tmp_feat.n_cols << endl;
      for (int v=0; v < tmp_feat.n_cols; ++v)
      {
	vec sample = tmp_feat.col(v);
	stat_seg (sample);

      }

    }

    //cout << endl;
    //cout << " " << stat_seg.count();

    if (stat_seg.count()>100) // Cuando en el segmento hay mas de 100 vectores
    {
    std::stringstream save_cov_seg;
    save_cov_seg << save_folder.str() << "/cov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

    std::stringstream save_LogMcov_seg;
    save_LogMcov_seg << save_folder.str() << "/LogMcov_seg" << s << "_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".h5";

    double THRESH = 0.000001;
    mat cov_seg_i = stat_seg.cov();

    //Following Mehrtash suggestions as per email dated June26th 2014
    cov_seg_i = 0.5*(cov_seg_i + cov_seg_i.t());
    vec D;
    mat V;
    eig_sym(D, V, cov_seg_i);
    uvec q1 = find(D < THRESH);

    if (q1.n_elem>0)
    {
      for (uword pos = 0; pos < q1.n_elem; ++pos)
      {
	D( q1(pos) ) = THRESH;

      }

      cov_seg_i = V*diagmat(D)*V.t();

    }
    //end suggestion

     eig_sym(D, V, cov_seg_i);
     mat log_M = V*diagmat( log(D) )*V.t();
     cov_seg_i.save( save_cov_seg.str(), hdf5_binary );
     log_M.save( save_LogMcov_seg.str(), hdf5_binary );
//      cov_seg_i.print("cov_seg_i");
//      log_M.print("log_M");
//      getchar();

    s++;
    }
    else {
     //cout << " " << stat_seg.count();
     //getchar();

    }

  }

  std::stringstream save_seg;
  vec total_seg;
  total_seg.zeros(1);
  total_seg( 0 ) = s;
  save_seg << save_folder.str() << "/num_seg_"<< all_people (pe) << "_" << actions(act) << "_dim" << dim  << ".dat";
  total_seg.save( save_seg.str(), raw_ascii );
  cout << "Total # of segments " << s << endl;
  //cout << "press a key " ;
  //getchar();

}

<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <gtest/gtest.h>

#include <string>

#include "parquet/types.h"

namespace parquet {

TEST(TestTypeToString, PhysicalTypes) {
  ASSERT_STREQ("BOOLEAN", TypeToString(Type::BOOLEAN).c_str());
  ASSERT_STREQ("INT32", TypeToString(Type::INT32).c_str());
  ASSERT_STREQ("INT64", TypeToString(Type::INT64).c_str());
  ASSERT_STREQ("INT96", TypeToString(Type::INT96).c_str());
  ASSERT_STREQ("FLOAT", TypeToString(Type::FLOAT).c_str());
  ASSERT_STREQ("DOUBLE", TypeToString(Type::DOUBLE).c_str());
  ASSERT_STREQ("BYTE_ARRAY", TypeToString(Type::BYTE_ARRAY).c_str());
  ASSERT_STREQ("FIXED_LEN_BYTE_ARRAY", TypeToString(Type::FIXED_LEN_BYTE_ARRAY).c_str());
}

TEST(TestConvertedTypeToString, ConvertedTypes) {
  ASSERT_STREQ("NONE", ConvertedTypeToString(ConvertedType::NONE).c_str());
  ASSERT_STREQ("UTF8", ConvertedTypeToString(ConvertedType::UTF8).c_str());
  ASSERT_STREQ("MAP", ConvertedTypeToString(ConvertedType::MAP).c_str());
  ASSERT_STREQ("MAP_KEY_VALUE",
               ConvertedTypeToString(ConvertedType::MAP_KEY_VALUE).c_str());
  ASSERT_STREQ("LIST", ConvertedTypeToString(ConvertedType::LIST).c_str());
  ASSERT_STREQ("ENUM", ConvertedTypeToString(ConvertedType::ENUM).c_str());
  ASSERT_STREQ("DECIMAL", ConvertedTypeToString(ConvertedType::DECIMAL).c_str());
  ASSERT_STREQ("DATE", ConvertedTypeToString(ConvertedType::DATE).c_str());
  ASSERT_STREQ("TIME_MILLIS", ConvertedTypeToString(ConvertedType::TIME_MILLIS).c_str());
  ASSERT_STREQ("TIME_MICROS", ConvertedTypeToString(ConvertedType::TIME_MICROS).c_str());
  ASSERT_STREQ("TIMESTAMP_MILLIS",
               ConvertedTypeToString(ConvertedType::TIMESTAMP_MILLIS).c_str());
  ASSERT_STREQ("TIMESTAMP_MICROS",
               ConvertedTypeToString(ConvertedType::TIMESTAMP_MICROS).c_str());
  ASSERT_STREQ("UINT_8", ConvertedTypeToString(ConvertedType::UINT_8).c_str());
  ASSERT_STREQ("UINT_16", ConvertedTypeToString(ConvertedType::UINT_16).c_str());
  ASSERT_STREQ("UINT_32", ConvertedTypeToString(ConvertedType::UINT_32).c_str());
  ASSERT_STREQ("UINT_64", ConvertedTypeToString(ConvertedType::UINT_64).c_str());
  ASSERT_STREQ("INT_8", ConvertedTypeToString(ConvertedType::INT_8).c_str());
  ASSERT_STREQ("INT_16", ConvertedTypeToString(ConvertedType::INT_16).c_str());
  ASSERT_STREQ("INT_32", ConvertedTypeToString(ConvertedType::INT_32).c_str());
  ASSERT_STREQ("INT_64", ConvertedTypeToString(ConvertedType::INT_64).c_str());
  ASSERT_STREQ("JSON", ConvertedTypeToString(ConvertedType::JSON).c_str());
  ASSERT_STREQ("BSON", ConvertedTypeToString(ConvertedType::BSON).c_str());
  ASSERT_STREQ("INTERVAL", ConvertedTypeToString(ConvertedType::INTERVAL).c_str());
}

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996)
#endif

TEST(TypePrinter, StatisticsTypes) {
  std::string smin;
  std::string smax;
  int32_t int_min = 1024;
  int32_t int_max = 2048;
  smin = std::string(reinterpret_cast<char*>(&int_min), sizeof(int32_t));
  smax = std::string(reinterpret_cast<char*>(&int_max), sizeof(int32_t));
  ASSERT_STREQ("1024", FormatStatValue(Type::INT32, smin).c_str());
  ASSERT_STREQ("2048", FormatStatValue(Type::INT32, smax).c_str());

  int64_t int64_min = 10240000000000;
  int64_t int64_max = 20480000000000;
  smin = std::string(reinterpret_cast<char*>(&int64_min), sizeof(int64_t));
  smax = std::string(reinterpret_cast<char*>(&int64_max), sizeof(int64_t));
  ASSERT_STREQ("10240000000000", FormatStatValue(Type::INT64, smin).c_str());
  ASSERT_STREQ("20480000000000", FormatStatValue(Type::INT64, smax).c_str());

  float float_min = 1.024f;
  float float_max = 2.048f;
  smin = std::string(reinterpret_cast<char*>(&float_min), sizeof(float));
  smax = std::string(reinterpret_cast<char*>(&float_max), sizeof(float));
  ASSERT_STREQ("1.024", FormatStatValue(Type::FLOAT, smin).c_str());
  ASSERT_STREQ("2.048", FormatStatValue(Type::FLOAT, smax).c_str());

  double double_min = 1.0245;
  double double_max = 2.0489;
  smin = std::string(reinterpret_cast<char*>(&double_min), sizeof(double));
  smax = std::string(reinterpret_cast<char*>(&double_max), sizeof(double));
  ASSERT_STREQ("1.0245", FormatStatValue(Type::DOUBLE, smin).c_str());
  ASSERT_STREQ("2.0489", FormatStatValue(Type::DOUBLE, smax).c_str());

  Int96 Int96_min = {{1024, 2048, 4096}};
  Int96 Int96_max = {{2048, 4096, 8192}};
  smin = std::string(reinterpret_cast<char*>(&Int96_min), sizeof(Int96));
  smax = std::string(reinterpret_cast<char*>(&Int96_max), sizeof(Int96));
  ASSERT_STREQ("1024 2048 4096", FormatStatValue(Type::INT96, smin).c_str());
  ASSERT_STREQ("2048 4096 8192", FormatStatValue(Type::INT96, smax).c_str());

  smin = std::string("abcdef");
  smax = std::string("ijklmnop");
  ASSERT_STREQ("abcdef", FormatStatValue(Type::BYTE_ARRAY, smin).c_str());
  ASSERT_STREQ("ijklmnop", FormatStatValue(Type::BYTE_ARRAY, smax).c_str());

  // PARQUET-1357: FormatStatValue truncates binary statistics on zero character
  smax.push_back('\0');
  ASSERT_EQ(smax, FormatStatValue(Type::BYTE_ARRAY, smax));

  smin = std::string("abcdefgh");
  smax = std::string("ijklmnop");
  ASSERT_STREQ("abcdefgh", FormatStatValue(Type::FIXED_LEN_BYTE_ARRAY, smin).c_str());
  ASSERT_STREQ("ijklmnop", FormatStatValue(Type::FIXED_LEN_BYTE_ARRAY, smax).c_str());
}

TEST(TestInt96Timestamp, Decoding) {
  auto check = [](int32_t julian_day, uint64_t nanoseconds) {
    Int96 i96{static_cast<uint32_t>(nanoseconds),
              static_cast<uint32_t>(nanoseconds >> 32),
              static_cast<uint32_t>(julian_day)};
    // Official formula according to https://github.com/apache/parquet-format/pull/49
    int64_t expected =
        (julian_day - 2440588) * (86400LL * 1000 * 1000 * 1000) + nanoseconds;
    int64_t actual = Int96GetNanoSeconds(i96);
    ASSERT_EQ(expected, actual);
  };

  // [2333837, 2547339] is the range of Julian days that can be converted to
  // 64-bit Unix timestamps.
  check(2333837, 0);
  check(2333855, 0);
  check(2547330, 0);
  check(2547338, 0);
  check(2547339, 0);

  check(2547330, 13);
  check(2547330, 32769);
  check(2547330, 87654);
  check(2547330, 0x123456789abcdefULL);
  check(2547330, 0xfedcba9876543210ULL);
  check(2547339, 0xffffffffffffffffULL);
}

#if !(defined(_WIN32) || defined(__CYGWIN__))
#pragma GCC diagnostic pop
#elif _MSC_VER
#pragma warning(pop)
#endif

}  // namespace parquet
<commit_msg>PARQUET-1845: [C++] Add expected results of Int96 in big-endian<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <gtest/gtest.h>

#include <string>

#include "parquet/types.h"

namespace parquet {

TEST(TestTypeToString, PhysicalTypes) {
  ASSERT_STREQ("BOOLEAN", TypeToString(Type::BOOLEAN).c_str());
  ASSERT_STREQ("INT32", TypeToString(Type::INT32).c_str());
  ASSERT_STREQ("INT64", TypeToString(Type::INT64).c_str());
  ASSERT_STREQ("INT96", TypeToString(Type::INT96).c_str());
  ASSERT_STREQ("FLOAT", TypeToString(Type::FLOAT).c_str());
  ASSERT_STREQ("DOUBLE", TypeToString(Type::DOUBLE).c_str());
  ASSERT_STREQ("BYTE_ARRAY", TypeToString(Type::BYTE_ARRAY).c_str());
  ASSERT_STREQ("FIXED_LEN_BYTE_ARRAY", TypeToString(Type::FIXED_LEN_BYTE_ARRAY).c_str());
}

TEST(TestConvertedTypeToString, ConvertedTypes) {
  ASSERT_STREQ("NONE", ConvertedTypeToString(ConvertedType::NONE).c_str());
  ASSERT_STREQ("UTF8", ConvertedTypeToString(ConvertedType::UTF8).c_str());
  ASSERT_STREQ("MAP", ConvertedTypeToString(ConvertedType::MAP).c_str());
  ASSERT_STREQ("MAP_KEY_VALUE",
               ConvertedTypeToString(ConvertedType::MAP_KEY_VALUE).c_str());
  ASSERT_STREQ("LIST", ConvertedTypeToString(ConvertedType::LIST).c_str());
  ASSERT_STREQ("ENUM", ConvertedTypeToString(ConvertedType::ENUM).c_str());
  ASSERT_STREQ("DECIMAL", ConvertedTypeToString(ConvertedType::DECIMAL).c_str());
  ASSERT_STREQ("DATE", ConvertedTypeToString(ConvertedType::DATE).c_str());
  ASSERT_STREQ("TIME_MILLIS", ConvertedTypeToString(ConvertedType::TIME_MILLIS).c_str());
  ASSERT_STREQ("TIME_MICROS", ConvertedTypeToString(ConvertedType::TIME_MICROS).c_str());
  ASSERT_STREQ("TIMESTAMP_MILLIS",
               ConvertedTypeToString(ConvertedType::TIMESTAMP_MILLIS).c_str());
  ASSERT_STREQ("TIMESTAMP_MICROS",
               ConvertedTypeToString(ConvertedType::TIMESTAMP_MICROS).c_str());
  ASSERT_STREQ("UINT_8", ConvertedTypeToString(ConvertedType::UINT_8).c_str());
  ASSERT_STREQ("UINT_16", ConvertedTypeToString(ConvertedType::UINT_16).c_str());
  ASSERT_STREQ("UINT_32", ConvertedTypeToString(ConvertedType::UINT_32).c_str());
  ASSERT_STREQ("UINT_64", ConvertedTypeToString(ConvertedType::UINT_64).c_str());
  ASSERT_STREQ("INT_8", ConvertedTypeToString(ConvertedType::INT_8).c_str());
  ASSERT_STREQ("INT_16", ConvertedTypeToString(ConvertedType::INT_16).c_str());
  ASSERT_STREQ("INT_32", ConvertedTypeToString(ConvertedType::INT_32).c_str());
  ASSERT_STREQ("INT_64", ConvertedTypeToString(ConvertedType::INT_64).c_str());
  ASSERT_STREQ("JSON", ConvertedTypeToString(ConvertedType::JSON).c_str());
  ASSERT_STREQ("BSON", ConvertedTypeToString(ConvertedType::BSON).c_str());
  ASSERT_STREQ("INTERVAL", ConvertedTypeToString(ConvertedType::INTERVAL).c_str());
}

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996)
#endif

TEST(TypePrinter, StatisticsTypes) {
  std::string smin;
  std::string smax;
  int32_t int_min = 1024;
  int32_t int_max = 2048;
  smin = std::string(reinterpret_cast<char*>(&int_min), sizeof(int32_t));
  smax = std::string(reinterpret_cast<char*>(&int_max), sizeof(int32_t));
  ASSERT_STREQ("1024", FormatStatValue(Type::INT32, smin).c_str());
  ASSERT_STREQ("2048", FormatStatValue(Type::INT32, smax).c_str());

  int64_t int64_min = 10240000000000;
  int64_t int64_max = 20480000000000;
  smin = std::string(reinterpret_cast<char*>(&int64_min), sizeof(int64_t));
  smax = std::string(reinterpret_cast<char*>(&int64_max), sizeof(int64_t));
  ASSERT_STREQ("10240000000000", FormatStatValue(Type::INT64, smin).c_str());
  ASSERT_STREQ("20480000000000", FormatStatValue(Type::INT64, smax).c_str());

  float float_min = 1.024f;
  float float_max = 2.048f;
  smin = std::string(reinterpret_cast<char*>(&float_min), sizeof(float));
  smax = std::string(reinterpret_cast<char*>(&float_max), sizeof(float));
  ASSERT_STREQ("1.024", FormatStatValue(Type::FLOAT, smin).c_str());
  ASSERT_STREQ("2.048", FormatStatValue(Type::FLOAT, smax).c_str());

  double double_min = 1.0245;
  double double_max = 2.0489;
  smin = std::string(reinterpret_cast<char*>(&double_min), sizeof(double));
  smax = std::string(reinterpret_cast<char*>(&double_max), sizeof(double));
  ASSERT_STREQ("1.0245", FormatStatValue(Type::DOUBLE, smin).c_str());
  ASSERT_STREQ("2.0489", FormatStatValue(Type::DOUBLE, smax).c_str());

#if ARROW_LITTLE_ENDIAN
  Int96 Int96_min = {{1024, 2048, 4096}};
  Int96 Int96_max = {{2048, 4096, 8192}};
#else
  Int96 Int96_min = {{2048, 1024, 4096}};
  Int96 Int96_max = {{4096, 2048, 8192}};
#endif
  smin = std::string(reinterpret_cast<char*>(&Int96_min), sizeof(Int96));
  smax = std::string(reinterpret_cast<char*>(&Int96_max), sizeof(Int96));
  ASSERT_STREQ("1024 2048 4096", FormatStatValue(Type::INT96, smin).c_str());
  ASSERT_STREQ("2048 4096 8192", FormatStatValue(Type::INT96, smax).c_str());

  smin = std::string("abcdef");
  smax = std::string("ijklmnop");
  ASSERT_STREQ("abcdef", FormatStatValue(Type::BYTE_ARRAY, smin).c_str());
  ASSERT_STREQ("ijklmnop", FormatStatValue(Type::BYTE_ARRAY, smax).c_str());

  // PARQUET-1357: FormatStatValue truncates binary statistics on zero character
  smax.push_back('\0');
  ASSERT_EQ(smax, FormatStatValue(Type::BYTE_ARRAY, smax));

  smin = std::string("abcdefgh");
  smax = std::string("ijklmnop");
  ASSERT_STREQ("abcdefgh", FormatStatValue(Type::FIXED_LEN_BYTE_ARRAY, smin).c_str());
  ASSERT_STREQ("ijklmnop", FormatStatValue(Type::FIXED_LEN_BYTE_ARRAY, smax).c_str());
}

TEST(TestInt96Timestamp, Decoding) {
  auto check = [](int32_t julian_day, uint64_t nanoseconds) {
#if ARROW_LITTLE_ENDIAN
    Int96 i96{static_cast<uint32_t>(nanoseconds),
              static_cast<uint32_t>(nanoseconds >> 32),
              static_cast<uint32_t>(julian_day)};
#else
    Int96 i96{static_cast<uint32_t>(nanoseconds >> 32),
              static_cast<uint32_t>(nanoseconds), static_cast<uint32_t>(julian_day)};
#endif
    // Official formula according to https://github.com/apache/parquet-format/pull/49
    int64_t expected =
        (julian_day - 2440588) * (86400LL * 1000 * 1000 * 1000) + nanoseconds;
    int64_t actual = Int96GetNanoSeconds(i96);
    ASSERT_EQ(expected, actual);
  };

  // [2333837, 2547339] is the range of Julian days that can be converted to
  // 64-bit Unix timestamps.
  check(2333837, 0);
  check(2333855, 0);
  check(2547330, 0);
  check(2547338, 0);
  check(2547339, 0);

  check(2547330, 13);
  check(2547330, 32769);
  check(2547330, 87654);
  check(2547330, 0x123456789abcdefULL);
  check(2547330, 0xfedcba9876543210ULL);
  check(2547339, 0xffffffffffffffffULL);
}

#if !(defined(_WIN32) || defined(__CYGWIN__))
#pragma GCC diagnostic pop
#elif _MSC_VER
#pragma warning(pop)
#endif

}  // namespace parquet
<|endoftext|>


<commit_before>#include <iostream>
#include <random>
#include <queue>
#include <SFML/System.hpp>

#include "Map.h"
#include "PoissonDiskSampling/PoissonDiskSampling.h"
#include "Math/Vector2.h"
#include "Noise/Noise.h"

const std::vector<std::vector<BiomeType>> Map::m_elevationMoistureMatrix = MakeBiomeMatrix();

std::vector<std::vector<BiomeType>> Map::MakeBiomeMatrix()
{
	std::vector<std::vector<BiomeType>> matrix;
	std::vector<BiomeType> biomeVector;

	biomeVector.push_back(BiomeType::SubtropicalDesert);
	biomeVector.push_back(BiomeType::TemprateDesert);
	biomeVector.push_back(BiomeType::TemprateDesert);
	biomeVector.push_back(BiomeType::Mountain);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::Grassland);
	biomeVector.push_back(BiomeType::Grassland);
	biomeVector.push_back(BiomeType::TemprateDesert);
	biomeVector.push_back(BiomeType::Mountain);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::TropicalSeasonalForest);
	biomeVector.push_back(BiomeType::Grassland);
	biomeVector.push_back(BiomeType::Shrubland);
	biomeVector.push_back(BiomeType::Tundra);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::TropicalSeasonalForest);
	biomeVector.push_back(BiomeType::TemprateDeciduousForest);
	biomeVector.push_back(BiomeType::Shrubland);
	biomeVector.push_back(BiomeType::Snow);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::TropicalRainForest);
	biomeVector.push_back(BiomeType::TemprateDeciduousForest);
	biomeVector.push_back(BiomeType::Taiga);
	biomeVector.push_back(BiomeType::Snow);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::TropicalRainForest);
	biomeVector.push_back(BiomeType::TemprateRainForest);
	biomeVector.push_back(BiomeType::Taiga);
	biomeVector.push_back(BiomeType::Snow);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	return matrix;
}

Map::Map(int width, int height, double pointSpread, std::string seed) :
	m_mapWidth(width), m_mapHeight(height), m_pointSpread(pointSpread), m_zCoord(0.0),
	m_noiseMap(nullptr), m_seed(seed), m_centersQuadTree(AABB(Vector2(width / 2, height / 2), Vector2(width / 2, height / 2)), 1)
{
	double approxPointCount = (2 * m_mapWidth * m_mapHeight) / (3.1416 * m_pointSpread * m_pointSpread);
	int maxTreeDepth = floor((log(approxPointCount) / log(4)) + 0.5);
	QuadTree<Center*>::SetMaxDepth(maxTreeDepth);

	m_seed = seed != "" ? seed : CreateSeed(20);
	std::mt19937 mt_rand(HashString(m_seed));

	m_zCoord = mt_rand();
	std::cout << "Seed: " << m_seed << "(" << HashString(m_seed) << ")" << std::endl;
}

void Map::Generate()
{
	sf::Clock timer;

	GeneratePolygons();

	std::cout << "Land distribution: ";
	timer.restart();
	GenerateLand();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	// Elevation
	std::cout << "Coast assignment: ";
	timer.restart();
	AssignOceanCoastLand();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Corner altitude: ";
	timer.restart();
	AssignCornerElevations();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Altitude redistribution: ";
	timer.restart();
	RedistributeElevations();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Center altitude: ";
	timer.restart();
	AssignPolygonElevations();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	// Moisture
	std::cout << "Downslopes: ";
	timer.restart();
	CalculateDownslopes();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "River generation: ";
	timer.restart();
	GenerateRivers();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Corner moisture: ";
	timer.restart();
	AssignCornerMoisture();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Moisture redistribution: ";
	timer.restart();
	RedistributeMoisture();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Center moisture: ";
	timer.restart();
	AssignPolygonMoisture();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	// Biomes
	std::cout << "Biome assignment: ";
	timer.restart();
	AssignBiomes();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Populate Quadtree: ";
	timer.restart();
	for (auto center : m_centers)
	{
		std::pair<Vector2, Vector2> aabb(center->GetBoundingBox());
		m_centersQuadTree.Insert2(center, AABB(aabb.first, aabb.second));
	}
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;
}

void Map::GeneratePolygons()
{
	sf::Clock timer;

	GeneratePoints();
	std::cout << "Point placement: " << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;
	timer.restart();

	Triangulate(m_points);
	std::cout << "Triangulation: " << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;
	timer.restart();

	FinishInfo();
	std::cout << "Finishing touches: " << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;
}

void Map::GenerateLand()
{
	m_noiseMap = new noise::module::Perlin();

	for (auto corner : m_corners)
	{
		if (!corner->IsInsideBoundingBox(m_mapWidth, m_mapHeight))
		{
			corner->m_border = true;
			corner->m_ocean = true;
			corner->m_water = true;
		}
	}

	for (auto corner : m_corners)
	{
		corner->m_water = !IsIsland(corner->m_position);
	}
}

std::vector<Edge*> Map::GetEdges() const
{
	return m_edges;
}

std::vector<Corner*> Map::GetCorners() const
{
	return m_corners;
}

std::vector<Center*> Map::GetCenters() const
{
	return m_centers;
}

Center* Map::GetCenterAt(Vector2 pos)
{
	Center* center = nullptr;
	std::vector<Center*> auxCenters = m_centersQuadTree.QueryRange(pos);

	if (auxCenters.size() > 0)
	{
		double minDist = Vector2(auxCenters[0]->m_position, pos).Length();
		center = auxCenters[0];

		for (auto auxCenter : auxCenters)
		{
			double newDist = Vector2(auxCenter->m_position, pos).Length();
			if (newDist < minDist)
			{
				minDist = newDist;
				center = auxCenter;
			}
		}
	}

	return center;
}

bool Map::IsIsland(Vector2 position)
{
	double waterThreshold = 0.075;

	if (position.x < m_mapWidth * waterThreshold || position.y < m_mapHeight * waterThreshold ||
		position.x > m_mapWidth * (1 - waterThreshold) || position.y > m_mapHeight * (1 - waterThreshold))
	{
		return false;
	}

	Vector2 centerPos = Vector2(m_mapWidth / 2.0, m_mapHeight / 2.0);
	position -= centerPos;

	double xCoord = (position.x / m_mapWidth) * 4;
	double yCoord = (position.y / m_mapHeight) * 4;
	double noiseVal = m_noiseMap->GetValue(xCoord, yCoord, m_zCoord);

	position /= std::min(m_mapWidth, m_mapHeight);
	double radius = position.Length();

	double factor = radius - 0.5;

	return noiseVal >= 0.3 * radius + factor;
}

void Map::CalculateDownslopes()
{
	for (auto c : m_corners)
	{
		Corner* d = c;
		for (auto q : c->m_corners)
		{
			if (q->m_elevation < d->m_elevation)
			{
				d = q;
			}
		}

		c->m_downslope = d;
	}
}

void Map::GenerateRivers()
{
	std::mt19937 mt_rand(HashString(m_seed));
	int numRivers = m_centers.size() / 3;

	for (int i = 0; i < numRivers; ++i)
	{
		Corner* q = m_corners[mt_rand() % m_corners.size()];

		if (q->m_ocean || q->m_elevation < 0.3 || q->m_elevation > 0.9)
		{
			continue;
		}

		while (!q->m_coast)
		{
			if (q == q->m_downslope)
			{
				break;
			}

			Edge* e = q->GetEdgeWith(q->m_downslope);
			e->m_riverVolume += 1;
			q->m_riverVolume += 1;
			q->m_downslope->m_riverVolume += 1;
			q = q->m_downslope;
		}
	}
}

void AssignOceanCoastLand();
void RedistributeElevations();
void AssignCornerElevations();
void AssignPolygonElevations();
void RedistributeMoisture();
void AssignCornerMoisture();
void AssignPolygonMoisture();
void AssignBiomes();

void GeneratePoints();
void Triangulate(std::vector<DelaunayTriangulation::Vertex> points);
void FinishInfo();
void AddCenter(Center* c);
Center* GetCenter(Vector2 position);
void OrderPoints(std::vector<Corner*>& corners);

std::vector<Corner*> GetLandCorners();
std::vector<Corner*> GetLakeCorners();
void LloydRelaxation();
std::string CreateSeed(int length);

static unsigned int HashString(std::string seed);<commit_msg>Implement Map::AssignOceanCoastLand()<commit_after>#include <iostream>
#include <random>
#include <queue>
#include <SFML/System.hpp>

#include "Map.h"
#include "PoissonDiskSampling/PoissonDiskSampling.h"
#include "Math/Vector2.h"
#include "Noise/Noise.h"

const std::vector<std::vector<BiomeType>> Map::m_elevationMoistureMatrix = MakeBiomeMatrix();

std::vector<std::vector<BiomeType>> Map::MakeBiomeMatrix()
{
	std::vector<std::vector<BiomeType>> matrix;
	std::vector<BiomeType> biomeVector;

	biomeVector.push_back(BiomeType::SubtropicalDesert);
	biomeVector.push_back(BiomeType::TemprateDesert);
	biomeVector.push_back(BiomeType::TemprateDesert);
	biomeVector.push_back(BiomeType::Mountain);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::Grassland);
	biomeVector.push_back(BiomeType::Grassland);
	biomeVector.push_back(BiomeType::TemprateDesert);
	biomeVector.push_back(BiomeType::Mountain);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::TropicalSeasonalForest);
	biomeVector.push_back(BiomeType::Grassland);
	biomeVector.push_back(BiomeType::Shrubland);
	biomeVector.push_back(BiomeType::Tundra);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::TropicalSeasonalForest);
	biomeVector.push_back(BiomeType::TemprateDeciduousForest);
	biomeVector.push_back(BiomeType::Shrubland);
	biomeVector.push_back(BiomeType::Snow);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::TropicalRainForest);
	biomeVector.push_back(BiomeType::TemprateDeciduousForest);
	biomeVector.push_back(BiomeType::Taiga);
	biomeVector.push_back(BiomeType::Snow);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	biomeVector.push_back(BiomeType::TropicalRainForest);
	biomeVector.push_back(BiomeType::TemprateRainForest);
	biomeVector.push_back(BiomeType::Taiga);
	biomeVector.push_back(BiomeType::Snow);
	matrix.push_back(biomeVector);
	biomeVector.clear();

	return matrix;
}

Map::Map(int width, int height, double pointSpread, std::string seed) :
	m_mapWidth(width), m_mapHeight(height), m_pointSpread(pointSpread), m_zCoord(0.0),
	m_noiseMap(nullptr), m_seed(seed), m_centersQuadTree(AABB(Vector2(width / 2, height / 2), Vector2(width / 2, height / 2)), 1)
{
	double approxPointCount = (2 * m_mapWidth * m_mapHeight) / (3.1416 * m_pointSpread * m_pointSpread);
	int maxTreeDepth = floor((log(approxPointCount) / log(4)) + 0.5);
	QuadTree<Center*>::SetMaxDepth(maxTreeDepth);

	m_seed = seed != "" ? seed : CreateSeed(20);
	std::mt19937 mt_rand(HashString(m_seed));

	m_zCoord = mt_rand();
	std::cout << "Seed: " << m_seed << "(" << HashString(m_seed) << ")" << std::endl;
}

void Map::Generate()
{
	sf::Clock timer;

	GeneratePolygons();

	std::cout << "Land distribution: ";
	timer.restart();
	GenerateLand();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	// Elevation
	std::cout << "Coast assignment: ";
	timer.restart();
	AssignOceanCoastLand();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Corner altitude: ";
	timer.restart();
	AssignCornerElevations();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Altitude redistribution: ";
	timer.restart();
	RedistributeElevations();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Center altitude: ";
	timer.restart();
	AssignPolygonElevations();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	// Moisture
	std::cout << "Downslopes: ";
	timer.restart();
	CalculateDownslopes();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "River generation: ";
	timer.restart();
	GenerateRivers();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Corner moisture: ";
	timer.restart();
	AssignCornerMoisture();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Moisture redistribution: ";
	timer.restart();
	RedistributeMoisture();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Center moisture: ";
	timer.restart();
	AssignPolygonMoisture();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	// Biomes
	std::cout << "Biome assignment: ";
	timer.restart();
	AssignBiomes();
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;

	std::cout << "Populate Quadtree: ";
	timer.restart();
	for (auto center : m_centers)
	{
		std::pair<Vector2, Vector2> aabb(center->GetBoundingBox());
		m_centersQuadTree.Insert2(center, AABB(aabb.first, aabb.second));
	}
	std::cout << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;
}

void Map::GeneratePolygons()
{
	sf::Clock timer;

	GeneratePoints();
	std::cout << "Point placement: " << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;
	timer.restart();

	Triangulate(m_points);
	std::cout << "Triangulation: " << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;
	timer.restart();

	FinishInfo();
	std::cout << "Finishing touches: " << timer.getElapsedTime().asMicroseconds() / 1000.0 << " ms." << std::endl;
}

void Map::GenerateLand()
{
	m_noiseMap = new noise::module::Perlin();

	for (auto corner : m_corners)
	{
		if (!corner->IsInsideBoundingBox(m_mapWidth, m_mapHeight))
		{
			corner->m_border = true;
			corner->m_ocean = true;
			corner->m_water = true;
		}
	}

	for (auto corner : m_corners)
	{
		corner->m_water = !IsIsland(corner->m_position);
	}
}

std::vector<Edge*> Map::GetEdges() const
{
	return m_edges;
}

std::vector<Corner*> Map::GetCorners() const
{
	return m_corners;
}

std::vector<Center*> Map::GetCenters() const
{
	return m_centers;
}

Center* Map::GetCenterAt(Vector2 pos)
{
	Center* center = nullptr;
	std::vector<Center*> auxCenters = m_centersQuadTree.QueryRange(pos);

	if (auxCenters.size() > 0)
	{
		double minDist = Vector2(auxCenters[0]->m_position, pos).Length();
		center = auxCenters[0];

		for (auto auxCenter : auxCenters)
		{
			double newDist = Vector2(auxCenter->m_position, pos).Length();
			if (newDist < minDist)
			{
				minDist = newDist;
				center = auxCenter;
			}
		}
	}

	return center;
}

bool Map::IsIsland(Vector2 position)
{
	double waterThreshold = 0.075;

	if (position.x < m_mapWidth * waterThreshold || position.y < m_mapHeight * waterThreshold ||
		position.x > m_mapWidth * (1 - waterThreshold) || position.y > m_mapHeight * (1 - waterThreshold))
	{
		return false;
	}

	Vector2 centerPos = Vector2(m_mapWidth / 2.0, m_mapHeight / 2.0);
	position -= centerPos;

	double xCoord = (position.x / m_mapWidth) * 4;
	double yCoord = (position.y / m_mapHeight) * 4;
	double noiseVal = m_noiseMap->GetValue(xCoord, yCoord, m_zCoord);

	position /= std::min(m_mapWidth, m_mapHeight);
	double radius = position.Length();

	double factor = radius - 0.5;

	return noiseVal >= 0.3 * radius + factor;
}

void Map::CalculateDownslopes()
{
	for (auto c : m_corners)
	{
		Corner* d = c;
		for (auto q : c->m_corners)
		{
			if (q->m_elevation < d->m_elevation)
			{
				d = q;
			}
		}

		c->m_downslope = d;
	}
}

void Map::GenerateRivers()
{
	std::mt19937 mt_rand(HashString(m_seed));
	int numRivers = m_centers.size() / 3;

	for (int i = 0; i < numRivers; ++i)
	{
		Corner* q = m_corners[mt_rand() % m_corners.size()];

		if (q->m_ocean || q->m_elevation < 0.3 || q->m_elevation > 0.9)
		{
			continue;
		}

		while (!q->m_coast)
		{
			if (q == q->m_downslope)
			{
				break;
			}

			Edge* e = q->GetEdgeWith(q->m_downslope);
			e->m_riverVolume += 1;
			q->m_riverVolume += 1;
			q->m_downslope->m_riverVolume += 1;
			q = q->m_downslope;
		}
	}
}

void Map::AssignOceanCoastLand()
{
	std::queue<Center*> centersQueue;

	for (auto c : m_centers)
	{
		int adjacentWater = 0;

		for (auto q : c->m_centers)
		{
			if (q->m_border)
			{
				c->m_border = true;
				c->m_ocean = true;
				q->m_water = true;
				centersQueue.push(c);
			}

			if (q->m_water)
			{
				adjacentWater++;
			}
		}

		c->m_water = (c->m_ocean || adjacentWater >= c->m_corners.size() * 0.5);
	}

	while (!centersQueue.empty())
	{
		Center* c = centersQueue.front();
		centersQueue.pop();

		for (auto r : c->m_centers)
		{
			if (r->m_water && !r->m_ocean)
			{
				r->m_ocean = true;
				centersQueue.push(r);
			}
		}
	}

	for (auto p : m_centers)
	{
		int numOcean = 0;
		int numLand = 0;

		for (auto q : p->m_centers)
		{
			numOcean += static_cast<int>(q->m_ocean);
			numLand += static_cast<int>(!q->m_water);
		}

		p->m_coast = numLand > 0 && numOcean > 0;
	}

	for (auto c : m_corners)
	{
		int adjOcean = 0;
		int adjLand = 0;

		for (auto p : c->m_centers)
		{
			adjOcean += static_cast<int>(p->m_ocean);
			adjLand += static_cast<int>(!p->m_water);
		}

		c->m_ocean = adjOcean == c->m_centers.size();
		c->m_coast = adjLand > 0 && adjOcean > 0;
		c->m_water = c->m_border || (adjLand != c->m_centers.size() && !c->m_coast);
	}
}

void RedistributeElevations();
void AssignCornerElevations();
void AssignPolygonElevations();
void RedistributeMoisture();
void AssignCornerMoisture();
void AssignPolygonMoisture();
void AssignBiomes();

void GeneratePoints();
void Triangulate(std::vector<DelaunayTriangulation::Vertex> points);
void FinishInfo();
void AddCenter(Center* c);
Center* GetCenter(Vector2 position);
void OrderPoints(std::vector<Corner*>& corners);

std::vector<Corner*> GetLandCorners();
std::vector<Corner*> GetLakeCorners();
void LloydRelaxation();
std::string CreateSeed(int length);

static unsigned int HashString(std::string seed);<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008, 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

/*!
    \mainpage Context Properties

    \brief The Context Framework allows you to access system- and
    session-wide named values. Examples are context properties like the
    current geographical location. You can receive notifications about
    changes to these values, and you can also easily subscribe and
    unsubscribe from change notifications to help with managing power
    consumption.

    \section Overview

    The Context Properties are key/value pairs. The keys are
    strings and the values are QVariants.

    Key are arranged in a hierarchical namespace like in this example
    of two contextual properties

    \code
    Screen.TopEdge = "left"
    Screen.IsCovered = false
    \endcode

    Although the key names can be considered to form a tree (with
    "Screen" at the root) there is no semantic relationship between
    parent and child nodes in the tree: the key "Screen" is unrelated
    to "Screen.TopEdge".  In particular, change notifications do not
    travel up the tree.

    The \ref Introspection section describes in detail how to get a list of
    existing keys and examine their capabilities.

    Programmers access the key/value pairs through instances of the
    ContextProperty class.  These instances allow applications to
    access the values and receive change notifications.

    Example:
    \code
    ContextProperty *topEdge = new ContextProperty("Screen.TopEdge");
    QObject::connect(topEdge, SIGNAL(valueChanged()),
                     this, SLOT(topEdgeChanged()));
    \endcode

    In your edgeUpChanged method you are able to retrieve the value of the property:
    \code
    qWarning() << "The edge " << topEdge->value() << " is up";
    \endcode

    Creating a ContextProperty instance for a key causes the program
    to 'subscribe' to this key.  The values for some keys might be
    expensive to determine, so you should only subscribe to those keys
    that you are currently interested in.  You can temporarily
    unsubscribe from a key without destroying the ContextProperty
    instance by using the unsubscribe() member function. Later, you
    can resume the subscription by calling the subscribe() member
    function.

    \code
    void onScreenBlank ()
    {
        topEdge->unsubscribe();
    }

    void onScreenUnblank ()
    {
        topEdge->subscribe();
    }
    \endcode

    All the context properties can be used anytime, not depending on
    whether the provider of the property is installed or running.  If
    the system/provider cannot provide you with a value, the value of
    the context property will be null.  If for some reason you are
    interested in property metadata (such as a key's current provider,
    availability, etc.) you should consult the \ref Introspection API.
*/

#include "contextproperty.h"
#include "propertyhandle.h"
#include "sconnect.h"
#include "logging.h"
#include "loggingfeatures.h"

#include <QCoreApplication>
#include <QThread>

using namespace ContextSubscriber;

/*!
   \class ContextPropertyPrivate

   \brief The private parts of the ContextProperty class.
*/

struct ContextPropertyPrivate
{
    PropertyHandle *handle; ///< The common handle behind this context property
    bool subscribed; ///< True, if we are subscribed to the handle behind us
    QVariant value; ///< Our knowledge of the value.  Needed because several
                    /// valueChanged signals might be emitted (queued) by the
                    /// PropertyHandle, without us handling them.
};

/*!
   \class ContextProperty

   \brief The ContextProperty class allows access to keys and their
   values.

   The value is available with the value() member function and change
   notifications are delivered via the valueChanged() signal.

   You can explicity subscribe and unsubscribe using the subscribe()
   and unsubscribe() member functions.  A ContextProperty is
   initially subscribed.

   When a ContextProperty is in the unsubscribed state, it usually
   keeps its last value.  This is not guaranteed however: more than
   one ContextProperty might exist in your process for the same key,
   and as long as one of them is subscribed, all of them might receive
   new values.  The valueChanged() signal is never emitted if the
   property is unsubscribed.

   A ContextProperty is generally asynchronous and relies on a running
   event loop.  Subscriptions and unsubcriptions are only handled and
   new values are only received when your program enters the event
   loop.

   ContextProperty objects can be created only after the
   Q(Core)Application is constructed.

   When a ContextProperty is first created or goes from the
   unsubcribed to the subscribed state later on, it is temporarily in
   an intermediate 'subscribing' state.  This state lasts until the
   negotiations with the provider of the key are over (or an error
   occurs) and the key's current value is known to the
   ContextProperty.

   Thus, there is a time after creating a ContextProperty (or
   subscribing it again) where value() might be out of sync with the
   provider of the key.  If you need to wait for this time to be over,
   you can not rely on the valueChanged() signal being emitted.
   This signal is only emitted when the value actually changes, which
   might not happen when subscription is over.

   Instead, you can use the waitForSubscription() member function.
   This function runs a recursive event loop, if necessary, until the
   ContextProperty is fully subscribed.

   Thus, the recommended way is to first create all ContextProperty
   instances that your program needs and QObject::connect their
   valueChanged() signals, then to call waitForSubscription() on those values
   that are needed to create the initial user interface.

   It is important to create all needed ContextProperty instances
   before calling waitForSubscription() on any of them.  Subscriptions
   are usually bundled together behind the scenes so that they can all
   be done with a single round trip to the provider.  Interleaving
   creation of ContextProperties with calls to waitForSubscription()
   would prevent this optimization.

   \note The \c ContextProperty class follows the usual QObject rules
   for non-GUI classes in multi-threaded programs.  In Qt terminology,
   the ContextProperty class is reentrant but not thread-safe.  This
   means that you can create ContextProperty instances in any thread
   and then freely use these instance in their threads, but you can
   not use a single instance concurrently from multiple threads.

   \note Please pay special attention to how signals and slots work in
   a multi-threaded program: by default, a slot is emitted in the
   thread that called QObject::connect().  For this to happen
   reliably, the thread needs to run a event loop.

   \note See the Qt documentation for \c QThread and related classes
   for more details.
 */

/// Constructs a new ContextProperty for \a key and subscribes to it.
ContextProperty::ContextProperty(const QString &key, QObject* parent)
    : QObject(parent), priv(0)
{
    priv = new ContextPropertyPrivate;

    priv->handle = PropertyHandle::instance(key);
    priv->subscribed = false;

    subscribe();
}

/// Unsubscribes from the ContextProperty and destroys it.
ContextProperty::~ContextProperty()
{
    unsubscribe();
    delete priv;
}

/// Returns the key.
QString ContextProperty::key() const
{
    return priv->handle->key();
}

/// Returns the current value.
QVariant ContextProperty::value() const
{
    return priv->handle->value();
}

/// Returns the current value, or the value \a def if the current
/// value is \c null.
QVariant ContextProperty::value(const QVariant &def) const
{
    QVariant val = priv->handle->value();
    if (val.isNull())
        return def;
    else
        return val;
}

// A safety measure to avoid emitting unnecessary signals, see
// ContextPropertyPrivate::value.
void ContextProperty::onValueChanged()
{
    QVariant newValue = priv->handle->value();
    if (priv->value != newValue ||
        priv->value.isNull() != newValue.isNull() ||
        priv->value.type() != newValue.type())
    {
        priv->value = newValue;
        Q_EMIT valueChanged();
    }
}

/// Starts subscribtion to the context property, if it isn't
/// subscribed already. If you need to wait for it to be complete, use
/// waitForSubscription().
void ContextProperty::subscribe() const
{
    if (priv->subscribed)
        return;

    // We create a queued connection, because otherwise we run
    // the users' valueChanged() handlers with locks and if they do
    // something fancy (for example unsubscribe) it can cause a
    // deadlock.
    sconnect(priv->handle, SIGNAL(valueChanged()), this, SLOT(onValueChanged()), Qt::QueuedConnection);
    priv->handle->subscribe();
    priv->subscribed = true;
}

/// Unsubscribes from the context property, if it is currently
/// subscribed. Unsubscribing informs the rest of the system that no
/// effort needs to be spent to keep the value up-to-date.  However,
/// the value might still change when it can happen 'for free'.  In
/// this case the valueChanged() signal won't be emitted.
void ContextProperty::unsubscribe() const
{
    if (!priv->subscribed)
        return;

    QObject::disconnect(priv->handle, SIGNAL(valueChanged()), this, SIGNAL(valueChanged()));
    priv->handle->unsubscribe();
    priv->subscribed = false;
}

/// Suspends the execution of the current thread until subcription is
/// complete for this context property.  This might cause the main
/// event loop of your program to run and consequently signals might
/// get emitted (including the valueChanged() signal of this
/// property).  Calling this function while the subscription is not in
/// progress (because it has completed already or because the property
/// is currently unsubscribed) does nothing. Calling this function
/// from a thread which is not the main thread results in busy looping.
void ContextProperty::waitForSubscription() const
{
    if (!priv->subscribed)
        return;

    while (priv->handle->isSubscribePending()) {
        if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
            // This is not a busy loop, since the QEventLoop::WaitForMoreEvents flag
            QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
        } else {
            usleep(100000); // 0.1 second
        }
    }
}

/// Suspends the execution of the current thread until subcription is complete
/// for this context property.  Spins the event loop if \a block is false, and
/// blocks (e.g., select / poll with a socket) if \a block is true. Calling this
/// function while the subscription is not in progress (because it has completed
/// already or because the property is currently unsubscribed) does nothing.
/// Calling this function with \a block = true is only allowed for
/// ContextProperty objects associated with the main thread, and calling this
/// function is only allowed in the main thread.
void ContextProperty::waitForSubscription(bool block) const
{
    if (!block) {
        waitForSubscription();
        return;
    }
    if (!priv->subscribed)
        return;
    priv->handle->blockUntilSubscribed();
}

/// Sets all of the ContextProperty instances immune to 'external
/// commanding'.  This is only intended to be used by the Context
/// Commander itself, so that it can use ContextProperties without
/// tripping over itself.  Don't use this.
void ContextProperty::ignoreCommander()
{
    PropertyHandle::ignoreCommander();
}

/// Returns the metadata about this property, please refer to \ref
/// Introspection for details.
const ContextPropertyInfo* ContextProperty::info() const
{
    return priv->handle->info();
}

/// Enables or disables all of the ContextProperty instances'
/// type-check feature.  If it is enabled and the received value from
/// the provider doesn't match the expected type, you will get an
/// error message on the stderr and the value won't be updated. If you
/// use this method, you have to use it before starting any threads.
void ContextProperty::setTypeCheck(bool newTypeCheck)
{
    PropertyHandle::setTypeCheck(newTypeCheck);
}

<commit_msg>Libcontextsubscriber fix: incorrect signal disconnection.<commit_after>/*
 * Copyright (C) 2008, 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

/*!
    \mainpage Context Properties

    \brief The Context Framework allows you to access system- and
    session-wide named values. Examples are context properties like the
    current geographical location. You can receive notifications about
    changes to these values, and you can also easily subscribe and
    unsubscribe from change notifications to help with managing power
    consumption.

    \section Overview

    The Context Properties are key/value pairs. The keys are
    strings and the values are QVariants.

    Key are arranged in a hierarchical namespace like in this example
    of two contextual properties

    \code
    Screen.TopEdge = "left"
    Screen.IsCovered = false
    \endcode

    Although the key names can be considered to form a tree (with
    "Screen" at the root) there is no semantic relationship between
    parent and child nodes in the tree: the key "Screen" is unrelated
    to "Screen.TopEdge".  In particular, change notifications do not
    travel up the tree.

    The \ref Introspection section describes in detail how to get a list of
    existing keys and examine their capabilities.

    Programmers access the key/value pairs through instances of the
    ContextProperty class.  These instances allow applications to
    access the values and receive change notifications.

    Example:
    \code
    ContextProperty *topEdge = new ContextProperty("Screen.TopEdge");
    QObject::connect(topEdge, SIGNAL(valueChanged()),
                     this, SLOT(topEdgeChanged()));
    \endcode

    In your edgeUpChanged method you are able to retrieve the value of the property:
    \code
    qWarning() << "The edge " << topEdge->value() << " is up";
    \endcode

    Creating a ContextProperty instance for a key causes the program
    to 'subscribe' to this key.  The values for some keys might be
    expensive to determine, so you should only subscribe to those keys
    that you are currently interested in.  You can temporarily
    unsubscribe from a key without destroying the ContextProperty
    instance by using the unsubscribe() member function. Later, you
    can resume the subscription by calling the subscribe() member
    function.

    \code
    void onScreenBlank ()
    {
        topEdge->unsubscribe();
    }

    void onScreenUnblank ()
    {
        topEdge->subscribe();
    }
    \endcode

    All the context properties can be used anytime, not depending on
    whether the provider of the property is installed or running.  If
    the system/provider cannot provide you with a value, the value of
    the context property will be null.  If for some reason you are
    interested in property metadata (such as a key's current provider,
    availability, etc.) you should consult the \ref Introspection API.
*/

#include "contextproperty.h"
#include "propertyhandle.h"
#include "sconnect.h"
#include "logging.h"
#include "loggingfeatures.h"

#include <QCoreApplication>
#include <QThread>

using namespace ContextSubscriber;

/*!
   \class ContextPropertyPrivate

   \brief The private parts of the ContextProperty class.
*/

struct ContextPropertyPrivate
{
    PropertyHandle *handle; ///< The common handle behind this context property
    bool subscribed; ///< True, if we are subscribed to the handle behind us
    QVariant value; ///< Our knowledge of the value.  Needed because several
                    /// valueChanged signals might be emitted (queued) by the
                    /// PropertyHandle, without us handling them.
};

/*!
   \class ContextProperty

   \brief The ContextProperty class allows access to keys and their
   values.

   The value is available with the value() member function and change
   notifications are delivered via the valueChanged() signal.

   You can explicity subscribe and unsubscribe using the subscribe()
   and unsubscribe() member functions.  A ContextProperty is
   initially subscribed.

   When a ContextProperty is in the unsubscribed state, it usually
   keeps its last value.  This is not guaranteed however: more than
   one ContextProperty might exist in your process for the same key,
   and as long as one of them is subscribed, all of them might receive
   new values.  The valueChanged() signal is never emitted if the
   property is unsubscribed.

   A ContextProperty is generally asynchronous and relies on a running
   event loop.  Subscriptions and unsubcriptions are only handled and
   new values are only received when your program enters the event
   loop.

   ContextProperty objects can be created only after the
   Q(Core)Application is constructed.

   When a ContextProperty is first created or goes from the
   unsubcribed to the subscribed state later on, it is temporarily in
   an intermediate 'subscribing' state.  This state lasts until the
   negotiations with the provider of the key are over (or an error
   occurs) and the key's current value is known to the
   ContextProperty.

   Thus, there is a time after creating a ContextProperty (or
   subscribing it again) where value() might be out of sync with the
   provider of the key.  If you need to wait for this time to be over,
   you can not rely on the valueChanged() signal being emitted.
   This signal is only emitted when the value actually changes, which
   might not happen when subscription is over.

   Instead, you can use the waitForSubscription() member function.
   This function runs a recursive event loop, if necessary, until the
   ContextProperty is fully subscribed.

   Thus, the recommended way is to first create all ContextProperty
   instances that your program needs and QObject::connect their
   valueChanged() signals, then to call waitForSubscription() on those values
   that are needed to create the initial user interface.

   It is important to create all needed ContextProperty instances
   before calling waitForSubscription() on any of them.  Subscriptions
   are usually bundled together behind the scenes so that they can all
   be done with a single round trip to the provider.  Interleaving
   creation of ContextProperties with calls to waitForSubscription()
   would prevent this optimization.

   \note The \c ContextProperty class follows the usual QObject rules
   for non-GUI classes in multi-threaded programs.  In Qt terminology,
   the ContextProperty class is reentrant but not thread-safe.  This
   means that you can create ContextProperty instances in any thread
   and then freely use these instance in their threads, but you can
   not use a single instance concurrently from multiple threads.

   \note Please pay special attention to how signals and slots work in
   a multi-threaded program: by default, a slot is emitted in the
   thread that called QObject::connect().  For this to happen
   reliably, the thread needs to run a event loop.

   \note See the Qt documentation for \c QThread and related classes
   for more details.
 */

/// Constructs a new ContextProperty for \a key and subscribes to it.
ContextProperty::ContextProperty(const QString &key, QObject* parent)
    : QObject(parent), priv(0)
{
    priv = new ContextPropertyPrivate;

    priv->handle = PropertyHandle::instance(key);
    priv->subscribed = false;

    subscribe();
}

/// Unsubscribes from the ContextProperty and destroys it.
ContextProperty::~ContextProperty()
{
    unsubscribe();
    delete priv;
}

/// Returns the key.
QString ContextProperty::key() const
{
    return priv->handle->key();
}

/// Returns the current value.
QVariant ContextProperty::value() const
{
    return priv->handle->value();
}

/// Returns the current value, or the value \a def if the current
/// value is \c null.
QVariant ContextProperty::value(const QVariant &def) const
{
    QVariant val = priv->handle->value();
    if (val.isNull())
        return def;
    else
        return val;
}

// A safety measure to avoid emitting unnecessary signals, see
// ContextPropertyPrivate::value.
void ContextProperty::onValueChanged()
{
    QVariant newValue = priv->handle->value();
    if (priv->value != newValue ||
        priv->value.isNull() != newValue.isNull() ||
        priv->value.type() != newValue.type())
    {
        priv->value = newValue;
        Q_EMIT valueChanged();
    }
}

/// Starts subscribtion to the context property, if it isn't
/// subscribed already. If you need to wait for it to be complete, use
/// waitForSubscription().
void ContextProperty::subscribe() const
{
    if (priv->subscribed)
        return;

    // We create a queued connection, because otherwise we run
    // the users' valueChanged() handlers with locks and if they do
    // something fancy (for example unsubscribe) it can cause a
    // deadlock.
    sconnect(priv->handle, SIGNAL(valueChanged()), this, SLOT(onValueChanged()), Qt::QueuedConnection);
    priv->handle->subscribe();
    priv->subscribed = true;
}

/// Unsubscribes from the context property, if it is currently
/// subscribed. Unsubscribing informs the rest of the system that no
/// effort needs to be spent to keep the value up-to-date.  However,
/// the value might still change when it can happen 'for free'.  In
/// this case the valueChanged() signal won't be emitted.
void ContextProperty::unsubscribe() const
{
    if (!priv->subscribed)
        return;

    QObject::disconnect(priv->handle, SIGNAL(valueChanged()), this, SLOT(onValueChanged()));
    priv->handle->unsubscribe();
    priv->subscribed = false;
}

/// Suspends the execution of the current thread until subcription is
/// complete for this context property.  This might cause the main
/// event loop of your program to run and consequently signals might
/// get emitted (including the valueChanged() signal of this
/// property).  Calling this function while the subscription is not in
/// progress (because it has completed already or because the property
/// is currently unsubscribed) does nothing. Calling this function
/// from a thread which is not the main thread results in busy looping.
void ContextProperty::waitForSubscription() const
{
    if (!priv->subscribed)
        return;

    while (priv->handle->isSubscribePending()) {
        if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
            // This is not a busy loop, since the QEventLoop::WaitForMoreEvents flag
            QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
        } else {
            usleep(100000); // 0.1 second
        }
    }
}

/// Suspends the execution of the current thread until subcription is complete
/// for this context property.  Spins the event loop if \a block is false, and
/// blocks (e.g., select / poll with a socket) if \a block is true. Calling this
/// function while the subscription is not in progress (because it has completed
/// already or because the property is currently unsubscribed) does nothing.
/// Calling this function with \a block = true is only allowed for
/// ContextProperty objects associated with the main thread, and calling this
/// function is only allowed in the main thread.
void ContextProperty::waitForSubscription(bool block) const
{
    if (!block) {
        waitForSubscription();
        return;
    }
    if (!priv->subscribed)
        return;
    priv->handle->blockUntilSubscribed();
}

/// Sets all of the ContextProperty instances immune to 'external
/// commanding'.  This is only intended to be used by the Context
/// Commander itself, so that it can use ContextProperties without
/// tripping over itself.  Don't use this.
void ContextProperty::ignoreCommander()
{
    PropertyHandle::ignoreCommander();
}

/// Returns the metadata about this property, please refer to \ref
/// Introspection for details.
const ContextPropertyInfo* ContextProperty::info() const
{
    return priv->handle->info();
}

/// Enables or disables all of the ContextProperty instances'
/// type-check feature.  If it is enabled and the received value from
/// the provider doesn't match the expected type, you will get an
/// error message on the stderr and the value won't be updated. If you
/// use this method, you have to use it before starting any threads.
void ContextProperty::setTypeCheck(bool newTypeCheck)
{
    PropertyHandle::setTypeCheck(newTypeCheck);
}

<|endoftext|>