<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow_lite_support/c/task/vision/image_classifier.h"

#include <string.h>

#include "tensorflow_lite_support/c/task/processor/classification_result.h"
#include "tensorflow_lite_support/c/task/vision/core/frame_buffer.h"
#include "tensorflow_lite_support/c/test/task/vision/utils/image_utils.h"
#include "tensorflow_lite_support/cc/port/gmock.h"
#include "tensorflow_lite_support/cc/port/gtest.h"
#include "tensorflow_lite_support/cc/test/test_utils.h"

namespace tflite {
namespace task {
namespace vision {
namespace {

using ::tflite::task::JoinPath;

constexpr char kTestDataDirectory[] =
    "tensorflow_lite_support/cc/test/testdata/task/vision/";
// Quantized model.
constexpr char kMobileNetQuantizedWithMetadata[] =
    "mobilenet_v1_0.25_224_quant.tflite";

CImageData LoadImage(const char* image_name) {
  return CDecodeImageFromFile(
      JoinPath("./" /*test src dir*/, kTestDataDirectory, image_name).data());
}

TEST(CImageClassifierFromOptionsTest, FailsWithMissingModelPath) {
  TfLiteImageClassifierOptions options = {0};
  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  ASSERT_EQ(image_classifier, nullptr);
}

TEST(CImageClassifierFromOptionsTest, SucceedsWithModelPath) {
  //   TfLiteImageClassifierOptions* options =
  //   TfLiteImageClassifierOptionsCreate();
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();
  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;
  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  EXPECT_NE(image_classifier, nullptr);
  TfLiteImageClassifierDelete(image_classifier);
}

TEST(CImageClassifierFromOptionsTest, SucceedsWithNumberOfThreads) {
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();

  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;
  options.base_options.compute_settings.tflite_settings.cpu_settings
      .num_threads = 3;
  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  EXPECT_NE(image_classifier, nullptr);
  TfLiteImageClassifierDelete(image_classifier);
}

TEST(CImageClassifierFromOptionsTest,
     FailsWithClassNameBlackListAndClassNameWhiteList) {
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();

  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;

  char* class_name_blacklist[] = {"brambling"};
  options.classification_options.class_name_blacklist.list =
      class_name_blacklist;
  options.classification_options.class_name_blacklist.length = 1;

  char* class_name_whitelist[] = {"cheeseburger"};
  options.classification_options.class_name_whitelist.list =
      class_name_whitelist;
  options.classification_options.class_name_whitelist.length = 1;

  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  EXPECT_EQ(image_classifier, nullptr);
  if (image_classifier) TfLiteImageClassifierDelete(image_classifier);
}

class CImageClassifierClassifyTest : public ::testing::Test {
 protected:
  void SetUp() override {
    TfLiteImageClassifierOptions options = {0};
    options.base_options.model_file.file_path =
        JoinPath("./" /*test src dir*/, kTestDataDirectory,
                 kMobileNetQuantizedWithMetadata)
            .data();
    image_classifier = TfLiteImageClassifierFromOptions(&options);

    ASSERT_NE(image_classifier, nullptr);
  }

  void TearDown() override { TfLiteImageClassifierDelete(image_classifier); }
  TfLiteImageClassifier* image_classifier;
};

TEST_F(CImageClassifierClassifyTest, SucceedsWithImageData) {
  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassify(image_classifier, &frame_buffer);

  CImageDataFree(&image_data);

  ASSERT_NE(classification_result, nullptr) << "Classification Result is NULL";
  EXPECT_TRUE(classification_result->size >= 1)
      << "Classification Result size is 0";
  EXPECT_NE(classification_result->classifications, nullptr)
      << "Classification Result Classifications is NULL";
  EXPECT_TRUE(classification_result->classifications->size >= 1)
      << "Classification Result Classifications Size is 0";
  EXPECT_NE(classification_result->classifications->categories, nullptr)
      << "Classification Result Classifications Classes is NULL";

  TfLiteClassificationResultDelete(classification_result);
}

TEST_F(CImageClassifierClassifyTest, SucceedsWithRoiWithinImageBounds) {
  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteBoundingBox bounding_box = {
      .origin_x = 0, .origin_y = 0, .width = 100, .height = 100};
  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassifyWithRoi(image_classifier, &frame_buffer,
                                           &bounding_box);

  CImageDataFree(&image_data);

  ASSERT_NE(classification_result, nullptr) << "Classification Result is NULL";
  EXPECT_TRUE(classification_result->size >= 1)
      << "Classification Result size is 0";
  EXPECT_NE(classification_result->classifications, nullptr)
      << "Classification Result Classifications is NULL";
  EXPECT_TRUE(classification_result->classifications->size >= 1)
      << "Classification Result Classifications Size is 0";
  EXPECT_NE(classification_result->classifications->categories, nullptr)
      << "Classification Result Classifications Classes is NULL";

  TfLiteClassificationResultDelete(classification_result);
}

TEST_F(CImageClassifierClassifyTest, FailsWithRoiOutsideImageBounds) {
  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteBoundingBox bounding_box = {
      .origin_x = 0, .origin_y = 0, .width = 250, .height = 250};
  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassifyWithRoi(image_classifier, &frame_buffer,
                                           &bounding_box);

  CImageDataFree(&image_data);

  ASSERT_EQ(classification_result, nullptr)
      << "Classification Result is not NULL";

  if (classification_result != nullptr)
    TfLiteClassificationResultDelete(classification_result);
}

TEST(CImageClassifierWithUserDefinedOptionsClassifyTest,
     SucceedsWithClassNameBlackList) {
  char* blacklisted_label_name = "cheeseburger";
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();

  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;

  char* class_name_blacklist[] = {blacklisted_label_name};
  options.classification_options.class_name_blacklist.list =
      class_name_blacklist;
  options.classification_options.class_name_blacklist.length = 1;

  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  ASSERT_NE(image_classifier, nullptr);

  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassify(image_classifier, &frame_buffer);

  CImageDataFree(&image_data);

  ASSERT_NE(classification_result, nullptr) << "Classification Result is NULL";
  EXPECT_TRUE(classification_result->size >= 1)
      << "Classification Result size is 0";
  EXPECT_NE(classification_result->classifications, nullptr)
      << "Classification Result Classifications is NULL";
  EXPECT_TRUE(classification_result->classifications->size >= 1)
      << "Classification Result Classifications Size is 0";
  EXPECT_NE(classification_result->classifications->categories, nullptr)
      << "Classification Result Classifications Categories is NULL";
  EXPECT_TRUE(
      strcmp(classification_result->classifications->categories[0].label,
             blacklisted_label_name) != 0)
      << "Black listed class is present in classification results ";
  if (image_classifier) TfLiteImageClassifierDelete(image_classifier);

  TfLiteClassificationResultDelete(classification_result);
}

TEST(CImageClassifierWithUserDefinedOptionsClassifyTest,
     SucceedsWithClassNameWhiteList) {
  char* whitelisted_label_name = "cheeseburger";
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();

  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;

  char* class_name_whitelist[] = {"cheeseburger"};
  options.classification_options.class_name_whitelist.list =
      class_name_whitelist;
  options.classification_options.class_name_whitelist.length = 1;

  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  ASSERT_NE(image_classifier, nullptr);

  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassify(image_classifier, &frame_buffer);

  CImageDataFree(&image_data);

  ASSERT_NE(classification_result, nullptr) << "Classification Result is NULL";
  EXPECT_TRUE(classification_result->size >= 1)
      << "Classification Result size is 0";
  EXPECT_NE(classification_result->classifications, nullptr)
      << "Classification Result Classifications is NULL";
  EXPECT_TRUE(classification_result->classifications->size == 1)
      << "Classification Result Classifications Size is 0";
  EXPECT_NE(classification_result->classifications->categories, nullptr)
      << "Classification Result Classifications Categories is NULL";
  EXPECT_TRUE(
      strcmp(classification_result->classifications->categories[0].label,
             whitelisted_label_name) == 0)
      << "White listed class is not present in classification results.";

  if (image_classifier) TfLiteImageClassifierDelete(image_classifier);

  TfLiteClassificationResultDelete(classification_result);
}

}  // namespace
}  // namespace vision
}  // namespace task
}  // namespace tflite
<commit_msg>Updated tests to reflect new structure of TfLiteBaseOptions<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow_lite_support/c/task/vision/image_classifier.h"

#include <string.h>

#include "tensorflow_lite_support/c/task/processor/classification_result.h"
#include "tensorflow_lite_support/c/task/vision/core/frame_buffer.h"
#include "tensorflow_lite_support/c/test/task/vision/utils/image_utils.h"
#include "tensorflow_lite_support/cc/port/gmock.h"
#include "tensorflow_lite_support/cc/port/gtest.h"
#include "tensorflow_lite_support/cc/test/test_utils.h"

namespace tflite {
namespace task {
namespace vision {
namespace {

using ::tflite::task::JoinPath;

constexpr char kTestDataDirectory[] =
    "tensorflow_lite_support/cc/test/testdata/task/vision/";
// Quantized model.
constexpr char kMobileNetQuantizedWithMetadata[] =
    "mobilenet_v1_0.25_224_quant.tflite";

CImageData LoadImage(const char* image_name) {
  return CDecodeImageFromFile(
      JoinPath("./" /*test src dir*/, kTestDataDirectory, image_name).data());
}

TEST(CImageClassifierFromOptionsTest, FailsWithMissingModelPath) {
  TfLiteImageClassifierOptions options = {0};
  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  ASSERT_EQ(image_classifier, nullptr);
}

TEST(CImageClassifierFromOptionsTest, SucceedsWithModelPath) {
  //   TfLiteImageClassifierOptions* options =
  //   TfLiteImageClassifierOptionsCreate();
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();
  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;
  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  EXPECT_NE(image_classifier, nullptr);
  TfLiteImageClassifierDelete(image_classifier);
}

TEST(CImageClassifierFromOptionsTest, SucceedsWithNumberOfThreads) {
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();

  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;
  options.base_options.compute_settings.num_threads = 3;
  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  EXPECT_NE(image_classifier, nullptr);
  TfLiteImageClassifierDelete(image_classifier);
}

TEST(CImageClassifierFromOptionsTest,
     FailsWithClassNameBlackListAndClassNameWhiteList) {
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();

  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;

  char* class_name_blacklist[] = {"brambling"};
  options.classification_options.class_name_blacklist.list =
      class_name_blacklist;
  options.classification_options.class_name_blacklist.length = 1;

  char* class_name_whitelist[] = {"cheeseburger"};
  options.classification_options.class_name_whitelist.list =
      class_name_whitelist;
  options.classification_options.class_name_whitelist.length = 1;

  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  EXPECT_EQ(image_classifier, nullptr);
  if (image_classifier) TfLiteImageClassifierDelete(image_classifier);
}

class CImageClassifierClassifyTest : public ::testing::Test {
 protected:
  void SetUp() override {
    TfLiteImageClassifierOptions options = {0};
    options.base_options.model_file.file_path =
        JoinPath("./" /*test src dir*/, kTestDataDirectory,
                 kMobileNetQuantizedWithMetadata)
            .data();
    image_classifier = TfLiteImageClassifierFromOptions(&options);

    ASSERT_NE(image_classifier, nullptr);
  }

  void TearDown() override { TfLiteImageClassifierDelete(image_classifier); }
  TfLiteImageClassifier* image_classifier;
};

TEST_F(CImageClassifierClassifyTest, SucceedsWithImageData) {
  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassify(image_classifier, &frame_buffer);

  CImageDataFree(&image_data);

  ASSERT_NE(classification_result, nullptr) << "Classification Result is NULL";
  EXPECT_TRUE(classification_result->size >= 1)
      << "Classification Result size is 0";
  EXPECT_NE(classification_result->classifications, nullptr)
      << "Classification Result Classifications is NULL";
  EXPECT_TRUE(classification_result->classifications->size >= 1)
      << "Classification Result Classifications Size is 0";
  EXPECT_NE(classification_result->classifications->categories, nullptr)
      << "Classification Result Classifications Classes is NULL";

  TfLiteClassificationResultDelete(classification_result);
}

TEST_F(CImageClassifierClassifyTest, SucceedsWithRoiWithinImageBounds) {
  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteBoundingBox bounding_box = {
      .origin_x = 0, .origin_y = 0, .width = 100, .height = 100};
  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassifyWithRoi(image_classifier, &frame_buffer,
                                           &bounding_box);

  CImageDataFree(&image_data);

  ASSERT_NE(classification_result, nullptr) << "Classification Result is NULL";
  EXPECT_TRUE(classification_result->size >= 1)
      << "Classification Result size is 0";
  EXPECT_NE(classification_result->classifications, nullptr)
      << "Classification Result Classifications is NULL";
  EXPECT_TRUE(classification_result->classifications->size >= 1)
      << "Classification Result Classifications Size is 0";
  EXPECT_NE(classification_result->classifications->categories, nullptr)
      << "Classification Result Classifications Classes is NULL";

  TfLiteClassificationResultDelete(classification_result);
}

TEST_F(CImageClassifierClassifyTest, FailsWithRoiOutsideImageBounds) {
  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteBoundingBox bounding_box = {
      .origin_x = 0, .origin_y = 0, .width = 250, .height = 250};
  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassifyWithRoi(image_classifier, &frame_buffer,
                                           &bounding_box);

  CImageDataFree(&image_data);

  ASSERT_EQ(classification_result, nullptr)
      << "Classification Result is not NULL";

  if (classification_result != nullptr)
    TfLiteClassificationResultDelete(classification_result);
}

TEST(CImageClassifierWithUserDefinedOptionsClassifyTest,
     SucceedsWithClassNameBlackList) {
  char* blacklisted_label_name = "cheeseburger";
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();

  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;

  char* class_name_blacklist[] = {blacklisted_label_name};
  options.classification_options.class_name_blacklist.list =
      class_name_blacklist;
  options.classification_options.class_name_blacklist.length = 1;

  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  ASSERT_NE(image_classifier, nullptr);

  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassify(image_classifier, &frame_buffer);

  CImageDataFree(&image_data);

  ASSERT_NE(classification_result, nullptr) << "Classification Result is NULL";
  EXPECT_TRUE(classification_result->size >= 1)
      << "Classification Result size is 0";
  EXPECT_NE(classification_result->classifications, nullptr)
      << "Classification Result Classifications is NULL";
  EXPECT_TRUE(classification_result->classifications->size >= 1)
      << "Classification Result Classifications Size is 0";
  EXPECT_NE(classification_result->classifications->categories, nullptr)
      << "Classification Result Classifications Categories is NULL";
  EXPECT_TRUE(
      strcmp(classification_result->classifications->categories[0].label,
             blacklisted_label_name) != 0)
      << "Black listed class is present in classification results ";
  if (image_classifier) TfLiteImageClassifierDelete(image_classifier);

  TfLiteClassificationResultDelete(classification_result);
}

TEST(CImageClassifierWithUserDefinedOptionsClassifyTest,
     SucceedsWithClassNameWhiteList) {
  char* whitelisted_label_name = "cheeseburger";
  const char* model_path = JoinPath("./" /*test src dir*/, kTestDataDirectory,
                                    kMobileNetQuantizedWithMetadata)
                               .data();

  TfLiteImageClassifierOptions options = {0};
  options.base_options.model_file.file_path = model_path;

  char* class_name_whitelist[] = {"cheeseburger"};
  options.classification_options.class_name_whitelist.list =
      class_name_whitelist;
  options.classification_options.class_name_whitelist.length = 1;

  TfLiteImageClassifier* image_classifier =
      TfLiteImageClassifierFromOptions(&options);
  ASSERT_NE(image_classifier, nullptr);

  CImageData image_data = LoadImage("burger-224.png");

  TfLiteFrameBuffer frame_buffer = {.dimension.width = image_data.width,
                                    .dimension.height = image_data.height,
                                    .buffer = image_data.pixel_data,
                                    .format = kRGB};

  TfLiteClassificationResult* classification_result =
      TfLiteImageClassifierClassify(image_classifier, &frame_buffer);

  CImageDataFree(&image_data);

  ASSERT_NE(classification_result, nullptr) << "Classification Result is NULL";
  EXPECT_TRUE(classification_result->size >= 1)
      << "Classification Result size is 0";
  EXPECT_NE(classification_result->classifications, nullptr)
      << "Classification Result Classifications is NULL";
  EXPECT_TRUE(classification_result->classifications->size == 1)
      << "Classification Result Classifications Size is 0";
  EXPECT_NE(classification_result->classifications->categories, nullptr)
      << "Classification Result Classifications Categories is NULL";
  EXPECT_TRUE(
      strcmp(classification_result->classifications->categories[0].label,
             whitelisted_label_name) == 0)
      << "White listed class is not present in classification results.";

  if (image_classifier) TfLiteImageClassifierDelete(image_classifier);

  TfLiteClassificationResultDelete(classification_result);
}

}  // namespace
}  // namespace vision
}  // namespace task
}  // namespace tflite
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <ctime>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <chrono>
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <algorithm>
#include <chrono>
#include <map>
#include <set>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

using namespace std;

char randomNucleotide(){
	switch (rand() % 4){
		case 0:
			return 'A';
		case 1:
			return 'C';
		case 2:
			return 'G';
		case 3:
			return 'T';
	}
	return 'A';
}

string randomSequence(const uint length){
	string result(length, 'A');
	for(uint i(0); i < length; ++i){
		result[i] = randomNucleotide();
	}
	return result;
}

void insertion(double rate, string& result){
	uint dice(rand() % 100);
	if(dice < rate){
		char newNucleotide(randomNucleotide());
		result.push_back(newNucleotide);
		insertion(rate, result);
	}
}

string mutateSequence(const string& referenceSequence, uint maxMutRate=0, vector <double> ratioMutation={0.06,0.73,0.21}){
//~ string mutateSequence(const string& referenceSequence, uint maxMutRate=3, vector <double> ratioMutation={0.06,0.73,0.21}){
	string result;
	result.reserve(5 * referenceSequence.size());
	for(uint i(0); i < referenceSequence.size(); ++i){
		uint mutRate(maxMutRate);
		//~ uint mutRate(rand() % maxMutRate);
		double substitutionRate(mutRate * ratioMutation[0]);
		double insertionRate(mutRate * ratioMutation[1]);
		double deletionRate(mutRate * ratioMutation[2]);
		uint dice(rand() % 100);

		if (dice <substitutionRate ){
			//SUBSTITUTION
			char newNucleotide(randomNucleotide());
			while(newNucleotide == referenceSequence[i]){
				newNucleotide = randomNucleotide();
			}
			result.push_back(newNucleotide);
			continue;
		} else if(dice < deletionRate+substitutionRate){
			//DELETION
			uint dice2(rand() % 100);
			while (dice2 < deletionRate+substitutionRate){ // deletions larger than 1
				++i;
				dice2 = rand() % 100;
			}
			continue;
		} else if (dice < deletionRate + substitutionRate + insertionRate){
			//INSERTION
			char newNucleotide(randomNucleotide());
			result.push_back(referenceSequence[i]);
			result.push_back(newNucleotide);
			//~ --i;
			insertion(deletionRate + substitutionRate + insertionRate, result); // larger than 1 insertions

			continue;
		} else {
		//NO ERROR
			result.push_back(referenceSequence[i]);
		}

	}
	return result;
}

//~ vector<string> generateAlternativeTranscriptReferences(uint transcriptNumber=3, uint totalExonNumber=15, uint exonNumber=6, uint sizeExons=100){
vector<vector<string>> generateAlternativeTranscriptReferences(ifstream& refFile, uint referenceNumber, uint transcriptNumber=3, uint totalExonNumber=14, uint exonNumber=10, uint sizeExons=200){
	string sequence;
	vector<vector<string>> result;
	uint nbRef(0);
	uint position(0);
	string transcript;
	unordered_set<uint> selectedExons;
	while (not refFile.eof() and nbRef < referenceNumber){
        getline(refFile, sequence);
		getline(refFile, sequence);
		uint lengthExons;
		if (sequence.size()/sizeExons < totalExonNumber){
			lengthExons = sequence.size()/(totalExonNumber+1);
		} else {
			lengthExons = sizeExons;
		}
		if (lengthExons > 30){
			position = 0;
			vector<string> exonList;
			uint i(0);
			while (i < totalExonNumber and position < sequence.size()){ // creation of exons from genomic sequence
				string exon(sequence.substr(position, lengthExons));
				exonList.push_back(exon);
				position += lengthExons;
				++i;
			}
			++nbRef;
			vector<string> transcriptList;
			for(uint i(0); i < transcriptNumber; ++i){
				uint dice1(rand() % (totalExonNumber - 3));
				uint transcriptExonNumber(dice1 + 3);
				transcript = "";
				selectedExons = {};
				while(selectedExons.size() != transcriptExonNumber){
					selectedExons.insert(rand() % exonList.size());
				}
				for(uint ii(0); ii < exonList.size(); ++ii){
					if(selectedExons.count(ii) == 1){
						transcript += exonList[ii];
					}
				}
				transcriptList.push_back(transcript);
			}
			result.push_back(transcriptList);
		}
	}
	return result;
}

unordered_map<uint, uint> geneExpressionChunks(uint referencesNumber, uint numberReads){
	uint nbMidExpressed(referencesNumber * 0.6); // code 1
	uint nbHighlyExpressed(referencesNumber * 0.1+1); // code 0

	unordered_map<uint, uint> result;
	cout << "high:" << nbHighlyExpressed << " medium:" << nbMidExpressed << " low:" <<  referencesNumber - nbMidExpressed - nbHighlyExpressed << endl;
	unordered_set<uint> refs;
	for (uint i(0); i < referencesNumber; ++i){
		refs.insert(i);
	}
	uint i(0);
	for (auto j (refs.begin()); j != refs.end(), i < nbHighlyExpressed;){
			result.insert({*j, 0});
			j = refs.erase(j);
			++i;
	}
	i = 0;
	for (auto j (refs.begin()); j != refs.end(), i < nbMidExpressed;){
			result.insert({*j, 1});
			j = refs.erase(j);
			++i;
	}
	cout << "check size " << refs.size();
	for (auto j (refs.begin()); j != refs.end(); ++j){

			result.insert({*j, 2});
	}
	return result;
}

void generateReads(uint numberReads, ifstream& inRef, uint referencesNumber=1, const string& outFileName="simulatedReads.fa", const string& outRefFileName="RefFile"){
	ofstream out(outFileName);
	ofstream outRef(outRefFileName);
	vector<vector<string>> referenceList(generateAlternativeTranscriptReferences(inRef, referencesNumber));

	int highly(numberReads);
	int regular(0);
	int rare(0);
	//~ int highly(numberReads*0.5);
	//~ int regular(numberReads*0.4);
	//~ int rare(numberReads - highly - regular);

	unordered_map<uint, uint> geneExpression(geneExpressionChunks(referencesNumber, numberReads));

	cout << "nb reads:" << numberReads << " nb rare reads:" << rare << " nb regular reads:"<< regular << " nb high reads:"<< highly << endl;

	for(uint i(0);i < referenceList.size(); ++i){
		string expr;
		switch (geneExpression[i]){
		case 0:
			expr = "highExpression";
			break;
		case 1:
			expr = "regularExpression";
			break;
		case 2:
			expr = "shallowExpression";
			break;
		}
		for(uint ii(0); ii<referenceList[i].size(); ++ii){
			outRef << ">referenceNumber:" << i << " alternativeNumber" << ii << " " <<  expr <<endl;
			outRef << referenceList[i][ii] << endl;
		}
	}

	string refRead,realRead;

	int hi(0), re(0), ra(0);
	while (hi < highly or re < regular or ra < rare){
		uint dice1(rand() % referencesNumber);
		uint dice2(rand() % (referenceList[dice1].size() ));
		int expr(geneExpression[dice1]);
		if (expr == 0 and hi < highly){
			++hi;
			string expression = "highExpression";
			refRead = referenceList[dice1][dice2];
			realRead = mutateSequence(refRead);
			out << ">referenceNumber:" << dice1 << " alternativeNumber:" << dice2  << " " << expression << endl;
			out << realRead << endl;
		}
		if (expr == 1 and re < regular){
			++re;
			string expression = "regularExpression";
			refRead = referenceList[dice1][dice2];
			realRead = mutateSequence(refRead);
			out << ">referenceNumber:" << dice1 << " alternativeNumber:" << dice2  << " " << expression << endl;
			out << realRead << endl;
		}
		if (expr == 2 and ra < rare){
			++ra;
			string expression = "lowExpression";
			refRead = referenceList[dice1][dice2];
			realRead = mutateSequence(refRead);
			out << ">referenceNumber:" << dice1 << " alternativeNumber:" << dice2  << " " << expression << endl;
			out << realRead << endl;
		}
	}
}

int main(int argc, char ** argv){
	if (argc > 1){
		string refName = argv[1];
		ifstream refFile(refName);
		srand (time(NULL));
		auto startChrono = chrono::system_clock::now();
		generateReads(50, refFile);
		auto end = chrono::system_clock::now(); auto waitedFor = end - startChrono;
		cout << "Time  in ms : " << (chrono::duration_cast<chrono::milliseconds>(waitedFor).count()) << endl;
	}
	return 0;
}
<commit_msg>fixed when there is only one reference<commit_after>#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <ctime>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <chrono>
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <algorithm>
#include <chrono>
#include <map>
#include <set>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

using namespace std;

char randomNucleotide(){
	switch (rand() % 4){
		case 0:
			return 'A';
		case 1:
			return 'C';
		case 2:
			return 'G';
		case 3:
			return 'T';
	}
	return 'A';
}

string randomSequence(const uint length){
	string result(length, 'A');
	for(uint i(0); i < length; ++i){
		result[i] = randomNucleotide();
	}
	return result;
}

void insertion(double rate, string& result){
	uint dice(rand() % 100);
	if(dice < rate){
		char newNucleotide(randomNucleotide());
		result.push_back(newNucleotide);
		insertion(rate, result);
	}
}

string mutateSequence(const string& referenceSequence, uint maxMutRate=0, vector <double> ratioMutation={0.06,0.73,0.21}){
//~ string mutateSequence(const string& referenceSequence, uint maxMutRate=3, vector <double> ratioMutation={0.06,0.73,0.21}){
	string result;
	result.reserve(5 * referenceSequence.size());
	for(uint i(0); i < referenceSequence.size(); ++i){
		uint mutRate(maxMutRate);
		//~ uint mutRate(rand() % maxMutRate);
		double substitutionRate(mutRate * ratioMutation[0]);
		double insertionRate(mutRate * ratioMutation[1]);
		double deletionRate(mutRate * ratioMutation[2]);
		uint dice(rand() % 100);

		if (dice <substitutionRate ){
			//SUBSTITUTION
			char newNucleotide(randomNucleotide());
			while(newNucleotide == referenceSequence[i]){
				newNucleotide = randomNucleotide();
			}
			result.push_back(newNucleotide);
			continue;
		} else if(dice < deletionRate+substitutionRate){
			//DELETION
			uint dice2(rand() % 100);
			while (dice2 < deletionRate+substitutionRate){ // deletions larger than 1
				++i;
				dice2 = rand() % 100;
			}
			continue;
		} else if (dice < deletionRate + substitutionRate + insertionRate){
			//INSERTION
			char newNucleotide(randomNucleotide());
			result.push_back(referenceSequence[i]);
			result.push_back(newNucleotide);
			//~ --i;
			insertion(deletionRate + substitutionRate + insertionRate, result); // larger than 1 insertions

			continue;
		} else {
		//NO ERROR
			result.push_back(referenceSequence[i]);
		}

	}
	return result;
}

//~ vector<string> generateAlternativeTranscriptReferences(uint transcriptNumber=3, uint totalExonNumber=15, uint exonNumber=6, uint sizeExons=100){
vector<vector<string>> generateAlternativeTranscriptReferences(ifstream& refFile, uint referenceNumber, uint transcriptNumber=3, uint totalExonNumber=14, uint exonNumber=10, uint sizeExons=200){
	string sequence;
	vector<vector<string>> result;
	uint nbRef(0);
	uint position(0);
	string transcript;
	unordered_set<uint> selectedExons;
	while (not refFile.eof() and nbRef < referenceNumber){
        getline(refFile, sequence);
		getline(refFile, sequence);
		uint lengthExons;
		if (sequence.size()/sizeExons < totalExonNumber){
			lengthExons = sequence.size()/(totalExonNumber+1);
		} else {
			lengthExons = sizeExons;
		}
		if (lengthExons > 30){
			position = 0;
			vector<string> exonList;
			uint i(0);
			while (i < totalExonNumber and position < sequence.size()){ // creation of exons from genomic sequence
				string exon(sequence.substr(position, lengthExons));
				exonList.push_back(exon);
				position += lengthExons;
				++i;
			}
			++nbRef;
			vector<string> transcriptList;
			for(uint i(0); i < transcriptNumber; ++i){
				uint dice1(rand() % (totalExonNumber - 3));
				uint transcriptExonNumber(dice1 + 3);
				transcript = "";
				selectedExons = {};
				while(selectedExons.size() != transcriptExonNumber){
					selectedExons.insert(rand() % exonList.size());
				}
				for(uint ii(0); ii < exonList.size(); ++ii){
					if(selectedExons.count(ii) == 1){
						transcript += exonList[ii];
					}
				}
				transcriptList.push_back(transcript);
			}
			result.push_back(transcriptList);
		}
	}
	return result;
}

unordered_map<uint, uint> geneExpressionChunks(uint referencesNumber, uint numberReads){
	uint nbMidExpressed, nbHighlyExpressed;
	if (referencesNumber > 1){
		nbMidExpressed = referencesNumber * 0.6; // code 1
		nbHighlyExpressed = referencesNumber * 0.1+1; // code 0
	} else {
		nbMidExpressed = 0;
		nbHighlyExpressed = 1;
	}

	unordered_map<uint, uint> result;
	cout << "high:" << nbHighlyExpressed << " medium:" << nbMidExpressed << " low:" <<  referencesNumber - nbMidExpressed - nbHighlyExpressed << endl;
	unordered_set<uint> refs;
	for (uint i(0); i < referencesNumber; ++i){
		refs.insert(i);
	}
	uint i(0);
	for (auto j (refs.begin()); j != refs.end(), i < nbHighlyExpressed;){
			result.insert({*j, 0});
			j = refs.erase(j);
			++i;
	}
	//~ i = 0;
	for (auto j (refs.begin()); j != refs.end(), i < nbMidExpressed + nbHighlyExpressed;){
			result.insert({*j, 1});
			j = refs.erase(j);
			++i;
	}
	//~ cout << "check size " << refs.size();
	for (auto j (refs.begin()); j != refs.end(); ++j){

			result.insert({*j, 2});
	}
	return result;
}

void generateReads(uint numberReads, ifstream& inRef, uint referencesNumber=1, const string& outFileName="simulatedReads.fa", const string& outRefFileName="RefFile"){
	ofstream out(outFileName);
	ofstream outRef(outRefFileName);
	vector<vector<string>> referenceList(generateAlternativeTranscriptReferences(inRef, referencesNumber));

	int highly, regular, rare;
	if (referencesNumber >1){
		highly = numberReads*0.5;
		regular = numberReads*0.4;
		rare= numberReads - highly - regular;
	} else {
		highly = numberReads;
		regular = 0;
		rare = 0;
	}

	unordered_map<uint, uint> geneExpression(geneExpressionChunks(referencesNumber, numberReads));

	cout << "nb reads:" << numberReads << " nb rare reads:" << rare << " nb regular reads:"<< regular << " nb high reads:"<< highly << endl;

	for(uint i(0);i < referenceList.size(); ++i){
		string expr;
		switch (geneExpression[i]){
		case 0:
			expr = "highExpression";
			break;
		case 1:
			expr = "regularExpression";
			break;
		case 2:
			expr = "shallowExpression";
			break;
		}
		for(uint ii(0); ii<referenceList[i].size(); ++ii){
			outRef << ">referenceNumber:" << i << " alternativeNumber" << ii << " " <<  expr <<endl;
			outRef << referenceList[i][ii] << endl;
		}
	}

	string refRead,realRead;
	int hi(0), re(0), ra(0);
	while (hi < highly or re < regular or ra < rare){
		uint dice1(rand() % referencesNumber);
		uint dice2(rand() % (referenceList[dice1].size() ));
		int expr(geneExpression[dice1]);
		if (expr == 0 and hi < highly){
			++hi;
			string expression = "highExpression";
			refRead = referenceList[dice1][dice2];
			realRead = mutateSequence(refRead);
			out << ">referenceNumber:" << dice1 << " alternativeNumber:" << dice2  << " " << expression << endl;
			out << realRead << endl;
		}
		if (expr == 1 and re < regular){
			++re;
			string expression = "regularExpression";
			refRead = referenceList[dice1][dice2];
			realRead = mutateSequence(refRead);
			out << ">referenceNumber:" << dice1 << " alternativeNumber:" << dice2  << " " << expression << endl;
			out << realRead << endl;
		}
		if (expr == 2 and ra < rare){
			++ra;
			string expression = "lowExpression";
			refRead = referenceList[dice1][dice2];
			realRead = mutateSequence(refRead);
			out << ">referenceNumber:" << dice1 << " alternativeNumber:" << dice2  << " " << expression << endl;
			out << realRead << endl;
		}
	}
}

int main(int argc, char ** argv){
	if (argc > 1){
		string refName = argv[1];
		ifstream refFile(refName);
		srand (time(NULL));
		auto startChrono = chrono::system_clock::now();
		generateReads(100, refFile);
		auto end = chrono::system_clock::now(); auto waitedFor = end - startChrono;
		cout << "Time  in ms : " << (chrono::duration_cast<chrono::milliseconds>(waitedFor).count()) << endl;
	}
	return 0;
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2019 WandererFan <wandererfan@gmail.com>                *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   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 Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
  #include <BRep_Builder.hxx>
  #include <TopoDS_Compound.hxx>
  # include <TopoDS_Shape.hxx>
  # include <TopoDS_Edge.hxx>
  # include <TopoDS.hxx>
  # include <BRepAdaptor_Curve.hxx>
  # include <Precision.hxx>

  # include <QGraphicsScene>
  # include <QGraphicsSceneMouseEvent>
  # include <QGraphicsItem>
  # include <QPainter>
  # include <QPaintDevice>
  # include <QSvgGenerator>
  #include <QRegExp>

  # include <math.h>
#endif

#include <App/Application.h>
#include <App/Material.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Parameter.h>
#include <Base/UnitsApi.h>
#include <Gui/Command.h>

#include <Mod/Part/App/PartFeature.h>

#include <Mod/TechDraw/App/DrawRichAnno.h>
#include <Mod/TechDraw/App/DrawUtil.h>
#include <Mod/TechDraw/App/Geometry.h>

#include "Rez.h"
#include "ZVALUE.h"
#include "QGIArrow.h"
#include "ViewProviderRichAnno.h"
#include "MDIViewPage.h"
#include "DrawGuiUtil.h"
#include "QGVPage.h"
#include "QGIPrimPath.h"
#include "QGEPath.h"
#include "QGMText.h"
#include "QGIView.h"

#include "QGIRichAnno.h"

using namespace TechDraw;
using namespace TechDrawGui;

//**************************************************************
QGIRichAnno::QGIRichAnno(QGraphicsItem* myParent,
                         TechDraw::DrawRichAnno* anno)
{
    setHandlesChildEvents(false);
    setAcceptHoverEvents(false);
    setFlag(QGraphicsItem::ItemIsSelectable, false);         //we actually select & drag m_text
    setFlag(QGraphicsItem::ItemIsMovable, false);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges,true);

    if (myParent != nullptr) {
        setParentItem(myParent);
    }
    setViewFeature(anno);

    m_text = new QGMText();
    m_text->setTextInteractionFlags(Qt::NoTextInteraction);
    addToGroup(m_text);
    m_text->setZValue(ZVALUE::DIMENSION);

    setZValue(ZVALUE::DIMENSION);

    QObject::connect(
        m_text, SIGNAL(dragging()),
        this  , SLOT  (textDragging())
            );
    QObject::connect(
        m_text, SIGNAL(dragFinished()),
        this  , SLOT  (textDragFinished())
            );
    QObject::connect(
        m_text, SIGNAL(selected(bool)),
        this  , SLOT  (select(bool)));

    QObject::connect(
        m_text, SIGNAL(hover(bool)),
        this  , SLOT  (hover(bool)));
}

QVariant QGIRichAnno::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemSelectedHasChanged && scene()) {
        //There's nothing special for QGIRA to do when selection changes!
    } else if(change == ItemSceneChange && scene()) {
        // nothing special!
    }
    return QGIView::itemChange(change, value);
}

void QGIRichAnno::textDragging(void)
{
//    Base::Console().Message("QGIRA::textDragging()\n");
    //this is the long way around.  can we do it without crossing the App/Gui boundary?
    //just update graphics until drag finished.
//    auto lead( dynamic_cast<TechDraw::DrawRichAnno*>(getFeature()) );

//    if( lead == nullptr ) {
//        return;
//    }

//    double x = Rez::appX(m_text->x()),
//           y = Rez::appX(m_text->y());
//    Base::Vector3d tPos(x,-y,0.0);
//    Gui::Command::openCommand("Drag Text");
//    lead->TextPosition.setValue(tPos);
//    Gui::Command::commitCommand();
//      draw();
}

void QGIRichAnno::textDragFinished(void)
{
//    Base::Console().Message("QGIRA::textDragFinished()\n");
    auto anno( dynamic_cast<TechDraw::DrawRichAnno*>(getFeature()) );

    if( anno == nullptr ) {
        return;
    }

    double x = Rez::appX(m_text->x()),
           y = - Rez::appX(m_text->y());
    anno->X.setValue(x);
    anno->Y.setValue(y);
}

void QGIRichAnno::select(bool state)
{
    setSelected(state);
    draw();
}

void QGIRichAnno::hover(bool state)
{
    m_hasHover = state;
    draw();
}

void QGIRichAnno::updateView(bool update)
{
//    Base::Console().Message("QGIRA::updateView() - %s\n", getViewName());
    Q_UNUSED(update);
    auto annoFeat( dynamic_cast<TechDraw::DrawRichAnno*>(getViewObject()) );
    if ( annoFeat == nullptr ) {
        Base::Console().Log("QGIRA::updateView - no feature!\n");
        return;
    }

    auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(getViewObject()));
    if ( vp == nullptr ) {
        return;
    }

    draw();
}

void QGIRichAnno::drawBorder()
{
////Leaders have no border!
//    QGIView::drawBorder();   //good for debugging
}

void QGIRichAnno::draw()
{
//    Base::Console().Log("QGITL::draw() - %s\n",getFeature()->getNameInDocument());
    if (!isVisible()) {
        Base::Console().Log("QGITL::draw - not visible\n");
        return;
    }

    TechDraw::DrawRichAnno* annoFeat = getFeature();
    if((!annoFeat) ) {
        Base::Console().Log("QGITL::draw - no feature\n");
        return;
    }

    auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(getFeature()));
    if ( vp == nullptr ) {
        Base::Console().Log("QGITL::draw - no viewprovider\n");
        return;
    }

    QGIView::draw();

    setTextItem();
}

void QGIRichAnno::setTextItem()
{
//    Base::Console().Message("QGIRA::setTextItem() - %s\n",getViewName());
    TechDraw::DrawRichAnno* annoFeat = getFeature();
    auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(annoFeat));
    if ( vp == nullptr ) {
        Base::Console().Log("QGIRA::setTextItem - no ViewProvider\n");
        return;
    }
    QFont font = m_text->font();
    font.setPointSizeF(Rez::guiX(vp->Fontsize.getValue()));
    font.setFamily(QString::fromLatin1(vp->Font.getValue()));
    m_text->setFont(font);

    //convert point font sizes to (Rez,mm) font sizes
    QRegExp rxFontSize(QString::fromUtf8("font-size:([0-9]*)pt;"));
    QString inHtml = QString::fromUtf8(annoFeat->AnnoText.getValue());
    QString match;
    double mmPerPoint = 0.353;
    double sizeConvert = Rez::getRezFactor() * mmPerPoint;
    int pos = 0;
    QStringList findList;
    QStringList replList;
    while ((pos = rxFontSize.indexIn(inHtml, pos)) != -1) {
        QString found = rxFontSize.cap(0);
        findList << found;
        QString qsOldSize = rxFontSize.cap(1);

        QString repl = found;
        double newSize = qsOldSize.toDouble();
        newSize = newSize * sizeConvert;
        QString qsNewSize = QString::number(newSize, 'f', 2);
        repl.replace(qsOldSize,qsNewSize);
        replList << repl;
        pos += rxFontSize.matchedLength();
    }
    QString outHtml = inHtml;
    int iRepl = 0;
    //TODO: check list for duplicates?
    for ( ; iRepl < findList.size(); iRepl++) {
        outHtml = outHtml.replace(findList[iRepl], replList[iRepl]);
    }

    m_text->setHtml(outHtml);

    m_text->setTextWidth(Rez::guiX(annoFeat->MaxWidth.getValue()));
    m_text->showBox(annoFeat->ShowFrame.getValue());

    double scale = getScale();
    double x = Rez::guiX(annoFeat->X.getValue());
    double y = Rez::guiX(annoFeat->Y.getValue());
    Base::Vector3d textPos(x,y,0.0);
    QPointF tPos(textPos.x * scale,- textPos.y * scale);
    m_text->setPos(tPos);
}

//void QGIRichAnno::drawBorder()
//{
//////Leaders have no border!
////    QGIView::drawBorder();   //good for debugging
//}

TechDraw::DrawRichAnno* QGIRichAnno::getFeature(void)
{
    TechDraw::DrawRichAnno* result =
         static_cast<TechDraw::DrawRichAnno*>(getViewObject());
    return result;
}

QRectF QGIRichAnno::boundingRect() const
{
    QRectF rect = mapFromItem(m_text,m_text->boundingRect()).boundingRect();
    return rect.adjusted(-10.,-10.,10.,10.);
}

QPainterPath QGIRichAnno::shape() const
{
    return QGraphicsItemGroup::shape();
}

void QGIRichAnno::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
    QStyleOptionGraphicsItem myOption(*option);
    myOption.state &= ~QStyle::State_Selected;

//    painter->drawRect(boundingRect());          //good for debugging

    QGIView::paint (painter, &myOption, widget);
}

#include <Mod/TechDraw/Gui/moc_QGIRichAnno.cpp>
<commit_msg>Fix RichAnno positioning for Scale != 1<commit_after>/***************************************************************************
 *   Copyright (c) 2019 WandererFan <wandererfan@gmail.com>                *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   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 Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
  #include <BRep_Builder.hxx>
  #include <TopoDS_Compound.hxx>
  # include <TopoDS_Shape.hxx>
  # include <TopoDS_Edge.hxx>
  # include <TopoDS.hxx>
  # include <BRepAdaptor_Curve.hxx>
  # include <Precision.hxx>

  # include <QGraphicsScene>
  # include <QGraphicsSceneMouseEvent>
  # include <QGraphicsItem>
  # include <QPainter>
  # include <QPaintDevice>
  # include <QSvgGenerator>
  #include <QRegExp>

  # include <math.h>
#endif

#include <App/Application.h>
#include <App/Material.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Parameter.h>
#include <Base/UnitsApi.h>
#include <Gui/Command.h>

#include <Mod/Part/App/PartFeature.h>

#include <Mod/TechDraw/App/DrawRichAnno.h>
#include <Mod/TechDraw/App/DrawUtil.h>
#include <Mod/TechDraw/App/Geometry.h>

#include "Rez.h"
#include "ZVALUE.h"
#include "QGIArrow.h"
#include "ViewProviderRichAnno.h"
#include "MDIViewPage.h"
#include "DrawGuiUtil.h"
#include "QGVPage.h"
#include "QGIPrimPath.h"
#include "QGEPath.h"
#include "QGMText.h"
#include "QGIView.h"

#include "QGIRichAnno.h"

using namespace TechDraw;
using namespace TechDrawGui;

//**************************************************************
QGIRichAnno::QGIRichAnno(QGraphicsItem* myParent,
                         TechDraw::DrawRichAnno* anno)
{
    setHandlesChildEvents(false);
    setAcceptHoverEvents(false);
    setFlag(QGraphicsItem::ItemIsSelectable, false);         //we actually select & drag m_text
    setFlag(QGraphicsItem::ItemIsMovable, false);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges,true);

    if (myParent != nullptr) {
        setParentItem(myParent);
    }
    setViewFeature(anno);

    m_text = new QGMText();
    m_text->setTextInteractionFlags(Qt::NoTextInteraction);
    addToGroup(m_text);
    m_text->setZValue(ZVALUE::DIMENSION);

    setZValue(ZVALUE::DIMENSION);

    QObject::connect(
        m_text, SIGNAL(dragging()),
        this  , SLOT  (textDragging())
            );
    QObject::connect(
        m_text, SIGNAL(dragFinished()),
        this  , SLOT  (textDragFinished())
            );
    QObject::connect(
        m_text, SIGNAL(selected(bool)),
        this  , SLOT  (select(bool)));

    QObject::connect(
        m_text, SIGNAL(hover(bool)),
        this  , SLOT  (hover(bool)));
}

QVariant QGIRichAnno::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemSelectedHasChanged && scene()) {
        //There's nothing special for QGIRA to do when selection changes!
    } else if(change == ItemSceneChange && scene()) {
        // nothing special!
    }
    return QGIView::itemChange(change, value);
}

void QGIRichAnno::textDragging(void)
{
//    Base::Console().Message("QGIRA::textDragging()\n");
    //this is the long way around.  can we do it without crossing the App/Gui boundary?
    //just update graphics until drag finished.
//    auto lead( dynamic_cast<TechDraw::DrawRichAnno*>(getFeature()) );

//    if( lead == nullptr ) {
//        return;
//    }

//    double x = Rez::appX(m_text->x()),
//           y = Rez::appX(m_text->y());
//    Base::Vector3d tPos(x,-y,0.0);
//    Gui::Command::openCommand("Drag Text");
//    lead->TextPosition.setValue(tPos);
//    Gui::Command::commitCommand();
//      draw();
}

void QGIRichAnno::textDragFinished(void)
{
//    Base::Console().Message("QGIRA::textDragFinished()\n");
    auto anno( dynamic_cast<TechDraw::DrawRichAnno*>(getFeature()) );

    if( anno == nullptr ) {
        return;
    }

    double x = Rez::appX(m_text->x()) / getScale();
    double y = - Rez::appX(m_text->y()) / getScale();
    anno->X.setValue(x);
    anno->Y.setValue(y);
}

void QGIRichAnno::select(bool state)
{
    setSelected(state);
    draw();
}

void QGIRichAnno::hover(bool state)
{
    m_hasHover = state;
    draw();
}

void QGIRichAnno::updateView(bool update)
{
//    Base::Console().Message("QGIRA::updateView() - %s\n", getViewName());
    Q_UNUSED(update);
    auto annoFeat( dynamic_cast<TechDraw::DrawRichAnno*>(getViewObject()) );
    if ( annoFeat == nullptr ) {
        Base::Console().Log("QGIRA::updateView - no feature!\n");
        return;
    }

    auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(getViewObject()));
    if ( vp == nullptr ) {
        return;
    }

    draw();
}

void QGIRichAnno::drawBorder()
{
////Leaders have no border!
//    QGIView::drawBorder();   //good for debugging
}

void QGIRichAnno::draw()
{
//    Base::Console().Log("QGITL::draw() - %s\n",getFeature()->getNameInDocument());
    if (!isVisible()) {
        Base::Console().Log("QGITL::draw - not visible\n");
        return;
    }

    TechDraw::DrawRichAnno* annoFeat = getFeature();
    if((!annoFeat) ) {
        Base::Console().Log("QGITL::draw - no feature\n");
        return;
    }

    auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(getFeature()));
    if ( vp == nullptr ) {
        Base::Console().Log("QGITL::draw - no viewprovider\n");
        return;
    }

    QGIView::draw();

    setTextItem();
}

void QGIRichAnno::setTextItem()
{
//    Base::Console().Message("QGIRA::setTextItem() - %s\n",getViewName());
    TechDraw::DrawRichAnno* annoFeat = getFeature();
    auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(annoFeat));
    if ( vp == nullptr ) {
        Base::Console().Log("QGIRA::setTextItem - no ViewProvider\n");
        return;
    }
    QFont font = m_text->font();
    font.setPointSizeF(Rez::guiX(vp->Fontsize.getValue()));
    font.setFamily(QString::fromLatin1(vp->Font.getValue()));
    m_text->setFont(font);

    //convert point font sizes to (Rez,mm) font sizes
    QRegExp rxFontSize(QString::fromUtf8("font-size:([0-9]*)pt;"));
    QString inHtml = QString::fromUtf8(annoFeat->AnnoText.getValue());
    QString match;
    double mmPerPoint = 0.353;
    double sizeConvert = Rez::getRezFactor() * mmPerPoint;
    int pos = 0;
    QStringList findList;
    QStringList replList;
    while ((pos = rxFontSize.indexIn(inHtml, pos)) != -1) {
        QString found = rxFontSize.cap(0);
        findList << found;
        QString qsOldSize = rxFontSize.cap(1);

        QString repl = found;
        double newSize = qsOldSize.toDouble();
        newSize = newSize * sizeConvert;
        QString qsNewSize = QString::number(newSize, 'f', 2);
        repl.replace(qsOldSize,qsNewSize);
        replList << repl;
        pos += rxFontSize.matchedLength();
    }
    QString outHtml = inHtml;
    int iRepl = 0;
    //TODO: check list for duplicates?
    for ( ; iRepl < findList.size(); iRepl++) {
        outHtml = outHtml.replace(findList[iRepl], replList[iRepl]);
    }

    m_text->setHtml(outHtml);

    m_text->setTextWidth(Rez::guiX(annoFeat->MaxWidth.getValue()));
    m_text->showBox(annoFeat->ShowFrame.getValue());

    double scale = getScale();
    double x = Rez::guiX(annoFeat->X.getValue());
    double y = Rez::guiX(annoFeat->Y.getValue());
    Base::Vector3d textPos(x,y,0.0);
    QPointF tPos(textPos.x * scale,- textPos.y * scale);
    m_text->setPos(tPos);
}

//void QGIRichAnno::drawBorder()
//{
//////Leaders have no border!
////    QGIView::drawBorder();   //good for debugging
//}

TechDraw::DrawRichAnno* QGIRichAnno::getFeature(void)
{
    TechDraw::DrawRichAnno* result =
         static_cast<TechDraw::DrawRichAnno*>(getViewObject());
    return result;
}

QRectF QGIRichAnno::boundingRect() const
{
    QRectF rect = mapFromItem(m_text,m_text->boundingRect()).boundingRect();
    return rect.adjusted(-10.,-10.,10.,10.);
}

QPainterPath QGIRichAnno::shape() const
{
    return QGraphicsItemGroup::shape();
}

void QGIRichAnno::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
    QStyleOptionGraphicsItem myOption(*option);
    myOption.state &= ~QStyle::State_Selected;

//    painter->drawRect(boundingRect());          //good for debugging

    QGIView::paint (painter, &myOption, widget);
}

#include <Mod/TechDraw/Gui/moc_QGIRichAnno.cpp>
<|endoftext|>


<commit_before>#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <fstream>
#include "../MasterHeader.h"
using namespace std;

//color pallette
static SDL_Color yellow{ 255,231,76,255 };
static SDL_Color red{ 255,89,100,255 };
static SDL_Color white{ 255,255,255,255 };
static SDL_Color blue{ 53,167,255,255 };
static SDL_Color green{ 56,230,140,255 };

//helper function for setting the color
void SetDrawColor(SDL_Renderer* render, const SDL_Color& color)
{
	SDL_SetRenderDrawColor(render, color.r, color.g, color.b, color.a);
}

//temp global variables to retain state for gui elements that will be contained within a window
//e.g. sliders and toggles need to retain state
static float vertSliderValue = 0.0f;

//todo: find a way to remove TTF_Font* parameter pass to all GUI related functions that need to display text
//e.g. GUI::Label() and GUI::TextField()
bool WindowFunction(int ui_id,const SDL_Rect* relativePos,TTF_Font* font)
{
	SDL_Rect buttonRect{ relativePos->x + 100 - 75 / 2,relativePos->y + 100 - 20 / 2,75,20 };
	SDL_Color blue2{ 0,0,255,255 };
	int buttonID = __LINE__;
	if (GUI::Button(buttonID, &buttonRect, blue2, "OK", font))
	{
		printf("Window ID: %d\nButton ID: %d\n", ui_id, buttonID);
		puts("Button pressed from window");
	}

	SDL_Rect vertSliderRect{relativePos->x + 10,relativePos->y + 10,20,150 };
	int sliderID = __LINE__;
	vertSliderValue = GUI::VerticalSlider(sliderID, &vertSliderRect, vertSliderValue, SDL_Color{ 255,0,0,255 });

	//temp ~ if window doesn't have exclusive focus with the mice (i.e. the mouse is pressing on other gui elements in the window)
	//the window should not be dragged
	return GUI::ui_global_state.keyboardFocusID != ui_id;
}

static string mapName;
static string levelWidth;
static string levelHeight;
static string tileWidth;
static string tileHeight;
static bool windowToggled = false;
//prototyped-canned code temporary
bool NewMapWindow(int ui_id, const SDL_Rect* relativePos, TTF_Font* font)
{
	int fontHeight = TTF_FontHeight(font);
	int titleYOffset = 10;
	int leftMargin = 10;

	int labelID = __LINE__;
	int titleWidth, titleHeight;
	TTF_SizeText(font, "New Map", &titleWidth, &titleHeight);
	//center title label along x-axis
	SDL_Point titlePos{ relativePos->x + (relativePos->w / 2 - titleWidth / 2), relativePos->y + titleYOffset};
	GUI::Label(labelID, &titlePos, font, "New Map", white);

	//map filename field
	int yOffset = (titlePos.y - relativePos->y) + titleHeight;
	SDL_Point labelPos{ relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset };
	GUI::Label(__LINE__, &labelPos, font, "Map Filename: ", white);

	int textFieldID = __LINE__;
	int widthOffset;
	TTF_SizeText(font, "Map Filename: ", &widthOffset, NULL);
	SDL_Rect textFieldPos{ relativePos->x + widthOffset + leftMargin,labelPos.y - 2,relativePos->w * 0.5f,fontHeight + 4};
	mapName = GUI::TextField(textFieldID, &textFieldPos, mapName, white, font);

	//level dimensions field
	yOffset = textFieldPos.y - relativePos->y + titleHeight;
	int levelDimensionsFieldID = __LINE__;
	SDL_Point label2Pos{ relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset };
	GUI::Label(levelDimensionsFieldID, &label2Pos, font, "Level WxH: ", white);
	TTF_SizeText(font, "Level WxH: ", &widthOffset, NULL);
	SDL_Rect textFieldPos2{ relativePos->x + leftMargin + widthOffset,label2Pos.y - 2,relativePos->w * 0.2f,fontHeight + 4 };
	levelWidth = GUI::TextField(__LINE__, &textFieldPos2, levelWidth, white, font);
	SDL_Point label3Pos{ relativePos->x + leftMargin + textFieldPos2.w + widthOffset,textFieldPos2.y };
	GUI::Label(__LINE__, &label3Pos, font, " x ", white);
	TTF_SizeText(font, " x ", &widthOffset, NULL);
	SDL_Rect textFieldPos3{ label3Pos.x + widthOffset, textFieldPos2.y,relativePos->w * 0.2f,fontHeight + 4 };
	levelHeight = GUI::TextField(__LINE__, &textFieldPos3, levelHeight, white, font);

	//tile dimensions field
	yOffset = textFieldPos3.y - relativePos->y + titleHeight;
	SDL_Point label4Pos{ relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset };
	GUI::Label(__LINE__, &label4Pos, font, "Tile WxH: ", white);
	TTF_SizeText(font, "Tile WxH: ", &widthOffset, NULL);
	SDL_Rect textFieldPos4{ relativePos->x + leftMargin + widthOffset,label4Pos.y - 2,relativePos->w * 0.2f,fontHeight + 4 };
	tileWidth = GUI::TextField(__LINE__, &textFieldPos4, tileWidth, white, font);
	SDL_Point label5Pos{ relativePos->x + leftMargin + textFieldPos4.w + widthOffset,textFieldPos4.y };
	GUI::Label(__LINE__, &label5Pos, font, " x ", white);
	TTF_SizeText(font, " x ", &widthOffset, NULL);
	SDL_Rect textFieldPos6{ label5Pos.x + widthOffset, textFieldPos4.y,relativePos->w * 0.2f,fontHeight + 4 };
	tileHeight = GUI::TextField(__LINE__, &textFieldPos6, tileHeight, white, font);

	int buttonWidth = relativePos->w * 0.2;
	int buttonHeight = relativePos->h * 0.2;
	SDL_Rect buttonRect{ relativePos->x + relativePos->w / 2 - buttonWidth / 2,relativePos->y + relativePos->h * 0.7,buttonWidth,buttonHeight};
	if (GUI::Button(__LINE__, &buttonRect, red, "OK", font))
	{
		//temporary functionality as this can be dangerous to do since creating a file that already exists
		//in the file system overrides that file!
		puts("Close this window and save the new file created");
		windowToggled = false;

		string mainPath(SDL_GetBasePath());
		mainPath += string("resources/");
		string filePath(mainPath + mapName);
		ofstream outputFile;
		outputFile.open(filePath, ifstream::out);

		if (outputFile.good())
		{
			//write map level name
			outputFile << mapName << endl;
			//write level dimensions
			outputFile << levelWidth << " " << levelHeight << endl;
			//write tile dimensions
			outputFile << tileWidth << " " << tileHeight << endl;
			outputFile.close();
		}
		else
		{
			printf("File is bad\n");
		}
	}

	return false;
}

bool ToolbarPrototype(int ui_id, const SDL_Rect* relativePos, TTF_Font* font)
{
	int newMapID = __LINE__;
	int saveMapID = __LINE__;
	int openMapID = __LINE__;
	int loadTileSetID = __LINE__;

	//construct rects for toolbar buttons
	int buttonWidth = 800 / 4;
	int buttonHeight = relativePos->h;
	int margin = 2;
	SDL_Rect buttonRects[4];
	for (int i = 0;i < 4;++i)
	{
		buttonRects[i].w = buttonWidth;
		buttonRects[i].h = buttonHeight;
		buttonRects[i].x = (i * (buttonWidth + margin)) + relativePos->x;
		buttonRects[i].y = relativePos->y;
	}

	if (GUI::Button(newMapID, &buttonRects[0], blue, "New Map", font))
	{
		windowToggled = !windowToggled;
	}

	GUI::Button(saveMapID, &buttonRects[1], green, "Save Map", font);

	GUI::Button(openMapID, &buttonRects[2], blue, "Open Map", font);

	GUI::Button(loadTileSetID, &buttonRects[3], green, "Load Tileset", font);

	if (windowToggled)
	{
		int windowWidth = 300;
		int windowHeight = 150;
		SDL_Rect newMapRect{ 800 / 2 - windowWidth / 2,600 / 2 - windowHeight / 2,windowWidth,windowHeight };
		GUI::Window(__LINE__, &newMapRect, font, NewMapWindow);
	}

	return false;
}

int main(int argc, char* argv[])
{
	Core core;
	SDL_Renderer* render = core.getRenderer();

	string mainPath(SDL_GetBasePath());
	mainPath += string("resources/");

	//load in font
	string fontPath = mainPath + string("SourceCodePro-Black.ttf");
	int fontSize = 12;
	TTF_Font* font = TTF_OpenFont(fontPath.c_str(), fontSize);

	//load in sample tilesheet to use
	ImageStore imageStore(render);
	string imageFile("tiles-stones.png");
	string imagePath(mainPath + imageFile);
	Image* src = imageStore.Load(imageFile, imagePath);
	int frameWidth = 64, frameHeight = 64;
	SpriteSheet tileSheet(render, src, frameWidth, frameHeight);

	//positions of each panel
	SDL_Rect toolbarRect;
	toolbarRect.x = 0;
	toolbarRect.y = 0;
	toolbarRect.w = SCREEN_WIDTH;
	toolbarRect.h = 20;
	SDL_Rect levelWindowRect{ 0,20,800,600 };
	SDL_Rect sidePanelRect{ 800,20,400,600 };

	SDL_Rect tilePreviewRect{ 825,50,150,150 };
	SDL_Rect tileSetRect{ 805,250, 190, 360 };

	SDL_Rect guiWindowRect{ 100,100,200,200 };

	bool isToggled = true;
	SDL_Rect toggleBounds{ 100,50, 25,25 };

	float sliderValue2 = 0.0f;
	SDL_Rect sliderRect2{ 400,50,20,200 };

	int selectedButton = -1;
	SDL_Rect newWindowRect;
	newWindowRect.w = 800 * 0.3f;
	newWindowRect.h = 600 * 0.35f;
	newWindowRect.x = 400 - newWindowRect.w / 2;
	newWindowRect.y = 300 - newWindowRect.h / 2;

	//---------------- Game Loop ------------------//

	GUI::Init(render);
	GameLoop::InitTimer();
	bool running = true;
	while (running)
	{
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			GUI::ProcessEvent(&event);
			switch (event.type)
			{
			case SDL_QUIT:
				running = false;
				break;
			}
		}

		/* GAME LOGIC FUNCTIONS GO HERE*/

		//Task : draw a mockup of where all the panels will go on the tile map editor window

		SetDrawColor(render, blue);
		SDL_RenderFillRect(render, &toolbarRect);

		SetDrawColor(render, white);
		SDL_RenderFillRect(render, &levelWindowRect);

		SetDrawColor(render, red);
		SDL_RenderFillRect(render, &sidePanelRect);

		SetDrawColor(render, yellow);
		SDL_RenderFillRect(render, &tilePreviewRect);

		SetDrawColor(render, green);
		SDL_RenderFillRect(render, &tileSetRect);

		//GUI::Window(__LINE__, &toolbarRect, font, ToolbarPrototype);

		//toolbar temp
		vector<string> strings;
		strings.push_back("New");
		strings.push_back("Open");
		strings.push_back("Save");
		int buttonToSelect = GUI::Toolbar(__LINE__,&toolbarRect, -1, strings,font);
		if (buttonToSelect != -1)
		{
			windowToggled = true;
			selectedButton = buttonToSelect;
		}

		if (!windowToggled)
		{
			selectedButton = -1;
		}
		enum TOOLMAP_BUTTONS { NEW, OPEN, SAVE };
		switch (selectedButton)
		{
		case NEW:
			GUI::Window(__LINE__, &newWindowRect, font, NewMapWindow);
			break;
		case OPEN:
			break;
		case SAVE:
			break;
		}

		SDL_RenderPresent(render);
		SDL_SetRenderDrawColor(render, 0, 0, 0, 0);
		SDL_RenderClear(render);

		GameLoop::UpdateFPS();
		GameLoop::CapFramerate(core.getTargetDeltaTime());
		float currentTime = GameLoop::UpdateCurrentTime();
		GameLoop::DisplayFPS(core.getWindow(), 500.0f);

		GUI::SetTimeAndOldMousePos(currentTime);
	}

	TTF_CloseFont(font);
	return 0;
}<commit_msg>Incorporate GridSelector into LevelEditor Prototype<commit_after>#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <fstream>
#include "../MasterHeader.h"
using namespace std;

//initialization and shutdown of SDL
static Core core;
static SDL_Renderer* render = core.getRenderer();

//image store
static ImageStore imageStore(render);
static SpriteSheet* tileSheet = nullptr;

//color pallette
static SDL_Color yellow{ 255,231,76,255 };
static SDL_Color red{ 255,89,100,255 };
static SDL_Color white{ 255,255,255,255 };
static SDL_Color blue{ 53,167,255,255 };
static SDL_Color green{ 56,230,140,255 };

//main path for saving/loading resources
static string mainPath(SDL_GetBasePath() + string("resources/"));

//helper function for setting the color
void SetDrawColor(SDL_Renderer* render, const SDL_Color& color)
{
	SDL_SetRenderDrawColor(render, color.r, color.g, color.b, color.a);
}

//temp global variables to retain state for gui elements that will be contained within a window
//e.g. sliders and toggles need to retain state
static float vertSliderValue = 0.0f;

//todo: find a way to remove TTF_Font* parameter pass to all GUI related functions that need to display text
//e.g. GUI::Label() and GUI::TextField()
bool WindowFunction(int ui_id,const SDL_Rect* relativePos,TTF_Font* font)
{
	SDL_Rect buttonRect{ relativePos->x + 100 - 75 / 2,relativePos->y + 100 - 20 / 2,75,20 };
	SDL_Color blue2{ 0,0,255,255 };
	int buttonID = __LINE__;
	if (GUI::Button(buttonID, &buttonRect, blue2, "OK", font))
	{
		printf("Window ID: %d\nButton ID: %d\n", ui_id, buttonID);
		puts("Button pressed from window");
	}

	SDL_Rect vertSliderRect{relativePos->x + 10,relativePos->y + 10,20,150 };
	int sliderID = __LINE__;
	vertSliderValue = GUI::VerticalSlider(sliderID, &vertSliderRect, vertSliderValue, SDL_Color{ 255,0,0,255 });

	//temp ~ if window doesn't have exclusive focus with the mice (i.e. the mouse is pressing on other gui elements in the window)
	//the window should not be dragged
	return GUI::ui_global_state.keyboardFocusID != ui_id;
}

static string mapName;
static string levelWidth;
static string levelHeight;
static string tileWidth;
static string tileHeight;
static bool windowToggled = false;
//prototyped-canned code temporary
static bool NewMapWindow(int ui_id, const SDL_Rect* relativePos, TTF_Font* font)
{
	int fontHeight = TTF_FontHeight(font);
	int titleYOffset = 10;
	int leftMargin = 10;

	int labelID = __LINE__;
	int titleWidth, titleHeight;
	TTF_SizeText(font, "New Map", &titleWidth, &titleHeight);
	//center title label along x-axis
	SDL_Point titlePos{ relativePos->x + (relativePos->w / 2 - titleWidth / 2), relativePos->y + titleYOffset};
	GUI::Label(labelID, &titlePos, font, "New Map", white);

	//map filename field
	int yOffset = (titlePos.y - relativePos->y) + titleHeight;
	SDL_Point labelPos{ relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset };
	GUI::Label(__LINE__, &labelPos, font, "Map Filename: ", white);

	int textFieldID = __LINE__;
	int widthOffset;
	TTF_SizeText(font, "Map Filename: ", &widthOffset, NULL);
	SDL_Rect textFieldPos{ relativePos->x + widthOffset + leftMargin,labelPos.y - 2,relativePos->w * 0.5f,fontHeight + 4};
	mapName = GUI::TextField(textFieldID, &textFieldPos, mapName, white, font);

	//level dimensions field
	yOffset = textFieldPos.y - relativePos->y + titleHeight;
	int levelDimensionsFieldID = __LINE__;
	SDL_Point label2Pos{ relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset };
	GUI::Label(levelDimensionsFieldID, &label2Pos, font, "Level WxH: ", white);
	TTF_SizeText(font, "Level WxH: ", &widthOffset, NULL);
	SDL_Rect textFieldPos2{ relativePos->x + leftMargin + widthOffset,label2Pos.y - 2,relativePos->w * 0.2f,fontHeight + 4 };
	levelWidth = GUI::TextField(__LINE__, &textFieldPos2, levelWidth, white, font);
	SDL_Point label3Pos{ relativePos->x + leftMargin + textFieldPos2.w + widthOffset,textFieldPos2.y };
	GUI::Label(__LINE__, &label3Pos, font, " x ", white);
	TTF_SizeText(font, " x ", &widthOffset, NULL);
	SDL_Rect textFieldPos3{ label3Pos.x + widthOffset, textFieldPos2.y,relativePos->w * 0.2f,fontHeight + 4 };
	levelHeight = GUI::TextField(__LINE__, &textFieldPos3, levelHeight, white, font);

	//tile dimensions field
	yOffset = textFieldPos3.y - relativePos->y + titleHeight;
	SDL_Point label4Pos{ relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset };
	GUI::Label(__LINE__, &label4Pos, font, "Tile WxH: ", white);
	TTF_SizeText(font, "Tile WxH: ", &widthOffset, NULL);
	SDL_Rect textFieldPos4{ relativePos->x + leftMargin + widthOffset,label4Pos.y - 2,relativePos->w * 0.2f,fontHeight + 4 };
	tileWidth = GUI::TextField(__LINE__, &textFieldPos4, tileWidth, white, font);
	SDL_Point label5Pos{ relativePos->x + leftMargin + textFieldPos4.w + widthOffset,textFieldPos4.y };
	GUI::Label(__LINE__, &label5Pos, font, " x ", white);
	TTF_SizeText(font, " x ", &widthOffset, NULL);
	SDL_Rect textFieldPos6{ label5Pos.x + widthOffset, textFieldPos4.y,relativePos->w * 0.2f,fontHeight + 4 };
	tileHeight = GUI::TextField(__LINE__, &textFieldPos6, tileHeight, white, font);

	int buttonWidth = relativePos->w * 0.2;
	int buttonHeight = relativePos->h * 0.2;
	SDL_Rect buttonRect{ relativePos->x + relativePos->w / 2 - buttonWidth / 2,relativePos->y + relativePos->h * 0.7,buttonWidth,buttonHeight};
	if (GUI::Button(__LINE__, &buttonRect, red, "OK", font))
	{
		//temporary functionality as this can be dangerous to do since creating a file that already exists
		//in the file system overrides that file!
		puts("Close this window and save the new file created");
		windowToggled = false;

		string filePath(mainPath + mapName);
		ofstream outputFile;
		outputFile.open(filePath, ifstream::out);

		if (outputFile.good())
		{
			//write map level name
			outputFile << mapName << endl;
			//write level dimensions
			outputFile << levelWidth << " " << levelHeight << endl;
			//write tile dimensions
			outputFile << tileWidth << " " << tileHeight << endl;
			outputFile.close();
		}
		else
		{
			printf("File is bad\n");
		}
	}

	return false;
}

static string tileSetName;
static string sliceWidth;
static string sliceHeight;
static bool TileSetWindow(int ui_id, const SDL_Rect* relativePos, TTF_Font* font)
{
	int fontHeight = TTF_FontHeight(font);
	int titleYOffset = 10;
	int leftMargin = 10;

	int titleWidth, titleHeight;
	TTF_SizeText(font, "Load Tile Set", &titleWidth, &titleHeight);
	//center title label along x-axis
	SDL_Point titlePos{ relativePos->x + (relativePos->w / 2 - titleWidth / 2), relativePos->y + titleYOffset };
	GUI::Label(__LINE__, &titlePos, font, "Load Tile Set", white);

	int yOffset = (titlePos.y - relativePos->y) + titleHeight;
	SDL_Point labelPos{ relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset };
	GUI::Label(__LINE__, &labelPos, font, "Tile Set File: ", white);
	int widthOffset;
	TTF_SizeText(font, "Tile Set File:  ", &widthOffset, NULL);
	SDL_Rect textFieldPos{ relativePos->x + widthOffset,labelPos.y - 2,relativePos->w * 0.5f,fontHeight + 4 };
	tileSetName = GUI::TextField(__LINE__, &textFieldPos, tileSetName, white, font);

	yOffset = (labelPos.y - relativePos->y) + titleHeight;
	SDL_Point labelPos2{relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset};
	GUI::Label(__LINE__, &labelPos2, font, "Slice Width: ", white);
	TTF_SizeText(font, "Slice Width:  ", &widthOffset, NULL);
	SDL_Rect textFieldPos2{ relativePos->x + widthOffset,labelPos2.y - 2,relativePos->w * 0.25f,fontHeight + 4 };
	sliceWidth = GUI::TextField(__LINE__, &textFieldPos2, sliceWidth, white, font);

	yOffset = (labelPos2.y - relativePos->y) + titleHeight;
	SDL_Point labelPos3{ relativePos->x + leftMargin,relativePos->y + fontHeight + yOffset };
	GUI::Label(__LINE__, &labelPos3, font, "Slice Height: ", white);
	TTF_SizeText(font, "Slice Height:  ", &widthOffset, NULL);
	SDL_Rect textFieldPos3{ relativePos->x + widthOffset,labelPos3.y - 2,relativePos->w * 0.25f,fontHeight + 4 };
	sliceHeight = GUI::TextField(__LINE__, &textFieldPos3, sliceHeight, white, font);

	int buttonWidth = relativePos->w * 0.2;
	int buttonHeight = relativePos->h * 0.2;
	SDL_Rect buttonRect{ relativePos->x + relativePos->w / 2 - buttonWidth / 2,relativePos->y + relativePos->h * 0.7,buttonWidth,buttonHeight };
	if (GUI::Button(__LINE__, &buttonRect, red, "OK", font))
	{
		windowToggled = false;

		if (tileSheet != nullptr)
		{
			delete tileSheet;
			tileSheet = nullptr;
		}

		printf("Loading tileset: %s\n", tileSetName.c_str());
		string filePath(mainPath + tileSetName);
		//load tileset from file system
		Image* img_src = imageStore.Load(tileSetName, filePath);
		//create spritesheet from img_src
		int frameWidth = stoi(sliceWidth);
		int frameHeight = stoi(sliceHeight);
		tileSheet = new SpriteSheet(render, img_src, frameWidth, frameHeight);
	}
	return false;
}

int main(int argc, char* argv[])
{
	//load in font
	string fontPath = mainPath + string("SourceCodePro-Black.ttf");
	int fontSize = 12;
	TTF_Font* font = TTF_OpenFont(fontPath.c_str(), fontSize);

	//load in sample tilesheet to use
	//ImageStore imageStore(render);
	//string imageFile("tiles-stones.png");
	//string imagePath(mainPath + imageFile);
	//Image* src = imageStore.Load(imageFile, imagePath);
	//int frameWidth = 64, frameHeight = 64;
	//SpriteSheet tileSheet(render, src, frameWidth, frameHeight);

	//positions of each panel
	SDL_Rect toolbarRect;
	toolbarRect.x = 0;
	toolbarRect.y = 0;
	toolbarRect.w = SCREEN_WIDTH;
	toolbarRect.h = 20;
	SDL_Rect levelWindowRect{ 0,20,800,600 };
	SDL_Rect sidePanelRect{ 800,20,400,600 };

	SDL_Rect tilePreviewRect{ 825,50,150,150 };
	SDL_Rect tileSetRect{ 805,250, 190, 360 };

	SDL_Rect guiWindowRect{ 100,100,200,200 };

	bool isToggled = true;
	SDL_Rect toggleBounds{ 100,50, 25,25 };

	float sliderValue2 = 0.0f;
	SDL_Rect sliderRect2{ 400,50,20,200 };

	//windows
#define EDITOR_WIDTH 800
#define EDITOR_HEIGHT 600
	int selectedButton = -1;
	SDL_Rect newWindowRect;
	newWindowRect.w = EDITOR_WIDTH * 0.3f;
	newWindowRect.h = EDITOR_HEIGHT * 0.35f;
	newWindowRect.x = EDITOR_WIDTH / 2 - newWindowRect.w / 2;
	newWindowRect.y = EDITOR_HEIGHT / 2 - newWindowRect.h / 2;

	SDL_Rect tileSetWindowRect;
	tileSetWindowRect.w = EDITOR_WIDTH * 0.35f;
	tileSetWindowRect.h = EDITOR_HEIGHT * 0.35f;
	tileSetWindowRect.x = EDITOR_WIDTH / 2 - tileSetWindowRect.w / 2;
	tileSetWindowRect.y = EDITOR_HEIGHT / 2 - tileSetWindowRect.h / 2;

	//tile selector
	int selectedTileIndex = -1;

	//---------------- Game Loop ------------------//

	GUI::Init(render);
	GameLoop::InitTimer();
	bool running = true;
	while (running)
	{
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			GUI::ProcessEvent(&event);
			switch (event.type)
			{
			case SDL_QUIT:
				running = false;
				break;
			}
		}

		/* GAME LOGIC FUNCTIONS GO HERE*/

		//Task : draw a mockup of where all the panels will go on the tile map editor window
		SetDrawColor(render, blue);
		SDL_RenderFillRect(render, &toolbarRect);

		SetDrawColor(render, white);
		SDL_RenderFillRect(render, &levelWindowRect);

		SetDrawColor(render, red);
		SDL_RenderFillRect(render, &sidePanelRect);

		SetDrawColor(render, yellow);
		SDL_RenderFillRect(render, &tilePreviewRect);

		SetDrawColor(render, green);
		SDL_RenderFillRect(render, &tileSetRect);

		//toolbar temp
		vector<string> strings;
		strings.push_back("New");
		strings.push_back("Open");
		strings.push_back("Save");
		strings.push_back("Load TileSet");
		int buttonToSelect = GUI::Toolbar(__LINE__,&toolbarRect, -1, strings,font);
		if (buttonToSelect != -1)
		{
			windowToggled = true;
			selectedButton = buttonToSelect;
		}

		if (!windowToggled)
			selectedButton = -1;

		enum TOOLMAP_BUTTONS { NEW, OPEN, SAVE,LOAD_TILESET };
		switch (selectedButton)
		{
		case NEW:
			GUI::Window(__LINE__, &newWindowRect, font, NewMapWindow);
			break;
		case OPEN:
			break;
		case SAVE:
			break;
		case LOAD_TILESET:
			GUI::Window(__LINE__, &tileSetWindowRect, font, TileSetWindow);
			break;
		}

		//display tilesheet
		if (tileSheet != nullptr)
		{
			int tileIndex = GUI::GridSelector(__LINE__, &tileSetRect, tileSheet, 4);
			if (tileIndex != -1)
				selectedTileIndex = tileIndex;

			//draw tile selected preview
			if(selectedTileIndex != -1)
				SDL_RenderCopy(render, tileSheet->texture, tileSheet->GetFrame(selectedTileIndex), &tilePreviewRect);
		}
		SDL_RenderPresent(render);
		SDL_SetRenderDrawColor(render, 0, 0, 0, 0);
		SDL_RenderClear(render);

		GameLoop::UpdateFPS();
		GameLoop::CapFramerate(core.getTargetDeltaTime());
		float currentTime = GameLoop::UpdateCurrentTime();
		GameLoop::DisplayFPS(core.getWindow(), 500.0f);

		GUI::SetTimeAndOldMousePos(currentTime);
	}

	TTF_CloseFont(font);
	return 0;
}<|endoftext|>


<commit_before>#include <Grappa.hpp>
#include "MatchesDHT.hpp"
#include <Cache.hpp>
#include <AsyncParallelFor.hpp>

#include <string>
#include <fstream>
#include <vector>

DEFINE_uint64( numTuples, 32, "Number of tuples to generate" );

std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
  std::stringstream ss(s);
  std::string item;
  while(std::getline(ss, item, delim)) {
    elems.push_back(item);
  }
  return elems;
}

std::vector<std::string> split(const std::string &s, char delim) {
  std::vector<std::string> elems;
  return split(s, delim, elems);
}

#define TUPLE_LEN 3
struct Tuple {
  int64_t columns[TUPLE_LEN];
};

std::ostream& operator<<( std::ostream& o, const Tuple& t ) {
  o << "T( ";
  for (uint64_t i=0; i<TUPLE_LEN; i++) {
    o << t.columns[i] << ", ";
  }
  o << ")";
}

typedef uint64_t Column;

uint64_t identity_hash( int64_t k ) {
  return k;
}

// local portal to DHT
typedef MatchesDHT<int64_t, Tuple, identity_hash> DHT_type;
DHT_type joinTable;

// local RO copies
GlobalAddress<Tuple> local_tuples;
Column local_joinIndex1, local_joinIndex2, local_joinIndex3;

// TODO: incorporate the edge tuples generation (although only does triples)
void tuple_gen( Tuple * slot ) {
  Tuple r;
  for ( uint64_t i=0; i<TUPLE_LEN; i++ ) {
    r.columns[i] = rand()%10;
  }
  *slot = r;
}

void scanAndHash( Tuple * t ) {
  int64_t key = t->columns[local_joinIndex1];
  Tuple val = *t;

  joinTable.insert( key, val );
}

void secondJoin( GlobalAddress<Tuple> start, int64_t iters);

void firstJoin( Tuple * t ) {
  int64_t key = t->columns[local_joinIndex2];

  GlobalAddress<Tuple> results;
  size_t num_results = joinTable.lookup( key, &results );
  DVLOG(4) << "key " << *t << " finds (" << results << ", " << num_results << ")";

  // inner for loop
  async_parallel_for<Tuple, secondJoin, joinerSpawn<Tuple,secondJoin,ASYNC_PAR_FOR_DEFAULT>, ASYNC_PAR_FOR_DEFAULT >( results, num_results );

}

void printAll( GlobalAddress<Tuple> ts, size_t num ) {
  Tuple storage[num];
  Incoherent<Tuple>::RO c_ts( ts, num, storage );
  for (uint64_t i=0; i<num; i++) {
    VLOG(1) << c_ts[i];
  }
}

void secondJoin( GlobalAddress<Tuple> start, int64_t iters ) {
  Tuple tuples_s[iters];
  Incoherent<Tuple>::RO tuples(start, iters, tuples_s);
  for (int64_t i = 0; i < iters; i++) {

    int64_t key = tuples[i].columns[local_joinIndex3];

    GlobalAddress<Tuple> results;
    size_t num_results = joinTable.lookup( key, &results );

    VLOG(1) << "results key " << key << " (n=" << num_results;
    printAll( results, num_results );
  }
}

LOOP_FUNCTOR(join_f_init2, nid, ((GlobalAddress<Tuple>,tuples)) ((Column,ji1)) ((Column,ji2)) ((Column,ji3)) ) {
  local_tuples = tuples;
  local_joinIndex1 = ji1;
  local_joinIndex2 = ji2;
  local_joinIndex3 = ji3;
}

LOOP_FUNCTION(global_joiner_reset, nid) {
  global_joiner.reset();
}

LOOP_FUNCTION(global_joiner_wait, nid) {
  global_joiner.wait();
}

void join2( GlobalAddress<Tuple> tuples, Column ji1, Column ji2, Column ji3 ) {
  // initialization
  on_all_nodes( join_f_init2, tuples, ji1, ji2, ji3 );

  // scan tuples and hash join col 1
  VLOG(1) << "Scan tuples, creating index on subject";
  forall_local<Tuple, scanAndHash>( tuples, FLAGS_numTuples );

  printAll(tuples, FLAGS_numTuples);

  // tell the DHT we are done with inserts
  VLOG(1) << "DHT setting to RO";
  DHT_type::set_RO_global( &joinTable );

  // firstJoin contains unsynced nested parallel loops, so require
  // this surrounding join

  // FIXME: this synchronization is overly complicated
  { global_joiner_reset f; fork_join_custom(&f); }
  VLOG(1) << "Starting 1st join";
  forall_local<Tuple, firstJoin>( tuples, FLAGS_numTuples );
  { global_joiner_wait f; fork_join_custom(&f); }
}

void user_main( int * ignore ) {

  GlobalAddress<Tuple> tuples = Grappa_typed_malloc<Tuple>( FLAGS_numTuples );

  VLOG(1) << "Generating some data";
  //forall_local<Tuple, tuple_gen>( tuples, FLAGS_numTuples );
  std::ifstream testfile("testcase.txt");
  std::string line;
  int fin = 0;
  if (testfile.is_open()) {
    while (testfile.good() && (fin++)<FLAGS_numTuples) {
      std::getline( testfile, line );
      std::cout<< "L " << line << std::endl;
      Incoherent<Tuple>::WO lr(tuples, 1);
      std::vector<std::string> tokens = split( line, ' ' );
     std::cout<< tokens[0] << " " << tokens[1] << std::endl;
      (*lr).columns[0] = std::stoi(tokens[0]);
      (*lr).columns[1] = 0;
      (*lr).columns[2] = stoi(tokens[1]);
    }
    testfile.close();
  }

  Incoherent<Tuple>::WO r(tuples, 6);

  DHT_type::init_global_DHT( &joinTable, 64 );

  Column joinIndex1 = 0; // subject
  Column joinIndex2 = 2; // object
  Column joinIndex3 = 2; // object

  // double join case (assuming one index to build)
  join2( tuples, joinIndex1, joinIndex2, joinIndex3 );

}

/// Main() entry
int main (int argc, char** argv) {
    Grappa_init( &argc, &argv );
    Grappa_activate();

    Grappa_run_user_main( &user_main, (int*)NULL );
    CHECK( Grappa_done() == true ) << "Grappa not done before scheduler exit";
    Grappa_finish( 0 );
}

// insert conflicts use java-style arraylist, enabling memcpy for next step of join
<commit_msg>changes for join performance collection<commit_after>#include <Grappa.hpp>
#include "MatchesDHT.hpp"
#include <Cache.hpp>
#include <AsyncParallelFor.hpp>

#include <string>
#include <fstream>
#include <vector>

DEFINE_uint64( numTuples, 32, "Number of tuples to generate" );
DEFINE_string( in, "", "Input file relation" );
DEFINE_bool( print, false, "Print results" );

std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
  std::stringstream ss(s);
  std::string item;
  while(std::getline(ss, item, delim)) {
    elems.push_back(item);
  }
  return elems;
}

std::vector<std::string> split(const std::string &s, char delim) {
  std::vector<std::string> elems;
  return split(s, delim, elems);
}

#define TUPLE_LEN 2
struct Tuple {
  int64_t columns[TUPLE_LEN];
};

std::ostream& operator<<( std::ostream& o, const Tuple& t ) {
  o << "T( ";
  for (uint64_t i=0; i<TUPLE_LEN; i++) {
    o << t.columns[i] << ", ";
  }
  o << ")";
}

typedef uint64_t Column;

uint64_t identity_hash( int64_t k ) {
  return k;
}

// local portal to DHT
typedef MatchesDHT<int64_t, Tuple, identity_hash> DHT_type;
DHT_type joinTable;

// local RO copies
GlobalAddress<Tuple> local_tuples;
Column local_joinIndex1, local_joinIndex2, local_joinIndex3;

// TODO: incorporate the edge tuples generation (although only does triples)
void tuple_gen( Tuple * slot ) {
  Tuple r;
  for ( uint64_t i=0; i<TUPLE_LEN; i++ ) {
    r.columns[i] = rand()%FLAGS_numTuples;
  }
  *slot = r;
}

void scanAndHash( Tuple * t ) {
  int64_t key = t->columns[local_joinIndex1];
  Tuple val = *t;

  VLOG(2) << "insert " << key << " | " << val;
  joinTable.insert( key, val );
}

void secondJoin( GlobalAddress<Tuple> start, int64_t iters);

void firstJoin( Tuple * t ) {
  int64_t key = t->columns[local_joinIndex2];

  GlobalAddress<Tuple> results;
  size_t num_results = joinTable.lookup( key, &results );
  DVLOG(4) << "key " << *t << " finds (" << results << ", " << num_results << ")";

  // inner for loop
  async_parallel_for<Tuple, secondJoin, joinerSpawn<Tuple,secondJoin,ASYNC_PAR_FOR_DEFAULT>, ASYNC_PAR_FOR_DEFAULT >( results, num_results );

}

void printAll( GlobalAddress<Tuple> ts, size_t num ) {
  Tuple storage[num];
  Incoherent<Tuple>::RO c_ts( ts, num, storage );
  for (uint64_t i=0; i<num; i++) {
    VLOG(1) << c_ts[i];
  }
}

void secondJoin( GlobalAddress<Tuple> start, int64_t iters ) {
  Tuple tuples_s[iters];
  Incoherent<Tuple>::RO tuples(start, iters, tuples_s);
  for (int64_t i = 0; i < iters; i++) {

    int64_t key = tuples[i].columns[local_joinIndex3];

    GlobalAddress<Tuple> results;
    size_t num_results = joinTable.lookup( key, &results );

    if (FLAGS_print) {
      VLOG(1) << "results key " << key << " (n=" << num_results;
      printAll( results, num_results );
    }
  }
}

LOOP_FUNCTOR(join_f_init2, nid, ((GlobalAddress<Tuple>,tuples)) ((Column,ji1)) ((Column,ji2)) ((Column,ji3)) ) {
  local_tuples = tuples;
  local_joinIndex1 = ji1;
  local_joinIndex2 = ji2;
  local_joinIndex3 = ji3;
}

LOOP_FUNCTION(global_joiner_reset, nid) {
  global_joiner.reset();
}

LOOP_FUNCTION(global_joiner_wait, nid) {
  global_joiner.wait();
}

void join2( GlobalAddress<Tuple> tuples, Column ji1, Column ji2, Column ji3 ) {
  // initialization
  on_all_nodes( join_f_init2, tuples, ji1, ji2, ji3 );

  // scan tuples and hash join col 1
  VLOG(1) << "Scan tuples, creating index on subject";
  double start = Grappa_walltime();
  forall_local<Tuple, scanAndHash>( tuples, FLAGS_numTuples );
  double end = Grappa_walltime();
  VLOG(1) << "insertions: " << (end-start)/FLAGS_numTuples << " per sec";

#if DEBUG
  printAll(tuples, FLAGS_numTuples);
#endif

  // tell the DHT we are done with inserts
  VLOG(1) << "DHT setting to RO";
  DHT_type::set_RO_global( &joinTable );

  // firstJoin contains unsynced nested parallel loops, so require
  // this surrounding join

  // FIXME: this synchronization is overly complicated
  start = Grappa_walltime();
  { global_joiner_reset f; fork_join_custom(&f); }
  VLOG(1) << "Starting 1st join";
  forall_local<Tuple, firstJoin>( tuples, FLAGS_numTuples );
  { global_joiner_wait f; fork_join_custom(&f); }
  end = Grappa_walltime();
  VLOG(1) << "joins: " << (end-start) << " seconds";
}

void user_main( int * ignore ) {

  GlobalAddress<Tuple> tuples = Grappa_typed_malloc<Tuple>( FLAGS_numTuples );

  if ( FLAGS_in == "" ) {
    VLOG(1) << "Generating some data";
    forall_local<Tuple, tuple_gen>( tuples, FLAGS_numTuples );
  } else {
    VLOG(1) << "Reading data from " << FLAGS_in;
    std::ifstream testfile(FLAGS_in);
    std::string line;
    int fin = 0;
    if (testfile.is_open()) {
      while (testfile.good() && fin<FLAGS_numTuples) {
        std::getline( testfile, line );
        Incoherent<Tuple>::WO lr(tuples+fin, 1);
        std::vector<std::string> tokens = split( line, ' ' );
        (*lr).columns[0] = std::stoi(tokens[0]);
        (*lr).columns[1] = stoi(tokens[1]);
        fin++;
      }
      testfile.close();
    }
  }

  Incoherent<Tuple>::WO r(tuples, 6);

  DHT_type::init_global_DHT( &joinTable, 64 );

  Column joinIndex1 = 0; // subject
  Column joinIndex2 = 1; // object

  // double join case (assuming one index to build)
  join2( tuples, joinIndex1, joinIndex2, joinIndex2 );

}

/// Main() entry
int main (int argc, char** argv) {
    Grappa_init( &argc, &argv );
    Grappa_activate();

    Grappa_run_user_main( &user_main, (int*)NULL );
    CHECK( Grappa_done() == true ) << "Grappa not done before scheduler exit";
    Grappa_finish( 0 );
}

// insert conflicts use java-style arraylist, enabling memcpy for next step of join
<|endoftext|>