<commit_before>#ifndef LEPP2_SPLIT_APPROXIMATOR_H__
#define LEPP2_SPLIT_APPROXIMATOR_H__
#include "lepp2/ObjectApproximator.hpp"
#include "lepp2/models/ObjectModel.h"

#include <deque>
#include <map>

#include <pcl/common/pca.h>
#include <pcl/common/common.h>

namespace lepp {

/**
 * An ABC that represents the strategy for splitting a point cloud used by the
 * `SplitObjectApproximator`.
 *
 * Varying the `SplitStrategy` implementation allows us to change how point
 * clouds are split (or if they are split at all) without changing the logic of
 * the `SplitObjectApproximator` approximator itself.
 */
template<class PointT>
class SplitStrategy {
public:
  /**
   * A pure virtual method that concrete implementations need to define.
   *
   * :param split_depth: The current split depth, i.e. the number of times the
   *     original cloud has already been split
   * :param point_cloud: The current point cloud that should be split by the
   *    `SplitStrategy` implementation.
   * :returns: The method should return a vector of point clouds obtained by
   *      splitting the given cloud into any number of parts. If the given
   *      point cloud should not be split, an empty vector should be returned.
   *      Once the empty vector is returned, the `SplitObjectApproximator` will
   *      stop the splitting process for that branch of the split tree.
   */
  virtual std::vector<typename pcl::PointCloud<PointT>::Ptr> split(
      int split_depth,
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) = 0;
protected:
  /**
   * A helper method that does the actual split, when needed.
   * A default implementation is provided, since that is what most splitters
   * will want to use...
   */
  virtual std::vector<typename pcl::PointCloud<PointT>::Ptr> doSplit(
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
};

template<class PointT>
std::vector<typename pcl::PointCloud<PointT>::Ptr>
SplitStrategy<PointT>::doSplit(
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {
  typedef pcl::PointCloud<PointT> PointCloud;
  typedef typename pcl::PointCloud<PointT>::Ptr PointCloudPtr;
  // Compute PCA for the input cloud
  pcl::PCA<PointT> pca;
  pca.setInputCloud(point_cloud);
  Eigen::Vector3f eigenvalues = pca.getEigenValues();
  Eigen::Matrix3f eigenvectors = pca.getEigenVectors();

  Eigen::Vector3d main_pca_axis = eigenvectors.col(0).cast<double>();

  // Compute the centroid
  Eigen::Vector4d centroid;
  pcl::compute3DCentroid(*point_cloud, centroid);

  /// The plane equation
  double d = (-1) * (
      centroid[0] * main_pca_axis[0] +
      centroid[1] * main_pca_axis[1] +
      centroid[2] * main_pca_axis[2]
  );

  // Prepare the two parts.
  std::vector<PointCloudPtr> ret;
  ret.push_back(PointCloudPtr(new pcl::PointCloud<PointT>()));
  ret.push_back(PointCloudPtr(new pcl::PointCloud<PointT>()));
  PointCloud& first = *ret[0];
  PointCloud& second = *ret[1];

  // Now divide the input cloud into two clusters based on the splitting plane
  size_t const sz = point_cloud->size();
  for (size_t i = 0; i < sz; ++i) {
    // Boost the precision of the points we are dealing with to make the
    // calculation more precise.
    PointT const& original_point = (*point_cloud)[i];
    Eigen::Vector3f const vector_point = original_point.getVector3fMap();
    Eigen::Vector3d const point = vector_point.cast<double>();
    // Decide on which side of the plane the current point is and add it to the
    // appropriate partition.
    if (point.dot(main_pca_axis) + d < 0.) {
      first.push_back(original_point);
    } else {
      second.push_back(original_point);
    }
  }

  // Return the parts in a vector, as expected by the interface...
  return ret;
}

/**
 * A `SplitStrategy` implementation that initiates the split iff the depth is
 * less than the given limit.
 */
template<class PointT>
class DepthLimitSplitStrategy : public SplitStrategy<PointT> {
public:
  DepthLimitSplitStrategy(int depth_limit) : limit_(depth_limit) {}
  std::vector<typename pcl::PointCloud<PointT>::Ptr> split(
      int split_depth,
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
private:
  /**
   * The limit at which splits will stop.
   */
  int const limit_;
};

template<class PointT>
std::vector<typename pcl::PointCloud<PointT>::Ptr>
DepthLimitSplitStrategy<PointT>::split(
    int split_depth,
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {

  if (split_depth < limit_) {
    return this->doSplit(point_cloud);
  } else {
    return std::vector<typename pcl::PointCloud<PointT>::Ptr>();
  }
}

/**
 * An approximator implementation that will generate an approximation by
 * splitting the given object into multiple parts. Each part approximation is
 * generated by delegating to a wrapped `ObjectApproximator` instance, allowing
 * clients to vary the algorithm used for approximations, while keeping the
 * logic of incrementally splitting up the object.
 */
template<class PointT>
class SplitObjectApproximator : public ObjectApproximator<PointT> {
public:
  /**
   * Create a new `SplitObjectApproximator` that will approximate each part by
   * using the given approximator instance.
   */
  SplitObjectApproximator(boost::shared_ptr<ObjectApproximator<PointT> > approx)
      : approximator_(approx),
        // TODO Allow for split strategy injection
        splitter_(new DepthLimitSplitStrategy<PointT>(1)) {}
  /**
   * `ObjectApproximator` interface method.
   */
  boost::shared_ptr<CompositeModel> approximate(
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
private:
  /**
   * An `ObjectApproximator` used to generate approximations for object parts.
   */
  boost::shared_ptr<ObjectApproximator<PointT> > approximator_;
  /**
   * The strategy to be used for splitting point clouds.
   */
  boost::shared_ptr<SplitStrategy<PointT> > splitter_;
};

template<class PointT>
boost::shared_ptr<CompositeModel> SplitObjectApproximator<PointT>::approximate(
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {
  boost::shared_ptr<CompositeModel> approx(new CompositeModel);
  typedef typename pcl::PointCloud<PointT>::ConstPtr PointCloudConstPtr;
  typedef typename pcl::PointCloud<PointT>::Ptr PointCloudPtr;
  std::deque<std::pair<int, PointCloudConstPtr> > queue;
  queue.push_back(std::make_pair(0, point_cloud));

  while (!queue.empty()) {
    int const depth = queue[0].first;
    PointCloudConstPtr const current_cloud = queue[0].second;
    queue.pop_front();

    // Delegates to the wrapped approximator for each part's approximation.
    ObjectModelPtr model = approximator_->approximate(current_cloud);
    // TODO Decide whether the model fits well enough for the current cloud.
    // For now we fix the number of split iterations.
    // The approximation should be improved. Try doing it for the split clouds
    std::vector<PointCloudPtr> const splits = splitter_->split(depth, current_cloud);
    // Add each new split section into the queue as children of the current
    // node.
    if (splits.size() != 0) {
      for (size_t i = 0; i < splits.size(); ++i) {
        queue.push_back(std::make_pair(depth + 1, splits[i]));
      }
    } else {
      // Keep the approximation
      approx->addModel(model);
    }
  }

  return approx;
}

}  // namespace lepp
#endif
<commit_msg>refactor(SplitStrategy): Make split a template method<commit_after>#ifndef LEPP2_SPLIT_APPROXIMATOR_H__
#define LEPP2_SPLIT_APPROXIMATOR_H__
#include "lepp2/ObjectApproximator.hpp"
#include "lepp2/models/ObjectModel.h"

#include <deque>
#include <map>

#include <pcl/common/pca.h>
#include <pcl/common/common.h>

namespace lepp {

/**
 * An ABC that represents the strategy for splitting a point cloud used by the
 * `SplitObjectApproximator`.
 *
 * Varying the `SplitStrategy` implementation allows us to change how point
 * clouds are split (or if they are split at all) without changing the logic of
 * the `SplitObjectApproximator` approximator itself.
 */
template<class PointT>
class SplitStrategy {
public:
  /**
   * Performs the split of the given point cloud according to the particular
   * strategy.
   *
   * This method has a default implementation that is a template method, which
   * calls the protected `shouldSplit` method and calls the `doSplit` if it
   * indicated that a split should be made. Since all of the methods are
   * virtual, concrete implementations can override how the split is made or
   * keep the default implementation.
   *
   * This method can also be overridden by concrete implementations if they
   * cannot implement the logic only in terms of the `shouldSplit` and
   * `doSplit` method implementations (although that should be rare).
   *
   * :param split_depth: The current split depth, i.e. the number of times the
   *     original cloud has already been split
   * :param point_cloud: The current point cloud that should be split by the
   *    `SplitStrategy` implementation.
   * :returns: The method should return a vector of point clouds obtained by
   *      splitting the given cloud into any number of parts. If the given
   *      point cloud should not be split, an empty vector should be returned.
   *      Once the empty vector is returned, the `SplitObjectApproximator` will
   *      stop the splitting process for that branch of the split tree.
   */
  virtual std::vector<typename pcl::PointCloud<PointT>::Ptr> split(
      int split_depth,
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
protected:
  /**
   * A pure virtual method that decides whether the given point cloud should be
   * split or not.
   *
   * :param split_depth: The current split depth, i.e. the number of times the
   *     original cloud has already been split
   * :param point_cloud: The current point cloud that should be split by the
   *    `SplitStrategy` implementation.
   * :returns: A boolean indicating whether the cloud should be split or not.
   */
  virtual bool shouldSplit(
      int split_depth,
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) = 0;
  /**
   * A helper method that does the actual split, when needed.
   * A default implementation is provided, since that is what most splitters
   * will want to use...
   */
  virtual std::vector<typename pcl::PointCloud<PointT>::Ptr> doSplit(
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
};

template<class PointT>
std::vector<typename pcl::PointCloud<PointT>::Ptr> SplitStrategy<PointT>::split(
    int split_depth,
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {
  if (this->shouldSplit(split_depth, point_cloud)) {
    return this->doSplit(point_cloud);
  } else {
    return std::vector<typename pcl::PointCloud<PointT>::Ptr>();
  }
}

template<class PointT>
std::vector<typename pcl::PointCloud<PointT>::Ptr>
SplitStrategy<PointT>::doSplit(
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {
  typedef pcl::PointCloud<PointT> PointCloud;
  typedef typename pcl::PointCloud<PointT>::Ptr PointCloudPtr;
  // Compute PCA for the input cloud
  pcl::PCA<PointT> pca;
  pca.setInputCloud(point_cloud);
  Eigen::Vector3f eigenvalues = pca.getEigenValues();
  Eigen::Matrix3f eigenvectors = pca.getEigenVectors();

  Eigen::Vector3d main_pca_axis = eigenvectors.col(0).cast<double>();

  // Compute the centroid
  Eigen::Vector4d centroid;
  pcl::compute3DCentroid(*point_cloud, centroid);

  /// The plane equation
  double d = (-1) * (
      centroid[0] * main_pca_axis[0] +
      centroid[1] * main_pca_axis[1] +
      centroid[2] * main_pca_axis[2]
  );

  // Prepare the two parts.
  std::vector<PointCloudPtr> ret;
  ret.push_back(PointCloudPtr(new pcl::PointCloud<PointT>()));
  ret.push_back(PointCloudPtr(new pcl::PointCloud<PointT>()));
  PointCloud& first = *ret[0];
  PointCloud& second = *ret[1];

  // Now divide the input cloud into two clusters based on the splitting plane
  size_t const sz = point_cloud->size();
  for (size_t i = 0; i < sz; ++i) {
    // Boost the precision of the points we are dealing with to make the
    // calculation more precise.
    PointT const& original_point = (*point_cloud)[i];
    Eigen::Vector3f const vector_point = original_point.getVector3fMap();
    Eigen::Vector3d const point = vector_point.cast<double>();
    // Decide on which side of the plane the current point is and add it to the
    // appropriate partition.
    if (point.dot(main_pca_axis) + d < 0.) {
      first.push_back(original_point);
    } else {
      second.push_back(original_point);
    }
  }

  // Return the parts in a vector, as expected by the interface...
  return ret;
}

/**
 * A `SplitStrategy` implementation that initiates the split iff the depth is
 * less than the given limit.
 */
template<class PointT>
class DepthLimitSplitStrategy : public SplitStrategy<PointT> {
public:
  DepthLimitSplitStrategy(int depth_limit) : limit_(depth_limit) {}
  bool shouldSplit(
      int split_depth,
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
private:
  /**
   * The limit at which splits will stop.
   */
  int const limit_;
};

template<class PointT>
bool DepthLimitSplitStrategy<PointT>::shouldSplit(
    int split_depth,
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {
  return split_depth < limit_;
}

/**
 * An approximator implementation that will generate an approximation by
 * splitting the given object into multiple parts. Each part approximation is
 * generated by delegating to a wrapped `ObjectApproximator` instance, allowing
 * clients to vary the algorithm used for approximations, while keeping the
 * logic of incrementally splitting up the object.
 */
template<class PointT>
class SplitObjectApproximator : public ObjectApproximator<PointT> {
public:
  /**
   * Create a new `SplitObjectApproximator` that will approximate each part by
   * using the given approximator instance.
   */
  SplitObjectApproximator(boost::shared_ptr<ObjectApproximator<PointT> > approx)
      : approximator_(approx),
        // TODO Allow for split strategy injection
        splitter_(new DepthLimitSplitStrategy<PointT>(1)) {}
  /**
   * `ObjectApproximator` interface method.
   */
  boost::shared_ptr<CompositeModel> approximate(
      const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud);
private:
  /**
   * An `ObjectApproximator` used to generate approximations for object parts.
   */
  boost::shared_ptr<ObjectApproximator<PointT> > approximator_;
  /**
   * The strategy to be used for splitting point clouds.
   */
  boost::shared_ptr<SplitStrategy<PointT> > splitter_;
};

template<class PointT>
boost::shared_ptr<CompositeModel> SplitObjectApproximator<PointT>::approximate(
    const typename pcl::PointCloud<PointT>::ConstPtr& point_cloud) {
  boost::shared_ptr<CompositeModel> approx(new CompositeModel);
  typedef typename pcl::PointCloud<PointT>::ConstPtr PointCloudConstPtr;
  typedef typename pcl::PointCloud<PointT>::Ptr PointCloudPtr;
  std::deque<std::pair<int, PointCloudConstPtr> > queue;
  queue.push_back(std::make_pair(0, point_cloud));

  while (!queue.empty()) {
    int const depth = queue[0].first;
    PointCloudConstPtr const current_cloud = queue[0].second;
    queue.pop_front();

    // Delegates to the wrapped approximator for each part's approximation.
    ObjectModelPtr model = approximator_->approximate(current_cloud);
    // TODO Decide whether the model fits well enough for the current cloud.
    // For now we fix the number of split iterations.
    // The approximation should be improved. Try doing it for the split clouds
    std::vector<PointCloudPtr> const splits = splitter_->split(depth, current_cloud);
    // Add each new split section into the queue as children of the current
    // node.
    if (splits.size() != 0) {
      for (size_t i = 0; i < splits.size(); ++i) {
        queue.push_back(std::make_pair(depth + 1, splits[i]));
      }
    } else {
      // Keep the approximation
      approx->addModel(model);
    }
  }

  return approx;
}

}  // namespace lepp
#endif
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "Packet.h"

TEST(packet, parseRead)
{
    ASSERT_EQ(1, 1);
}
<commit_msg>Adding few testcases for Packet::parseRead<commit_after>#include "gtest/gtest.h"
#include "Packet.h"

TEST(packet, shouldReadPacketForOneServiceAndOnceCharacteristic)
{
  char binPkt[] = {
    0x01, 0x03, 0x01, 0x01, 0x01, //header
    0x01,  //serviceId
    0x01, 0x01 //charCount, charIds
  };

  ReadPacket* readPacket = Packet :: parseRead(binPkt);
  ASSERT_EQ(readPacket->serviceId, 0);
  ASSERT_EQ(readPacket->charCount, 1);

  char characteristicIds[] = {0x01};

  for (size_t i = 0; i < readPacket->charCount; ++i) {
    ASSERT_EQ(readPacket->characteristicIds[i], characteristicIds[i]);
  }
}

TEST(packet, shouldReadPacketForOneServiceAndTwoCharacteristic)
{
  char binPkt[] = {
    0x01, 0x03, 0x01, 0x01, 0x01, //header
    0x04,  //serviceId
    0x02, 0x02, 0x01 //charCount, charIds...
  };

  ReadPacket* readPacket = Packet :: parseRead(binPkt);
  ASSERT_EQ(readPacket->serviceId, 3);
  ASSERT_EQ(readPacket->charCount, 2);

  char characteristicIds[] = {0x02, 0x01};

  for (size_t i = 0; i < readPacket->charCount; ++i) {
    ASSERT_EQ(readPacket->characteristicIds[i], characteristicIds[i]);
  }
}
<|endoftext|>


<commit_before>#include "external_copy.h"

#include "isolate/environment.h"
#include "isolate/util.h"

#include <cstring>

using namespace v8;
using std::make_unique;
using std::unique_ptr;

namespace ivm {

/**
 * ExternalCopy implemtation
 */
unique_ptr<ExternalCopy> ExternalCopy::Copy(const Local<Value>& value) {
	unique_ptr<ExternalCopy> copy = CopyIfPrimitive(value);
	if (copy) {
		return copy;
	} else if (value->IsDate()) {
		return make_unique<ExternalCopyDate>(value);
	} else if (value->IsArrayBuffer()) {
		Local<ArrayBuffer> array_buffer(Local<ArrayBuffer>::Cast(value));
		ArrayBuffer::Contents contents(array_buffer->GetContents());
		return make_unique<ExternalCopyArrayBuffer>(contents.Data(), contents.ByteLength());
	} else if (value->IsArrayBufferView()) {
		Local<ArrayBufferView> view(Local<ArrayBufferView>::Cast(value));
		using ViewType = ExternalCopyArrayBufferView::ViewType;
		ViewType type;
		if (view->IsUint8Array()) {
			type = ViewType::Uint8;
		} else if (view->IsUint8ClampedArray()) {
			type = ViewType::Uint8Clamped;
		} else if (view->IsInt8Array()) {
			type = ViewType::Int8;
		} else if (view->IsUint16Array()) {
			type = ViewType::Uint16;
		} else if (view->IsInt16Array()) {
			type = ViewType::Int16;
		} else if (view->IsUint32Array()) {
			type = ViewType::Uint32;
		} else if (view->IsInt32Array()) {
			type = ViewType::Int32;
		} else if (view->IsFloat32Array()) {
			type = ViewType::Float32;
		} else if (view->IsFloat64Array()) {
			type = ViewType::Float64;
		} else if (view->IsDataView()) {
			type = ViewType::DataView;
		} else {
			assert(false);
		}
		return make_unique<ExternalCopyArrayBufferView>(view, type);
	} else if (value->IsObject()) {
		Isolate* isolate = Isolate::GetCurrent();
		ValueSerializer serializer(isolate);
		Unmaybe(serializer.WriteValue(isolate->GetCurrentContext(), value));
		return make_unique<ExternalCopySerialized>(serializer.Release());
	} else {
		// ???
		assert(false);
		throw std::exception();
	}
}

unique_ptr<ExternalCopy> ExternalCopy::CopyIfPrimitive(const Local<Value>& value) {
	if (value->IsBoolean()) {
		return make_unique<ExternalCopyTemplate<Boolean, bool>>(value);
	} else if (value->IsNumber()) {
		if (value->IsUint32()) {
			return make_unique<ExternalCopyTemplate<Uint32, uint32_t>>(value);
		} else if (value->IsInt32()) {
			return make_unique<ExternalCopyTemplate<Int32, int32_t>>(value);
		} else {
			// This handles Infinity, -Infinity, NaN
			return make_unique<ExternalCopyTemplate<Number, double>>(value);
		}
	} else if (value->IsString()) {
		return make_unique<ExternalCopyString>(value);
	} else if (value->IsNull()) {
		return make_unique<ExternalCopyNull>();
	} else if (value->IsUndefined() || value->IsSymbol()) {
		return make_unique<ExternalCopyUndefined>();
	} else {
		return nullptr;
	}
}

unique_ptr<ExternalCopy> ExternalCopy::CopyIfPrimitiveOrError(const Local<Value>& value) {
	if (value->IsObject()) {

		// Detect which subclass of Error was thrown (no better way to do this??)
		Local<Object> object(Local<Object>::Cast(value));
		std::string name(*String::Utf8Value(object->GetConstructorName()));
		ExternalCopyError::ErrorType error_type = (ExternalCopyError::ErrorType)0;
		if (name == "RangeError") {
			error_type = ExternalCopyError::ErrorType::RangeError;
		} else if (name == "ReferenceError") {
			error_type = ExternalCopyError::ErrorType::ReferenceError;
		} else if (name == "SyntaxError") {
			error_type = ExternalCopyError::ErrorType::SyntaxError;
		} else if (name == "TypeError") {
			error_type = ExternalCopyError::ErrorType::TypeError;
		} else if (name == "Error") {
			error_type = ExternalCopyError::ErrorType::Error;
		}

		// If we matched one of the Error constructors will copy this object
		if (error_type != (ExternalCopyError::ErrorType)0) {

			// Get `message`
			TryCatch try_catch(Isolate::GetCurrent());
			Local<Value> message(object->Get(v8_symbol("message")));
			unique_ptr<ExternalCopyString> message_copy;
			if (try_catch.HasCaught()) {
				try_catch.Reset();
			} else if (message->IsString()) {
				message_copy = make_unique<ExternalCopyString>(message);
			} else {
				message_copy = make_unique<ExternalCopyString>(v8_string(""));
			}

			// Get `stack`
			Local<Value> stack(object->Get(v8_symbol("stack")));
			unique_ptr<ExternalCopyString> stack_copy;
			if (try_catch.HasCaught()) {
				// printf("try_catch: %s<<\n", *String::Utf8Value(try_catch.Message()->Get()));
				try_catch.Reset();
			} else if (stack->IsString()) {
				stack_copy = make_unique<ExternalCopyString>(stack);
			}

			return make_unique<ExternalCopyError>(error_type, std::move(message_copy), std::move(stack_copy));
		}
	}
	return CopyIfPrimitive(value);
}

Local<Value> ExternalCopy::CopyIntoCheckHeap() {
	IsolateEnvironment::HeapCheck heap_check(*IsolateEnvironment::GetCurrent(), WorstCaseHeapSize());
	auto value = CopyInto();
	heap_check.Epilogue();
	return value;
}

Local<Value> ExternalCopy::TransferIn() {
	return CopyIntoCheckHeap();
}

/**
 * ExternalCopySerialized implemtation
 */
ExternalCopySerialized::ExternalCopySerialized(std::pair<uint8_t*, size_t> val) : buffer(val.first, std::free), size(val.second) {}

Local<Value> ExternalCopySerialized::CopyInto() const {
	Isolate* isolate = Isolate::GetCurrent();
	ValueDeserializer deserializer(isolate, buffer.get(), size);
	return Unmaybe(deserializer.ReadValue(isolate->GetCurrentContext()));
}

size_t ExternalCopySerialized::Size() const {
	return size;
}

uint32_t ExternalCopySerialized::WorstCaseHeapSize() const {
	// The worst I could come up with was an array of strings each with length 2.
	return size * 6;
}

/**
 * ExternalCopyError implemtation
 */
ExternalCopyError::ExternalCopyError(
	ErrorType error_type,
	unique_ptr<ExternalCopyString> message,
	unique_ptr<ExternalCopyString> stack)
	: error_type(error_type),
	message(std::move(message)),
	stack(std::move(stack)) {}

ExternalCopyError::ExternalCopyError(ErrorType error_type, const std::string& message) : error_type(error_type), message(make_unique<ExternalCopyString>(message)) {}

Local<Value> ExternalCopyError::CopyInto() const {

	// First make the exception w/ correct + message
	Local<String> message(Local<String>::Cast(this->message->CopyInto()));
	Local<Value> handle;
	switch (error_type) {
		case ErrorType::RangeError:
			handle = Exception::RangeError(message);
			break;
		case ErrorType::ReferenceError:
			handle = Exception::ReferenceError(message);
			break;
		case ErrorType::SyntaxError:
			handle = Exception::SyntaxError(message);
			break;
		case ErrorType::TypeError:
			handle = Exception::TypeError(message);
			break;
		case ErrorType::Error:
			handle = Exception::Error(message);
			break;
	}

	// Now add stack information
	if (this->stack) {
		Local<String> stack(Local<String>::Cast(this->stack->CopyInto()));
		Local<Object>::Cast(handle)->Set(v8_symbol("stack"), stack);
	}
	return handle;
}

size_t ExternalCopyError::Size() const {
	return
		(message ? message->Size() : 0) +
		(stack ? stack->Size() : 0);
}

uint32_t ExternalCopyError::WorstCaseHeapSize() const {
	return 128 + (message ? message->WorstCaseHeapSize() : 0) + (stack ? stack->WorstCaseHeapSize() : 0);
}

/**
 * ExternalCopyNull and ExternalCopyUndefined implemtations
 */
Local<Value> ExternalCopyNull::CopyInto() const {
	return Null(Isolate::GetCurrent());
}

size_t ExternalCopyNull::Size() const {
	return 0;
}

uint32_t ExternalCopyNull::WorstCaseHeapSize() const {
	return 16;
}

Local<Value> ExternalCopyUndefined::CopyInto() const {
	return Undefined(Isolate::GetCurrent());
}

size_t ExternalCopyUndefined::Size() const {
	return 0;
}

uint32_t ExternalCopyUndefined::WorstCaseHeapSize() const {
	return 16;
}

/**
 * ExternalCopyDate implemtation
 */
ExternalCopyDate::ExternalCopyDate(const Local<Value>& value) : value(Local<Date>::Cast(value)->ValueOf()) {}

Local<Value> ExternalCopyDate::CopyInto() const {
	return Date::New(Isolate::GetCurrent(), value);
}

size_t ExternalCopyDate::Size() const {
	return sizeof(double);
}

uint32_t ExternalCopyDate::WorstCaseHeapSize() const {
	// Seems pretty excessive, but that's what I observed
	return 140;
}

/**
 * ExternalCopyArrayBuffer implemtation
 */
ExternalCopyArrayBuffer::ExternalCopyArrayBuffer(const void* data, size_t length) : value(malloc(length), std::free), length(length) {
	std::memcpy(value.get(), data, length);
}

ExternalCopyArrayBuffer::ExternalCopyArrayBuffer(const Local<ArrayBufferView>& handle) : value(malloc(handle->ByteLength()), std::free), length(handle->ByteLength()) {
	if (handle->CopyContents(value.get(), length) != length) {
		throw js_generic_error("Failed to copy array contents");
	}
}

Local<Value> ExternalCopyArrayBuffer::CopyInto() const {
	Local<ArrayBuffer> array_buffer(ArrayBuffer::New(Isolate::GetCurrent(), length));
	std::memcpy(array_buffer->GetContents().Data(), value.get(), length);
	return array_buffer;
}

size_t ExternalCopyArrayBuffer::Size() const {
	return length;
}

uint32_t ExternalCopyArrayBuffer::WorstCaseHeapSize() const {
	// ArrayBuffers use system heap, not the flimsy v8 heap
	return 96;
}

const void* ExternalCopyArrayBuffer::Data() const {
	return value.get();
}

size_t ExternalCopyArrayBuffer::Length() const {
	return length;
}

/**
 * ExternalCopyArrayBufferView implemtation
 */
ExternalCopyArrayBufferView::ExternalCopyArrayBufferView(const Local<ArrayBufferView>& handle, ViewType type) : buffer(handle), type(type) {}

Local<Value> ExternalCopyArrayBufferView::CopyInto() const {
	Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(this->buffer.CopyInto());
	size_t length = buffer->ByteLength();
	switch (type) {
		case ViewType::Uint8:
			return Uint8Array::New(buffer, 0, length);
		case ViewType::Uint8Clamped:
			return Uint8ClampedArray::New(buffer, 0, length);
		case ViewType::Int8:
			return Int8Array::New(buffer, 0, length);
		case ViewType::Uint16:
			return Uint16Array::New(buffer, 0, length);
		case ViewType::Int16:
			return Int16Array::New(buffer, 0, length);
		case ViewType::Uint32:
			return Uint32Array::New(buffer, 0, length);
		case ViewType::Int32:
			return Int32Array::New(buffer, 0, length);
		case ViewType::Float32:
			return Float32Array::New(buffer, 0, length);
		case ViewType::Float64:
			return Float64Array::New(buffer, 0, length);
		case ViewType::DataView:
			return DataView::New(buffer, 0, length);
		default:
			throw std::exception();
	}
}

size_t ExternalCopyArrayBufferView::Size() const {
	return buffer.Size();
}

uint32_t ExternalCopyArrayBufferView::WorstCaseHeapSize() const {
	// This includes the overhead of the ArrayBuffer
	return 208;
}

} // namespace ivm
<commit_msg>Annoying comment typo<commit_after>#include "external_copy.h"

#include "isolate/environment.h"
#include "isolate/util.h"

#include <cstring>

using namespace v8;
using std::make_unique;
using std::unique_ptr;

namespace ivm {

/**
 * ExternalCopy implementation
 */
unique_ptr<ExternalCopy> ExternalCopy::Copy(const Local<Value>& value) {
	unique_ptr<ExternalCopy> copy = CopyIfPrimitive(value);
	if (copy) {
		return copy;
	} else if (value->IsDate()) {
		return make_unique<ExternalCopyDate>(value);
	} else if (value->IsArrayBuffer()) {
		Local<ArrayBuffer> array_buffer(Local<ArrayBuffer>::Cast(value));
		ArrayBuffer::Contents contents(array_buffer->GetContents());
		return make_unique<ExternalCopyArrayBuffer>(contents.Data(), contents.ByteLength());
	} else if (value->IsArrayBufferView()) {
		Local<ArrayBufferView> view(Local<ArrayBufferView>::Cast(value));
		using ViewType = ExternalCopyArrayBufferView::ViewType;
		ViewType type;
		if (view->IsUint8Array()) {
			type = ViewType::Uint8;
		} else if (view->IsUint8ClampedArray()) {
			type = ViewType::Uint8Clamped;
		} else if (view->IsInt8Array()) {
			type = ViewType::Int8;
		} else if (view->IsUint16Array()) {
			type = ViewType::Uint16;
		} else if (view->IsInt16Array()) {
			type = ViewType::Int16;
		} else if (view->IsUint32Array()) {
			type = ViewType::Uint32;
		} else if (view->IsInt32Array()) {
			type = ViewType::Int32;
		} else if (view->IsFloat32Array()) {
			type = ViewType::Float32;
		} else if (view->IsFloat64Array()) {
			type = ViewType::Float64;
		} else if (view->IsDataView()) {
			type = ViewType::DataView;
		} else {
			assert(false);
		}
		return make_unique<ExternalCopyArrayBufferView>(view, type);
	} else if (value->IsObject()) {
		Isolate* isolate = Isolate::GetCurrent();
		ValueSerializer serializer(isolate);
		Unmaybe(serializer.WriteValue(isolate->GetCurrentContext(), value));
		return make_unique<ExternalCopySerialized>(serializer.Release());
	} else {
		// ???
		assert(false);
		throw std::exception();
	}
}

unique_ptr<ExternalCopy> ExternalCopy::CopyIfPrimitive(const Local<Value>& value) {
	if (value->IsBoolean()) {
		return make_unique<ExternalCopyTemplate<Boolean, bool>>(value);
	} else if (value->IsNumber()) {
		if (value->IsUint32()) {
			return make_unique<ExternalCopyTemplate<Uint32, uint32_t>>(value);
		} else if (value->IsInt32()) {
			return make_unique<ExternalCopyTemplate<Int32, int32_t>>(value);
		} else {
			// This handles Infinity, -Infinity, NaN
			return make_unique<ExternalCopyTemplate<Number, double>>(value);
		}
	} else if (value->IsString()) {
		return make_unique<ExternalCopyString>(value);
	} else if (value->IsNull()) {
		return make_unique<ExternalCopyNull>();
	} else if (value->IsUndefined() || value->IsSymbol()) {
		return make_unique<ExternalCopyUndefined>();
	} else {
		return nullptr;
	}
}

unique_ptr<ExternalCopy> ExternalCopy::CopyIfPrimitiveOrError(const Local<Value>& value) {
	if (value->IsObject()) {

		// Detect which subclass of Error was thrown (no better way to do this??)
		Local<Object> object(Local<Object>::Cast(value));
		std::string name(*String::Utf8Value(object->GetConstructorName()));
		ExternalCopyError::ErrorType error_type = (ExternalCopyError::ErrorType)0;
		if (name == "RangeError") {
			error_type = ExternalCopyError::ErrorType::RangeError;
		} else if (name == "ReferenceError") {
			error_type = ExternalCopyError::ErrorType::ReferenceError;
		} else if (name == "SyntaxError") {
			error_type = ExternalCopyError::ErrorType::SyntaxError;
		} else if (name == "TypeError") {
			error_type = ExternalCopyError::ErrorType::TypeError;
		} else if (name == "Error") {
			error_type = ExternalCopyError::ErrorType::Error;
		}

		// If we matched one of the Error constructors will copy this object
		if (error_type != (ExternalCopyError::ErrorType)0) {

			// Get `message`
			TryCatch try_catch(Isolate::GetCurrent());
			Local<Value> message(object->Get(v8_symbol("message")));
			unique_ptr<ExternalCopyString> message_copy;
			if (try_catch.HasCaught()) {
				try_catch.Reset();
			} else if (message->IsString()) {
				message_copy = make_unique<ExternalCopyString>(message);
			} else {
				message_copy = make_unique<ExternalCopyString>(v8_string(""));
			}

			// Get `stack`
			Local<Value> stack(object->Get(v8_symbol("stack")));
			unique_ptr<ExternalCopyString> stack_copy;
			if (try_catch.HasCaught()) {
				// printf("try_catch: %s<<\n", *String::Utf8Value(try_catch.Message()->Get()));
				try_catch.Reset();
			} else if (stack->IsString()) {
				stack_copy = make_unique<ExternalCopyString>(stack);
			}

			return make_unique<ExternalCopyError>(error_type, std::move(message_copy), std::move(stack_copy));
		}
	}
	return CopyIfPrimitive(value);
}

Local<Value> ExternalCopy::CopyIntoCheckHeap() {
	IsolateEnvironment::HeapCheck heap_check(*IsolateEnvironment::GetCurrent(), WorstCaseHeapSize());
	auto value = CopyInto();
	heap_check.Epilogue();
	return value;
}

Local<Value> ExternalCopy::TransferIn() {
	return CopyIntoCheckHeap();
}

/**
 * ExternalCopySerialized implementation
 */
ExternalCopySerialized::ExternalCopySerialized(std::pair<uint8_t*, size_t> val) : buffer(val.first, std::free), size(val.second) {}

Local<Value> ExternalCopySerialized::CopyInto() const {
	Isolate* isolate = Isolate::GetCurrent();
	ValueDeserializer deserializer(isolate, buffer.get(), size);
	return Unmaybe(deserializer.ReadValue(isolate->GetCurrentContext()));
}

size_t ExternalCopySerialized::Size() const {
	return size;
}

uint32_t ExternalCopySerialized::WorstCaseHeapSize() const {
	// The worst I could come up with was an array of strings each with length 2.
	return size * 6;
}

/**
 * ExternalCopyError implementation
 */
ExternalCopyError::ExternalCopyError(
	ErrorType error_type,
	unique_ptr<ExternalCopyString> message,
	unique_ptr<ExternalCopyString> stack)
	: error_type(error_type),
	message(std::move(message)),
	stack(std::move(stack)) {}

ExternalCopyError::ExternalCopyError(ErrorType error_type, const std::string& message) : error_type(error_type), message(make_unique<ExternalCopyString>(message)) {}

Local<Value> ExternalCopyError::CopyInto() const {

	// First make the exception w/ correct + message
	Local<String> message(Local<String>::Cast(this->message->CopyInto()));
	Local<Value> handle;
	switch (error_type) {
		case ErrorType::RangeError:
			handle = Exception::RangeError(message);
			break;
		case ErrorType::ReferenceError:
			handle = Exception::ReferenceError(message);
			break;
		case ErrorType::SyntaxError:
			handle = Exception::SyntaxError(message);
			break;
		case ErrorType::TypeError:
			handle = Exception::TypeError(message);
			break;
		case ErrorType::Error:
			handle = Exception::Error(message);
			break;
	}

	// Now add stack information
	if (this->stack) {
		Local<String> stack(Local<String>::Cast(this->stack->CopyInto()));
		Local<Object>::Cast(handle)->Set(v8_symbol("stack"), stack);
	}
	return handle;
}

size_t ExternalCopyError::Size() const {
	return
		(message ? message->Size() : 0) +
		(stack ? stack->Size() : 0);
}

uint32_t ExternalCopyError::WorstCaseHeapSize() const {
	return 128 + (message ? message->WorstCaseHeapSize() : 0) + (stack ? stack->WorstCaseHeapSize() : 0);
}

/**
 * ExternalCopyNull and ExternalCopyUndefined implementations
 */
Local<Value> ExternalCopyNull::CopyInto() const {
	return Null(Isolate::GetCurrent());
}

size_t ExternalCopyNull::Size() const {
	return 0;
}

uint32_t ExternalCopyNull::WorstCaseHeapSize() const {
	return 16;
}

Local<Value> ExternalCopyUndefined::CopyInto() const {
	return Undefined(Isolate::GetCurrent());
}

size_t ExternalCopyUndefined::Size() const {
	return 0;
}

uint32_t ExternalCopyUndefined::WorstCaseHeapSize() const {
	return 16;
}

/**
 * ExternalCopyDate implementation
 */
ExternalCopyDate::ExternalCopyDate(const Local<Value>& value) : value(Local<Date>::Cast(value)->ValueOf()) {}

Local<Value> ExternalCopyDate::CopyInto() const {
	return Date::New(Isolate::GetCurrent(), value);
}

size_t ExternalCopyDate::Size() const {
	return sizeof(double);
}

uint32_t ExternalCopyDate::WorstCaseHeapSize() const {
	// Seems pretty excessive, but that's what I observed
	return 140;
}

/**
 * ExternalCopyArrayBuffer implementation
 */
ExternalCopyArrayBuffer::ExternalCopyArrayBuffer(const void* data, size_t length) : value(malloc(length), std::free), length(length) {
	std::memcpy(value.get(), data, length);
}

ExternalCopyArrayBuffer::ExternalCopyArrayBuffer(const Local<ArrayBufferView>& handle) : value(malloc(handle->ByteLength()), std::free), length(handle->ByteLength()) {
	if (handle->CopyContents(value.get(), length) != length) {
		throw js_generic_error("Failed to copy array contents");
	}
}

Local<Value> ExternalCopyArrayBuffer::CopyInto() const {
	Local<ArrayBuffer> array_buffer(ArrayBuffer::New(Isolate::GetCurrent(), length));
	std::memcpy(array_buffer->GetContents().Data(), value.get(), length);
	return array_buffer;
}

size_t ExternalCopyArrayBuffer::Size() const {
	return length;
}

uint32_t ExternalCopyArrayBuffer::WorstCaseHeapSize() const {
	// ArrayBuffers use system heap, not the flimsy v8 heap
	return 96;
}

const void* ExternalCopyArrayBuffer::Data() const {
	return value.get();
}

size_t ExternalCopyArrayBuffer::Length() const {
	return length;
}

/**
 * ExternalCopyArrayBufferView implementation
 */
ExternalCopyArrayBufferView::ExternalCopyArrayBufferView(const Local<ArrayBufferView>& handle, ViewType type) : buffer(handle), type(type) {}

Local<Value> ExternalCopyArrayBufferView::CopyInto() const {
	Local<ArrayBuffer> buffer = Local<ArrayBuffer>::Cast(this->buffer.CopyInto());
	size_t length = buffer->ByteLength();
	switch (type) {
		case ViewType::Uint8:
			return Uint8Array::New(buffer, 0, length);
		case ViewType::Uint8Clamped:
			return Uint8ClampedArray::New(buffer, 0, length);
		case ViewType::Int8:
			return Int8Array::New(buffer, 0, length);
		case ViewType::Uint16:
			return Uint16Array::New(buffer, 0, length);
		case ViewType::Int16:
			return Int16Array::New(buffer, 0, length);
		case ViewType::Uint32:
			return Uint32Array::New(buffer, 0, length);
		case ViewType::Int32:
			return Int32Array::New(buffer, 0, length);
		case ViewType::Float32:
			return Float32Array::New(buffer, 0, length);
		case ViewType::Float64:
			return Float64Array::New(buffer, 0, length);
		case ViewType::DataView:
			return DataView::New(buffer, 0, length);
		default:
			throw std::exception();
	}
}

size_t ExternalCopyArrayBufferView::Size() const {
	return buffer.Size();
}

uint32_t ExternalCopyArrayBufferView::WorstCaseHeapSize() const {
	// This includes the overhead of the ArrayBuffer
	return 208;
}

} // namespace ivm
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "catch.hpp"

#include "etl/fast_vector.hpp"
#include "etl/fast_matrix.hpp"
#include "etl/dyn_vector.hpp"
#include "etl/dyn_matrix.hpp"
#include "etl/traits.hpp"

TEST_CASE( "etl_traits/fast_vector_1", "etl_traits<fast_vector>" ) {
    using type = etl::fast_vector<double, 4>;
    type test_vector(3.3);

    REQUIRE(etl::etl_traits<type>::size(test_vector) == 4);
    REQUIRE(etl::size(test_vector) == 4);
    REQUIRE(etl::etl_traits<type>::is_vector);
    REQUIRE(etl::etl_traits<type>::is_value);
    REQUIRE(etl::etl_traits<type>::is_fast);
    REQUIRE(!etl::etl_traits<type>::is_matrix);

    constexpr const auto size_1 = etl::etl_traits<type>::size();
    REQUIRE(size_1 == 4);

    constexpr const auto size_2 = etl::size(test_vector);
    REQUIRE(size_2 == 4);

    constexpr const auto size_3 = etl::etl_traits<type>::dim<0>();
    REQUIRE(size_1 == 4);
}

TEST_CASE( "etl_traits/fast_matrix_1", "etl_traits<fast_matrix>" ) {
    using type = etl::fast_matrix<double, 3, 2>;
    type test_matrix(3.3);

    REQUIRE(etl::etl_traits<type>::size(test_matrix) == 6);
    REQUIRE(etl::size(test_matrix) == 6);
    REQUIRE(etl::etl_traits<type>::rows(test_matrix) == 3);
    REQUIRE(etl::rows(test_matrix) == 3);
    REQUIRE(etl::etl_traits<type>::columns(test_matrix) == 2);
    REQUIRE(etl::columns(test_matrix) == 2);
    REQUIRE(etl::etl_traits<type>::is_matrix);
    REQUIRE(etl::etl_traits<type>::is_value);
    REQUIRE(etl::etl_traits<type>::is_fast);
    REQUIRE(!etl::etl_traits<type>::is_vector);

    constexpr const auto size_1 = etl::etl_traits<type>::size();
    constexpr const auto rows_1 = etl::etl_traits<type>::rows();
    constexpr const auto columns_1 = etl::etl_traits<type>::columns();

    REQUIRE(size_1 == 6);
    REQUIRE(rows_1 == 3);
    REQUIRE(columns_1 == 2);

    constexpr const auto size_2 = etl::size(test_matrix);
    constexpr const auto rows_2 = etl::rows(test_matrix);
    constexpr const auto columns_2 = etl::columns(test_matrix);

    REQUIRE(size_2 == 6);
    REQUIRE(rows_2 == 3);
    REQUIRE(columns_2 == 2);

    constexpr const auto rows_3 = etl::etl_traits<type>::dim<0>();
    constexpr const auto columns_3 = etl::etl_traits<type>::dim<1>();

    REQUIRE(rows_3 == 3);
    REQUIRE(columns_3 == 2);
}

TEST_CASE( "etl_traits/dyn_vector_1", "etl_traits<dyn_vector>" ) {
    using type = etl::dyn_vector<double>;
    type test_vector(4, 3.3);

    REQUIRE(etl::etl_traits<type>::size(test_vector) == 4);
    REQUIRE(etl::etl_traits<type>::dim(test_vector, 0) == 4);
    REQUIRE(etl::size(test_vector) == 4);
    REQUIRE(etl::etl_traits<type>::is_vector);
    REQUIRE(etl::etl_traits<type>::is_value);
    REQUIRE(!etl::etl_traits<type>::is_fast);
    REQUIRE(!etl::etl_traits<type>::is_matrix);
}

TEST_CASE( "etl_traits/dyn_matrix_1", "etl_traits<dyn_matrix>" ) {
    using type = etl::dyn_matrix<double>;
    type test_matrix(3, 2, 3.3);

    REQUIRE(etl::etl_traits<type>::size(test_matrix) == 6);
    REQUIRE(etl::size(test_matrix) == 6);
    REQUIRE(etl::etl_traits<type>::rows(test_matrix) == 3);
    REQUIRE(etl::rows(test_matrix) == 3);
    REQUIRE(etl::etl_traits<type>::columns(test_matrix) == 2);
    REQUIRE(etl::columns(test_matrix) == 2);
    REQUIRE(etl::etl_traits<type>::dim(test_matrix, 0) == 3);
    REQUIRE(etl::etl_traits<type>::dim(test_matrix, 1) == 2);
    REQUIRE(etl::etl_traits<type>::is_matrix);
    REQUIRE(etl::etl_traits<type>::is_value);
    REQUIRE(!etl::etl_traits<type>::is_fast);
    REQUIRE(!etl::etl_traits<type>::is_vector);
}

TEST_CASE( "etl_traits/unary_dyn_mat", "etl_traits<unary<dyn_mat>>" ) {
    using mat_type = etl::dyn_matrix<double>;
    mat_type test_matrix(3, 2, 3.3);

    using expr_type = decltype(log(test_matrix));
    expr_type expr(test_matrix);

    REQUIRE(etl::etl_traits<expr_type>::size(expr) == 6);
    REQUIRE(etl::size(expr) == 6);
    REQUIRE(etl::etl_traits<expr_type>::rows(expr) == 3);
    REQUIRE(etl::rows(expr) == 3);
    REQUIRE(etl::etl_traits<expr_type>::columns(expr) == 2);
    REQUIRE(etl::columns(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::dim(expr, 0) == 3);
    REQUIRE(etl::etl_traits<expr_type>::dim(expr, 1) == 2);
    REQUIRE(etl::etl_traits<expr_type>::is_matrix);
    REQUIRE(!etl::etl_traits<expr_type>::is_value);
    REQUIRE(!etl::etl_traits<expr_type>::is_fast);
    REQUIRE(!etl::etl_traits<expr_type>::is_vector);
}

TEST_CASE( "etl_traits/binary_dyn_mat", "etl_traits<binary<dyn_mat, dyn_mat>>" ) {
    using mat_type = etl::dyn_matrix<double>;
    mat_type test_matrix(3, 2, 3.3);

    using expr_type = decltype(test_matrix + test_matrix);
    expr_type expr(test_matrix, test_matrix);

    REQUIRE(etl::etl_traits<expr_type>::size(expr) == 6);
    REQUIRE(etl::size(expr) == 6);
    REQUIRE(etl::etl_traits<expr_type>::rows(expr) == 3);
    REQUIRE(etl::rows(expr) == 3);
    REQUIRE(etl::etl_traits<expr_type>::columns(expr) == 2);
    REQUIRE(etl::columns(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::dim(expr, 0) == 3);
    REQUIRE(etl::etl_traits<expr_type>::dim(expr, 1) == 2);
    REQUIRE(etl::etl_traits<expr_type>::is_matrix);
    REQUIRE(!etl::etl_traits<expr_type>::is_value);
    REQUIRE(!etl::etl_traits<expr_type>::is_fast);
    REQUIRE(!etl::etl_traits<expr_type>::is_vector);
}

TEST_CASE( "etl_traits/unary_fast_mat", "etl_traits<unary<fast_mat>>" ) {
    using mat_type = etl::fast_matrix<double, 3, 2>;
    mat_type test_matrix(3.3);

    using expr_type = decltype(log(test_matrix));
    expr_type expr(test_matrix);

    REQUIRE(etl::etl_traits<expr_type>::size(expr) == 6);
    REQUIRE(etl::size(expr) == 6);
    REQUIRE(etl::etl_traits<expr_type>::rows(expr) == 3);
    REQUIRE(etl::rows(expr) == 3);
    REQUIRE(etl::etl_traits<expr_type>::columns(expr) == 2);
    REQUIRE(etl::columns(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::is_matrix);
    REQUIRE(!etl::etl_traits<expr_type>::is_value);
    REQUIRE(etl::etl_traits<expr_type>::is_fast);
    REQUIRE(!etl::etl_traits<expr_type>::is_vector);

    constexpr const auto size_1 = etl::etl_traits<expr_type>::size();
    constexpr const auto rows_1 = etl::etl_traits<expr_type>::rows();
    constexpr const auto columns_1 = etl::etl_traits<expr_type>::columns();

    REQUIRE(size_1 == 6);
    REQUIRE(rows_1 == 3);
    REQUIRE(columns_1 == 2);

    constexpr const auto size_2 = etl::size(expr);
    constexpr const auto rows_2 = etl::rows(expr);
    constexpr const auto columns_2 = etl::columns(expr);

    REQUIRE(size_2 == 6);
    REQUIRE(rows_2 == 3);
    REQUIRE(columns_2 == 2);

    constexpr const auto rows_3 = etl::etl_traits<expr_type>::dim<0>();
    constexpr const auto columns_3 = etl::etl_traits<expr_type>::dim<1>();

    REQUIRE(rows_3 == 3);
    REQUIRE(columns_3 == 2);
}

TEST_CASE( "etl_traits/binary_fast_mat", "etl_traits<binary<fast_mat, fast_mat>>" ) {
    using mat_type = etl::fast_matrix<double, 3, 2>;
    mat_type test_matrix(3.3);

    using expr_type = decltype(test_matrix + test_matrix);
    expr_type expr(test_matrix, test_matrix);

    REQUIRE(etl::etl_traits<expr_type>::size(expr) == 6);
    REQUIRE(etl::size(expr) == 6);
    REQUIRE(etl::etl_traits<expr_type>::rows(expr) == 3);
    REQUIRE(etl::rows(expr) == 3);
    REQUIRE(etl::etl_traits<expr_type>::columns(expr) == 2);
    REQUIRE(etl::columns(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::is_matrix);
    REQUIRE(!etl::etl_traits<expr_type>::is_value);
    REQUIRE(etl::etl_traits<expr_type>::is_fast);
    REQUIRE(!etl::etl_traits<expr_type>::is_vector);

    constexpr const auto size_1 = etl::etl_traits<expr_type>::size();
    constexpr const auto rows_1 = etl::etl_traits<expr_type>::rows();
    constexpr const auto columns_1 = etl::etl_traits<expr_type>::columns();

    REQUIRE(size_1 == 6);
    REQUIRE(rows_1 == 3);
    REQUIRE(columns_1 == 2);

    constexpr const auto size_2 = etl::size(expr);
    constexpr const auto rows_2 = etl::rows(expr);
    constexpr const auto columns_2 = etl::columns(expr);

    REQUIRE(size_2 == 6);
    REQUIRE(rows_2 == 3);
    REQUIRE(columns_2 == 2);

    constexpr const auto rows_3 = etl::etl_traits<expr_type>::dim<0>();
    constexpr const auto columns_3 = etl::etl_traits<expr_type>::dim<1>();

    REQUIRE(rows_3 == 3);
    REQUIRE(columns_3 == 2);
}<commit_msg>Test the new traits<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "catch.hpp"

#include "etl/fast_vector.hpp"
#include "etl/fast_matrix.hpp"
#include "etl/dyn_vector.hpp"
#include "etl/dyn_matrix.hpp"
#include "etl/traits.hpp"

TEST_CASE( "etl_traits/fast_vector_1", "etl_traits<fast_vector>" ) {
    using type = etl::fast_vector<double, 4>;
    type test_vector(3.3);

    REQUIRE(etl::etl_traits<type>::size(test_vector) == 4);
    REQUIRE(etl::etl_traits<type>::dimensions(test_vector) == 1);
    REQUIRE(etl::size(test_vector) == 4);
    REQUIRE(etl::etl_traits<type>::is_vector);
    REQUIRE(etl::etl_traits<type>::is_value);
    REQUIRE(etl::etl_traits<type>::is_fast);
    REQUIRE(!etl::etl_traits<type>::is_matrix);

    constexpr const auto size_1 = etl::etl_traits<type>::size();
    REQUIRE(size_1 == 4);

    constexpr const auto size_2 = etl::size(test_vector);
    REQUIRE(size_2 == 4);

    constexpr const auto size_3 = etl::etl_traits<type>::dim<0>();
    REQUIRE(size_3 == 4);

    constexpr const auto size_4 = etl::etl_traits<type>::dimensions();
    REQUIRE(size_4 == 1);

    constexpr const auto size_5 = etl::dimensions(test_vector);
    REQUIRE(size_5 == 1);
}

TEST_CASE( "etl_traits/fast_matrix_1", "etl_traits<fast_matrix>" ) {
    using type = etl::fast_matrix<double, 3, 2>;
    type test_matrix(3.3);

    REQUIRE(etl::etl_traits<type>::size(test_matrix) == 6);
    REQUIRE(etl::size(test_matrix) == 6);
    REQUIRE(etl::etl_traits<type>::rows(test_matrix) == 3);
    REQUIRE(etl::rows(test_matrix) == 3);
    REQUIRE(etl::etl_traits<type>::columns(test_matrix) == 2);
    REQUIRE(etl::columns(test_matrix) == 2);
    REQUIRE(etl::etl_traits<type>::dimensions(test_matrix) == 2);
    REQUIRE(etl::dimensions(test_matrix) == 2);
    REQUIRE(etl::etl_traits<type>::is_matrix);
    REQUIRE(etl::etl_traits<type>::is_value);
    REQUIRE(etl::etl_traits<type>::is_fast);
    REQUIRE(!etl::etl_traits<type>::is_vector);

    constexpr const auto size_1 = etl::etl_traits<type>::size();
    constexpr const auto rows_1 = etl::etl_traits<type>::rows();
    constexpr const auto columns_1 = etl::etl_traits<type>::columns();
    constexpr const auto dim_1 = etl::etl_traits<type>::dimensions();

    REQUIRE(size_1 == 6);
    REQUIRE(rows_1 == 3);
    REQUIRE(columns_1 == 2);
    REQUIRE(dim_1 == 2);

    constexpr const auto size_2 = etl::size(test_matrix);
    constexpr const auto rows_2 = etl::rows(test_matrix);
    constexpr const auto columns_2 = etl::columns(test_matrix);
    constexpr const auto dim_2 = etl::dimensions(test_matrix);

    REQUIRE(size_2 == 6);
    REQUIRE(rows_2 == 3);
    REQUIRE(columns_2 == 2);
    REQUIRE(dim_2 == 2);

    constexpr const auto rows_3 = etl::etl_traits<type>::dim<0>();
    constexpr const auto columns_3 = etl::etl_traits<type>::dim<1>();

    REQUIRE(rows_3 == 3);
    REQUIRE(columns_3 == 2);
}

TEST_CASE( "etl_traits/dyn_vector_1", "etl_traits<dyn_vector>" ) {
    using type = etl::dyn_vector<double>;
    type test_vector(4, 3.3);

    REQUIRE(etl::etl_traits<type>::size(test_vector) == 4);
    REQUIRE(etl::size(test_vector) == 4);
    REQUIRE(etl::etl_traits<type>::dim(test_vector, 0) == 4);
    REQUIRE(etl::etl_traits<type>::dimensions(test_vector) == 1);
    REQUIRE(etl::dimensions(test_vector) == 1);
    REQUIRE(etl::etl_traits<type>::is_vector);
    REQUIRE(etl::etl_traits<type>::is_value);
    REQUIRE(!etl::etl_traits<type>::is_fast);
    REQUIRE(!etl::etl_traits<type>::is_matrix);
}

TEST_CASE( "etl_traits/dyn_matrix_1", "etl_traits<dyn_matrix>" ) {
    using type = etl::dyn_matrix<double>;
    type test_matrix(3, 2, 3.3);

    REQUIRE(etl::etl_traits<type>::size(test_matrix) == 6);
    REQUIRE(etl::size(test_matrix) == 6);
    REQUIRE(etl::etl_traits<type>::rows(test_matrix) == 3);
    REQUIRE(etl::rows(test_matrix) == 3);
    REQUIRE(etl::etl_traits<type>::columns(test_matrix) == 2);
    REQUIRE(etl::columns(test_matrix) == 2);
    REQUIRE(etl::etl_traits<type>::dimensions(test_matrix) == 2);
    REQUIRE(etl::dimensions(test_matrix) == 2);
    REQUIRE(etl::etl_traits<type>::dim(test_matrix, 0) == 3);
    REQUIRE(etl::etl_traits<type>::dim(test_matrix, 1) == 2);
    REQUIRE(etl::etl_traits<type>::is_matrix);
    REQUIRE(etl::etl_traits<type>::is_value);
    REQUIRE(!etl::etl_traits<type>::is_fast);
    REQUIRE(!etl::etl_traits<type>::is_vector);
}

TEST_CASE( "etl_traits/unary_dyn_mat", "etl_traits<unary<dyn_mat>>" ) {
    using mat_type = etl::dyn_matrix<double>;
    mat_type test_matrix(3, 2, 3.3);

    using expr_type = decltype(log(test_matrix));
    expr_type expr(test_matrix);

    REQUIRE(etl::etl_traits<expr_type>::size(expr) == 6);
    REQUIRE(etl::size(expr) == 6);
    REQUIRE(etl::etl_traits<expr_type>::rows(expr) == 3);
    REQUIRE(etl::rows(expr) == 3);
    REQUIRE(etl::etl_traits<expr_type>::columns(expr) == 2);
    REQUIRE(etl::columns(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::dim(expr, 0) == 3);
    REQUIRE(etl::etl_traits<expr_type>::dim(expr, 1) == 2);
    REQUIRE(etl::etl_traits<expr_type>::dimensions(expr) == 2);
    REQUIRE(etl::dimensions(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::is_matrix);
    REQUIRE(!etl::etl_traits<expr_type>::is_value);
    REQUIRE(!etl::etl_traits<expr_type>::is_fast);
    REQUIRE(!etl::etl_traits<expr_type>::is_vector);
}

TEST_CASE( "etl_traits/binary_dyn_mat", "etl_traits<binary<dyn_mat, dyn_mat>>" ) {
    using mat_type = etl::dyn_matrix<double>;
    mat_type test_matrix(3, 2, 3.3);

    using expr_type = decltype(test_matrix + test_matrix);
    expr_type expr(test_matrix, test_matrix);

    REQUIRE(etl::etl_traits<expr_type>::size(expr) == 6);
    REQUIRE(etl::size(expr) == 6);
    REQUIRE(etl::etl_traits<expr_type>::rows(expr) == 3);
    REQUIRE(etl::rows(expr) == 3);
    REQUIRE(etl::etl_traits<expr_type>::columns(expr) == 2);
    REQUIRE(etl::columns(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::dimensions(expr) == 2);
    REQUIRE(etl::dimensions(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::dim(expr, 0) == 3);
    REQUIRE(etl::etl_traits<expr_type>::dim(expr, 1) == 2);
    REQUIRE(etl::etl_traits<expr_type>::is_matrix);
    REQUIRE(!etl::etl_traits<expr_type>::is_value);
    REQUIRE(!etl::etl_traits<expr_type>::is_fast);
    REQUIRE(!etl::etl_traits<expr_type>::is_vector);
}

TEST_CASE( "etl_traits/unary_fast_mat", "etl_traits<unary<fast_mat>>" ) {
    using mat_type = etl::fast_matrix<double, 3, 2>;
    mat_type test_matrix(3.3);

    using expr_type = decltype(log(test_matrix));
    expr_type expr(test_matrix);

    REQUIRE(etl::etl_traits<expr_type>::size(expr) == 6);
    REQUIRE(etl::size(expr) == 6);
    REQUIRE(etl::etl_traits<expr_type>::rows(expr) == 3);
    REQUIRE(etl::rows(expr) == 3);
    REQUIRE(etl::etl_traits<expr_type>::columns(expr) == 2);
    REQUIRE(etl::columns(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::dimensions(expr) == 2);
    REQUIRE(etl::dimensions(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::is_matrix);
    REQUIRE(!etl::etl_traits<expr_type>::is_value);
    REQUIRE(etl::etl_traits<expr_type>::is_fast);
    REQUIRE(!etl::etl_traits<expr_type>::is_vector);

    constexpr const auto size_1 = etl::etl_traits<expr_type>::size();
    constexpr const auto rows_1 = etl::etl_traits<expr_type>::rows();
    constexpr const auto columns_1 = etl::etl_traits<expr_type>::columns();
    constexpr const auto dim_1 = etl::etl_traits<expr_type>::dimensions();

    REQUIRE(size_1 == 6);
    REQUIRE(rows_1 == 3);
    REQUIRE(columns_1 == 2);
    REQUIRE(dim_1 == 2);

    constexpr const auto size_2 = etl::size(expr);
    constexpr const auto rows_2 = etl::rows(expr);
    constexpr const auto columns_2 = etl::columns(expr);
    constexpr const auto dim_2 = etl::dimensions(expr);

    REQUIRE(size_2 == 6);
    REQUIRE(rows_2 == 3);
    REQUIRE(columns_2 == 2);
    REQUIRE(dim_2 == 2);

    constexpr const auto rows_3 = etl::etl_traits<expr_type>::dim<0>();
    constexpr const auto columns_3 = etl::etl_traits<expr_type>::dim<1>();

    REQUIRE(rows_3 == 3);
    REQUIRE(columns_3 == 2);
}

TEST_CASE( "etl_traits/binary_fast_mat", "etl_traits<binary<fast_mat, fast_mat>>" ) {
    using mat_type = etl::fast_matrix<double, 3, 2>;
    mat_type test_matrix(3.3);

    using expr_type = decltype(test_matrix + test_matrix);
    expr_type expr(test_matrix, test_matrix);

    REQUIRE(etl::etl_traits<expr_type>::size(expr) == 6);
    REQUIRE(etl::size(expr) == 6);
    REQUIRE(etl::etl_traits<expr_type>::rows(expr) == 3);
    REQUIRE(etl::rows(expr) == 3);
    REQUIRE(etl::etl_traits<expr_type>::columns(expr) == 2);
    REQUIRE(etl::columns(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::dimensions(expr) == 2);
    REQUIRE(etl::dimensions(expr) == 2);
    REQUIRE(etl::etl_traits<expr_type>::is_matrix);
    REQUIRE(!etl::etl_traits<expr_type>::is_value);
    REQUIRE(etl::etl_traits<expr_type>::is_fast);
    REQUIRE(!etl::etl_traits<expr_type>::is_vector);

    constexpr const auto size_1 = etl::etl_traits<expr_type>::size();
    constexpr const auto rows_1 = etl::etl_traits<expr_type>::rows();
    constexpr const auto columns_1 = etl::etl_traits<expr_type>::columns();
    constexpr const auto dim_1 = etl::etl_traits<expr_type>::dimensions();

    REQUIRE(size_1 == 6);
    REQUIRE(rows_1 == 3);
    REQUIRE(columns_1 == 2);
    REQUIRE(dim_1 == 2);

    constexpr const auto size_2 = etl::size(expr);
    constexpr const auto rows_2 = etl::rows(expr);
    constexpr const auto columns_2 = etl::columns(expr);
    constexpr const auto dim_2 = etl::dimensions(expr);

    REQUIRE(size_2 == 6);
    REQUIRE(rows_2 == 3);
    REQUIRE(columns_2 == 2);
    REQUIRE(dim_2 == 2);

    constexpr const auto rows_3 = etl::etl_traits<expr_type>::dim<0>();
    constexpr const auto columns_3 = etl::etl_traits<expr_type>::dim<1>();

    REQUIRE(rows_3 == 3);
    REQUIRE(columns_3 == 2);
}<|endoftext|>


<commit_before>#ifndef GUARD_VERIFY_HPP
#define GUARD_VERIFY_HPP

#include <numeric>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <functional>
#include <mlopen/returns.hpp>

namespace mlopen {

// Compute the value of a range
template<class R>
using range_value = typename std::decay<decltype(*std::declval<R>().begin())>::type;

template<class... Ts>
using common_type = typename std::common_type<Ts...>::type;

struct sum_fn
{
    template<class T, class U>
    auto operator()(T x, U y) const MLOPEN_RETURNS(x + y);
};
static constexpr sum_fn sum{};

struct max_fn
{
    template<class T, class U>
    auto operator()(T x, U y) const MLOPEN_RETURNS(std::max<common_type<T, U>>(x, y));
};
static constexpr max_fn max{};

struct abs_diff_fn
{
    template<class T, class U>
    auto operator()(T x, U y) const MLOPEN_RETURNS(std::fabs(x - y));
};

static constexpr abs_diff_fn abs_diff{};

template<class T, class U>
T as(T, U x)
{
    return x;
}

struct float_equal_fn
{
    template<class T>
    static bool apply(T x, T y)
    {
        return
            std::isfinite(x) and
            std::isfinite(y) and
            std::nextafter(x, std::numeric_limits<T>::lowest()) <= y and
            std::nextafter(x, std::numeric_limits<T>::max()) >= y;
    }

    template<class T, class U>
    bool operator()(T x, U y) const
    {
        return float_equal_fn::apply<common_type<T, U>>(x, y);
    }

};

static constexpr float_equal_fn float_equal{};

struct compare_mag_fn
{
    template<class T, class U>
    bool operator()(T x, U y) const
    {
        return std::fabs(x) < std::fabs(y);
    }
};
static constexpr compare_mag_fn compare_mag{};

struct square_diff_fn
{
    template<class T, class U>
    double operator()(T x, U y) const { return (x - y)*(x - y); }
};
static constexpr square_diff_fn square_diff{};

template<class R1>
auto range_distance(R1&& r1) MLOPEN_RETURNS
(std::distance(r1.begin(), r1.end()));

template<class R1>
bool range_zero(R1&& r1)
{
    return std::all_of(r1.begin(), r1.end(), [](float x) { return x == 0.0; });
}

template<class R1, class R2, class T, class Reducer, class Product>
T range_product(R1&& r1, R2&& r2, T state, Reducer r, Product p)
{
    return std::inner_product(r1.begin(), r1.end(), r2.begin(), state, r, p);
}

template<class R1, class R2, class Compare>
std::size_t mismatch_idx(R1&& r1, R2&& r2, Compare compare)
{
    auto p = std::mismatch(r1.begin(), r1.end(), r2.begin(), compare);
    return std::distance(r1.begin(), p.first);
}

template<class R1, class R2>
double max_diff(R1&& r1, R2&& r2)
{
    return range_product(r1, r2, 0.0, max, abs_diff);
}

template<class R1, class R2, class T>
std::size_t mismatch_diff(R1&& r1, R2&& r2, T diff)
{
    return mismatch_idx(r1, r2, std::bind(float_equal, diff, std::bind(abs_diff, std::placeholders::_1, std::placeholders::_2)));
}

template<class R1, class R2>
double rms_range(R1&& r1, R2&& r2)
{
    std::size_t n = range_distance(r1);
    if (n == range_distance(r2))
    {
        double square_difference = range_product(r1, r2, 0.0, sum_fn{}, square_diff);
        double mag1 = *std::max_element(r1.begin(), r1.end(), compare_mag);
        double mag2 = *std::max_element(r2.begin(), r2.end(), compare_mag);
        double mag = std::max({std::fabs(mag1), std::fabs(mag2), std::numeric_limits<double>::min()});
        return std::sqrt(square_difference) / (std::sqrt(n)*mag);
    }
    else return std::numeric_limits<range_value<R1>>::max();
}

}

#endif
<commit_msg>removed extra newline<commit_after>#ifndef GUARD_VERIFY_HPP
#define GUARD_VERIFY_HPP

#include <numeric>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <functional>
#include <mlopen/returns.hpp>

namespace mlopen {

// Compute the value of a range
template<class R>
using range_value = typename std::decay<decltype(*std::declval<R>().begin())>::type;

template<class... Ts>
using common_type = typename std::common_type<Ts...>::type;

struct sum_fn
{
    template<class T, class U>
    auto operator()(T x, U y) const MLOPEN_RETURNS(x + y);
};
static constexpr sum_fn sum{};

struct max_fn
{
    template<class T, class U>
    auto operator()(T x, U y) const MLOPEN_RETURNS(std::max<common_type<T, U>>(x, y));
};
static constexpr max_fn max{};

struct abs_diff_fn
{
    template<class T, class U>
    auto operator()(T x, U y) const MLOPEN_RETURNS(std::fabs(x - y));
};

static constexpr abs_diff_fn abs_diff{};

template<class T, class U>
T as(T, U x)
{
    return x;
}

struct float_equal_fn
{
    template<class T>
    static bool apply(T x, T y)
    {
        return
            std::isfinite(x) and
            std::isfinite(y) and
            std::nextafter(x, std::numeric_limits<T>::lowest()) <= y and
            std::nextafter(x, std::numeric_limits<T>::max()) >= y;
    }

    template<class T, class U>
    bool operator()(T x, U y) const
    {
        return float_equal_fn::apply<common_type<T, U>>(x, y);
    }

};

static constexpr float_equal_fn float_equal{};

struct compare_mag_fn
{
    template<class T, class U>
    bool operator()(T x, U y) const
    {
        return std::fabs(x) < std::fabs(y);
    }
};
static constexpr compare_mag_fn compare_mag{};

struct square_diff_fn
{
    template<class T, class U>
    double operator()(T x, U y) const { return (x - y)*(x - y); }
};
static constexpr square_diff_fn square_diff{};

template<class R1>
auto range_distance(R1&& r1) MLOPEN_RETURNS
(std::distance(r1.begin(), r1.end()));

template<class R1>
bool range_zero(R1&& r1)
{
    return std::all_of(r1.begin(), r1.end(), [](float x) { return x == 0.0; });
}

template<class R1, class R2, class T, class Reducer, class Product>
T range_product(R1&& r1, R2&& r2, T state, Reducer r, Product p)
{
    return std::inner_product(r1.begin(), r1.end(), r2.begin(), state, r, p);
}

template<class R1, class R2, class Compare>
std::size_t mismatch_idx(R1&& r1, R2&& r2, Compare compare)
{
    auto p = std::mismatch(r1.begin(), r1.end(), r2.begin(), compare);
    return std::distance(r1.begin(), p.first);
}

template<class R1, class R2>
double max_diff(R1&& r1, R2&& r2)
{
    return range_product(r1, r2, 0.0, max, abs_diff);
}

template<class R1, class R2, class T>
std::size_t mismatch_diff(R1&& r1, R2&& r2, T diff)
{
    return mismatch_idx(r1, r2, std::bind(float_equal, diff, std::bind(abs_diff, std::placeholders::_1, std::placeholders::_2)));
}

template<class R1, class R2>
double rms_range(R1&& r1, R2&& r2)
{
    std::size_t n = range_distance(r1);
    if (n == range_distance(r2))
    {
        double square_difference = range_product(r1, r2, 0.0, sum_fn{}, square_diff);
        double mag1 = *std::max_element(r1.begin(), r1.end(), compare_mag);
        double mag2 = *std::max_element(r2.begin(), r2.end(), compare_mag);
        double mag = std::max({std::fabs(mag1), std::fabs(mag2), std::numeric_limits<double>::min()});
        return std::sqrt(square_difference) / (std::sqrt(n)*mag);
    }
    else return std::numeric_limits<range_value<R1>>::max();
}

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2010 MQWeb - Franky Braem
 *
 * Licensed under the EUPL, Version 1.1 or – as soon they
 * will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the
 * Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the Licence is
 * distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the Licence for the specific language governing
 * permissions and limitations under the Licence.
 */
#include "MQ/Web/QueueController.h"
#include "MQ/Web/QueueMapper.h"
#include "MQ/Web/JSONView.h"

namespace MQ
{
namespace Web
{

QueueController::QueueController() : MQController()
{
}

QueueController::~QueueController()
{
}

void QueueController::inquire()
{
	Poco::JSON::Object::Ptr pcfParameters;

	if ( data().has("filter") && data().isObject("filter") )
	{
		pcfParameters = data().getObject("filter");
	}
	else
	{
		pcfParameters = new Poco::JSON::Object();
		set("filter", pcfParameters);

		std::vector<std::string> parameters = getParameters();
		// First parameter is queuemanager
		// Second parameter can be a queuename and will result in inquiring
		// only that queue and ignores all query parameters.
		if ( parameters.size() > 1 )
		{
			pcfParameters->set("QName", parameters[1]);
		}
		else
		{
			// Handle query parameters
			std::string queueNameField;
			if ( form().has("QName") )
			{
				queueNameField = form().get("QName");
			}
			else
			{
				queueNameField = form().get("queueName", "*");
			}
			if ( queueNameField.empty() )
			{
				queueNameField = "*";
			}
			pcfParameters->set("QName", queueNameField);
		}

		std::string queueDepthField;
		if ( form().has("CurrentQDepth") )
		{
			queueDepthField = form().get("CurrentQDepth", "");
		}
		else if ( form().has("queueDepth"))
		{
			queueDepthField = form().get("queueDepth", "");
		}
		if ( !queueDepthField.empty() )
		{
			int queueDepth = 0;
			if ( Poco::NumberParser::tryParse(queueDepthField, queueDepth) )
			{
				Poco::JSON::Object::Ptr filter = new Poco::JSON::Object();
				filter->set("Parameter", "CurrentQDepth");
				filter->set("Operator", "NLT"); //Not Less
				filter->set("FilterValue", queueDepth);
				pcfParameters->set("IntegerFilterCommand", filter);
			}
		}

		if ( form().has("queueUsage") )
		{
			pcfParameters->set("Usage", form().get("queueUsage"));
		}
		else if ( form().has("Usage") )
		{
			pcfParameters->set("Usage", form().get("Usage"));
		}

		pcfParameters->set("QType", form().get("queueType", "All"));
		pcfParameters->set("ExcludeSystem", form().get("excludeSystem", "false").compare("true") == 0);
		pcfParameters->set("ExcludeTemp", form().get("excludeTemp", "false").compare("true") == 0);

		Poco::JSON::Array::Ptr attrs = new Poco::JSON::Array();
		pcfParameters->set("QAttrs", attrs);

		for(Poco::Net::NameValueCollection::ConstIterator itAttrs = form().find("Attrs");
			itAttrs != form().end() && Poco::icompare(itAttrs->first, "Attrs") == 0;
			++itAttrs)
		{
			attrs->add(itAttrs->second);
		}
	}

	QueueMapper mapper(*commandServer());
	Poco::JSON::Array::Ptr queues = mapper.inquire(pcfParameters);
	set("queues", queues);
	setView(new JSONView());
}

} } // Namespace MQ::Web
<commit_msg>Allow QAttrs and Attrs query parameters for selecting attributes<commit_after>/*
 * Copyright 2010 MQWeb - Franky Braem
 *
 * Licensed under the EUPL, Version 1.1 or – as soon they
 * will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the
 * Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the Licence is
 * distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the Licence for the specific language governing
 * permissions and limitations under the Licence.
 */
#include "MQ/Web/QueueController.h"
#include "MQ/Web/QueueMapper.h"
#include "MQ/Web/JSONView.h"

namespace MQ
{
namespace Web
{

QueueController::QueueController() : MQController()
{
}

QueueController::~QueueController()
{
}

void QueueController::inquire()
{
	Poco::JSON::Object::Ptr pcfParameters;

	if ( data().has("filter") && data().isObject("filter") )
	{
		pcfParameters = data().getObject("filter");
	}
	else
	{
		pcfParameters = new Poco::JSON::Object();
		set("filter", pcfParameters);

		std::vector<std::string> parameters = getParameters();
		// First parameter is queuemanager
		// Second parameter can be a queuename. If this is passed, the
		// query parameter QName or queueName is ignored.
		if ( parameters.size() > 1 )
		{
			pcfParameters->set("QName", parameters[1]);
		}
		else
		{
			// Handle query parameters
			std::string queueNameField;
			if ( form().has("QName") )
			{
				queueNameField = form().get("QName");
			}
			else
			{
				queueNameField = form().get("queueName", "*");
			}
			if ( queueNameField.empty() )
			{
				queueNameField = "*";
			}
			pcfParameters->set("QName", queueNameField);
		}

		std::string queueDepthField;
		if ( form().has("CurrentQDepth") )
		{
			queueDepthField = form().get("CurrentQDepth", "");
		}
		else if ( form().has("queueDepth"))
		{
			queueDepthField = form().get("queueDepth", "");
		}
		if ( !queueDepthField.empty() )
		{
			int queueDepth = 0;
			if ( Poco::NumberParser::tryParse(queueDepthField, queueDepth) )
			{
				Poco::JSON::Object::Ptr filter = new Poco::JSON::Object();
				filter->set("Parameter", "CurrentQDepth");
				filter->set("Operator", "NLT"); //Not Less
				filter->set("FilterValue", queueDepth);
				pcfParameters->set("IntegerFilterCommand", filter);
			}
		}

		if ( form().has("queueUsage") )
		{
			pcfParameters->set("Usage", form().get("queueUsage"));
		}
		else if ( form().has("Usage") )
		{
			pcfParameters->set("Usage", form().get("Usage"));
		}

		pcfParameters->set("QType", form().get("queueType", "All"));
		pcfParameters->set("ExcludeSystem", form().get("excludeSystem", "false").compare("true") == 0);
		pcfParameters->set("ExcludeTemp", form().get("excludeTemp", "false").compare("true") == 0);

		Poco::JSON::Array::Ptr attrs = new Poco::JSON::Array();
		pcfParameters->set("QAttrs", attrs);

		Poco::Net::NameValueCollection::ConstIterator itAttrs = form().find("QAttrs");
		if ( itAttrs == form().end() )
		{
			itAttrs = form().find("Attrs");
		}

		for(;
			itAttrs != form().end() && Poco::icompare(itAttrs->first, "Attrs") == 0;
			++itAttrs)
		{
			attrs->add(itAttrs->second);
		}
	}

	QueueMapper mapper(*commandServer());
	Poco::JSON::Array::Ptr queues = mapper.inquire(pcfParameters);
	set("queues", queues);
	setView(new JSONView());
}

} } // Namespace MQ::Web
<|endoftext|>


<commit_before>/*
 * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
 * http://code.google.com/p/poly2tri/
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * * Neither the name of Poly2Tri nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without specific
 *   prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <cstdlib>
#include <GL/glfw.h>
#include <time.h>
#include <fstream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;

#include "../poly2tri/poly2tri.h"
using namespace p2t;

void Init();
void ShutDown(int return_code);
void MainLoop(const double zoom);
void Draw(const double zoom);
void DrawMap(const double zoom);
void ConstrainedColor(bool constrain);
double StringToDouble(const std::string& s);
double Random(double (*fun)(double), double xmin, double xmax);
double Fun(double x);

/// Dude hole examples
vector<Point*> CreateHeadHole();
vector<Point*> CreateChestHole();

float rotate_y = 0,
      rotate_z = 0;
const float rotations_per_tick = .2;

/// Screen center x
double cx = 0.0;
/// Screen center y
double cy = 0.0;

/// Constrained triangles
vector<Triangle*> triangles;
/// Triangle map
list<Triangle*> map;
/// Polylines
vector< vector<Point*> > polylines;

/// Draw the entire triangle map?
bool draw_map = false;
/// Create a random distribution of points?
bool random_distribution = false;

int main(int argc, char* argv[])
{

  int num_points = 0;
  double max, min;
  double zoom;

  if (argc != 5) {
    cout << "-== USAGE ==-" << endl;
    cout << "Load Data File: p2t filename center_x center_y zoom" << endl;
    cout << " Random Points: p2t random num_points width zoom" << endl;
    return 1;
  }

  if(string(argv[1]) == "random") {
    num_points = atoi(argv[2]);
    random_distribution = true;
    char* pEnd;
    max = strtod(argv[3], &pEnd);
    min = -max;
    cx = cy = 0;
    zoom = atof(argv[4]);
  } else {
    zoom = atof(argv[4]);
    cx = atof(argv[2]);
    cy = atof(argv[3]);
  }

  vector<p2t::Point*> polyline;

  if(random_distribution) {
    // Create a simple bounding box
    polyline.push_back(new Point(min,min));
    polyline.push_back(new Point(min,max));
    polyline.push_back(new Point(max,max));
    polyline.push_back(new Point(max,min));
  } else {
    // Load pointset from file

    // Parse and tokenize data file
    string line;
    ifstream myfile(argv[1]);
    if (myfile.is_open()) {
      while (!myfile.eof()) {
        getline(myfile, line);
        if (line.size() == 0) {
          break;
        }
        istringstream iss(line);
        vector<string> tokens;
        copy(istream_iterator<string>(iss), istream_iterator<string>(),
             back_inserter<vector<string> >(tokens));
        double x = StringToDouble(tokens[0]);
        double y = StringToDouble(tokens[1]);
        polyline.push_back(new Point(x, y));
        num_points++;
      }
      myfile.close();
    } else {
      cout << "File not opened" << endl;
    }
  }

  cout << "Number of constrained edges = " << polyline.size() << endl;
  polylines.push_back(polyline);

  Init();

  /*
   * Perform triangulation!
   */

  double init_time = glfwGetTime();

  /*
   * STEP 1: Create CDT and add primary polyline
   * NOTE: polyline must be a simple polygon. The polyline's points
   * constitute the polygon's constrained edges!
   */
  CDT* cdt = new CDT(polyline);

  /*
   * STEP 2: Add holes or Steiner points if necessary
   */
  string s(argv[1]);
  if(s.find("dude.dat", 0) != string::npos) {
    // Add head hole
    vector<Point*> head_hole = CreateHeadHole();
    num_points += head_hole.size();
    cdt->AddHole(head_hole);
    // Add chest hole
    vector<Point*> chest_hole = CreateChestHole();
    num_points += chest_hole.size();
    cdt->AddHole(chest_hole);
    polylines.push_back(head_hole);
    polylines.push_back(chest_hole);
  } else if (random_distribution) {
    max-=(1e-4);
    min+=(1e-4);
    for(int i = 0; i < num_points; i++) {
      double x = Random(Fun, min, max);
      double y = Random(Fun, min, max);
      cdt->AddPoint(new Point(x, y));
    }
  }

  /*
   * STEP 3: Triangulate!
   */
  cdt->Triangulate();

  double dt = glfwGetTime() - init_time;

  triangles = cdt->GetTriangles();
  map = cdt->GetMap();

  cout << "Number of points = " << num_points << endl;
  cout << "Number of triangles = " << triangles.size() << endl;
  cout << "Elapsed time (ms) = " << dt*1000.0 << endl;

  MainLoop(zoom);

  ShutDown(0);
  return 0;
}

void Init()
{
  const int window_width = 800,
            window_height = 600;

  if (glfwInit() != GL_TRUE)
    ShutDown(1);
  // 800 x 600, 16 bit color, no depth, alpha or stencil buffers, windowed
  if (glfwOpenWindow(window_width, window_height, 5, 6, 5, 0, 0, 0, GLFW_WINDOW) != GL_TRUE)
    ShutDown(1);

  glfwSetWindowTitle("Poly2Tri - C++");
  glfwSwapInterval(1);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
}

void ShutDown(int return_code)
{
  glfwTerminate();
  exit(return_code);
}

void MainLoop(const double zoom)
{
  // the time of the previous frame
  double old_time = glfwGetTime();
  // this just loops as long as the program runs
  bool running = true;

  while (running) {
    // calculate time elapsed, and the amount by which stuff rotates
    double current_time = glfwGetTime(),
           delta_rotate = (current_time - old_time) * rotations_per_tick * 360;
    old_time = current_time;

    // escape to quit, arrow keys to rotate view
    // Check if ESC key was pressed or window was closed
    running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);

    if (glfwGetKey(GLFW_KEY_LEFT) == GLFW_PRESS)
      rotate_y += delta_rotate;
    if (glfwGetKey(GLFW_KEY_RIGHT) == GLFW_PRESS)
      rotate_y -= delta_rotate;
    // z axis always rotates
    rotate_z += delta_rotate;

    // Draw the scene
    if (draw_map) {
      DrawMap(zoom);
    } else {
      Draw(zoom);
    }

    // swap back and front buffers
    glfwSwapBuffers();
  }
}

void ResetZoom(double zoom, double cx, double cy, double width, double height)
{
  double left = -width / zoom;
  double right = width / zoom;
  double bottom = -height / zoom;
  double top = height / zoom;

  // Reset viewport
  glLoadIdentity();
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  // Reset ortho view
  glOrtho(left, right, bottom, top, 1, -1);
  glTranslatef(-cx, -cy, 0);
  glMatrixMode(GL_MODELVIEW);
  glDisable(GL_DEPTH_TEST);
  glLoadIdentity();

  // Clear the screen
  glClear(GL_COLOR_BUFFER_BIT);
}

void Draw(const double zoom)
{
  // reset zoom
  Point center = Point(cx, cy);

  ResetZoom(zoom, center.x, center.y, 800, 600);

  for (int i = 0; i < triangles.size(); i++) {
    Triangle& t = *triangles[i];
    Point& a = *t.GetPoint(0);
    Point& b = *t.GetPoint(1);
    Point& c = *t.GetPoint(2);

    // Red
    glColor3f(1, 0, 0);

    glBegin(GL_LINE_LOOP);
    glVertex2f(a.x, a.y);
    glVertex2f(b.x, b.y);
    glVertex2f(c.x, c.y);
    glEnd();
  }

  // green
  glColor3f(0, 1, 0);

  for(int i = 0; i < polylines.size(); i++) {
    vector<Point*> poly = polylines[i];
    glBegin(GL_LINE_LOOP);
      for(int j = 0; j < poly.size(); j++) {
        glVertex2f(poly[j]->x, poly[j]->y);
      }
    glEnd();
  }
}

void DrawMap(const double zoom)
{
  // reset zoom
  Point center = Point(cx, cy);

  ResetZoom(zoom, center.x, center.y, 800, 600);

  list<Triangle*>::iterator it;
  for (it = map.begin(); it != map.end(); it++) {
    Triangle& t = **it;
    Point& a = *t.GetPoint(0);
    Point& b = *t.GetPoint(1);
    Point& c = *t.GetPoint(2);

    ConstrainedColor(t.constrained_edge[2]);
    glBegin(GL_LINES);
    glVertex2f(a.x, a.y);
    glVertex2f(b.x, b.y);
    glEnd( );

    ConstrainedColor(t.constrained_edge[0]);
    glBegin(GL_LINES);
    glVertex2f(b.x, b.y);
    glVertex2f(c.x, c.y);
    glEnd( );

    ConstrainedColor(t.constrained_edge[1]);
    glBegin(GL_LINES);
    glVertex2f(c.x, c.y);
    glVertex2f(a.x, a.y);
    glEnd( );
  }
}

void ConstrainedColor(bool constrain)
{
  if (constrain) {
    // Green
    glColor3f(0, 1, 0);
  } else {
    // Red
    glColor3f(1, 0, 0);
  }
}

vector<Point*> CreateHeadHole() {

  vector<Point*> head_hole;
  head_hole.push_back(new Point(325, 437));
  head_hole.push_back(new Point(320, 423));
  head_hole.push_back(new Point(329, 413));
  head_hole.push_back(new Point(332, 423));

  return head_hole;
}

vector<Point*> CreateChestHole() {

  vector<Point*> chest_hole;
  chest_hole.push_back(new Point(320.72342,480));
  chest_hole.push_back(new Point(338.90617,465.96863));
  chest_hole.push_back(new Point(347.99754,480.61584));
  chest_hole.push_back(new Point(329.8148,510.41534));
  chest_hole.push_back(new Point(339.91632,480.11077));
  chest_hole.push_back(new Point(334.86556,478.09046));

  return chest_hole;

}

double StringToDouble(const std::string& s)
{
  std::istringstream i(s);
  double x;
  if (!(i >> x))
    return 0;
  return x;
}

double Fun(double x)
{
  return 2.5 + sin(10 * x) / x;
}

double Random(double (*fun)(double), double xmin = 0, double xmax = 1)
{
  static double (*Fun)(double) = NULL, YMin, YMax;
  static bool First = true;

  // Initialises random generator for first call
  if (First)
  {
    First = false;
    srand((unsigned) time(NULL));
  }

  // Evaluates maximum of function
  if (fun != Fun)
  {
    Fun = fun;
    YMin = 0, YMax = Fun(xmin);
    for (int iX = 1; iX < RAND_MAX; iX++)
    {
      double X = xmin + (xmax - xmin) * iX / RAND_MAX;
      double Y = Fun(X);
      YMax = Y > YMax ? Y : YMax;
    }
  }

  // Gets random values for X & Y
  double X = xmin + (xmax - xmin) * rand() / RAND_MAX;
  double Y = YMin + (YMax - YMin) * rand() / RAND_MAX;

  // Returns if valid and try again if not valid
  return Y < fun(X) ? X : Random(Fun, xmin, xmax);
}
<commit_msg>updated comment<commit_after>/*
 * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
 * http://code.google.com/p/poly2tri/
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * * Neither the name of Poly2Tri nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without specific
 *   prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <cstdlib>
#include <GL/glfw.h>
#include <time.h>
#include <fstream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;

#include "../poly2tri/poly2tri.h"
using namespace p2t;

void Init();
void ShutDown(int return_code);
void MainLoop(const double zoom);
void Draw(const double zoom);
void DrawMap(const double zoom);
void ConstrainedColor(bool constrain);
double StringToDouble(const std::string& s);
double Random(double (*fun)(double), double xmin, double xmax);
double Fun(double x);

/// Dude hole examples
vector<Point*> CreateHeadHole();
vector<Point*> CreateChestHole();

float rotate_y = 0,
      rotate_z = 0;
const float rotations_per_tick = .2;

/// Screen center x
double cx = 0.0;
/// Screen center y
double cy = 0.0;

/// Constrained triangles
vector<Triangle*> triangles;
/// Triangle map
list<Triangle*> map;
/// Polylines
vector< vector<Point*> > polylines;

/// Draw the entire triangle map?
bool draw_map = false;
/// Create a random distribution of points?
bool random_distribution = false;

int main(int argc, char* argv[])
{

  int num_points = 0;
  double max, min;
  double zoom;

  if (argc != 5) {
    cout << "-== USAGE ==-" << endl;
    cout << "Load Data File: p2t filename center_x center_y zoom" << endl;
    cout << " Random Points: p2t random num_points width zoom" << endl;
    return 1;
  }

  if(string(argv[1]) == "random") {
    num_points = atoi(argv[2]);
    random_distribution = true;
    char* pEnd;
    max = strtod(argv[3], &pEnd);
    min = -max;
    cx = cy = 0;
    zoom = atof(argv[4]);
  } else {
    zoom = atof(argv[4]);
    cx = atof(argv[2]);
    cy = atof(argv[3]);
  }

  vector<p2t::Point*> polyline;

  if(random_distribution) {
    // Create a simple bounding box
    polyline.push_back(new Point(min,min));
    polyline.push_back(new Point(min,max));
    polyline.push_back(new Point(max,max));
    polyline.push_back(new Point(max,min));
  } else {
    // Load pointset from file

    // Parse and tokenize data file
    string line;
    ifstream myfile(argv[1]);
    if (myfile.is_open()) {
      while (!myfile.eof()) {
        getline(myfile, line);
        if (line.size() == 0) {
          break;
        }
        istringstream iss(line);
        vector<string> tokens;
        copy(istream_iterator<string>(iss), istream_iterator<string>(),
             back_inserter<vector<string> >(tokens));
        double x = StringToDouble(tokens[0]);
        double y = StringToDouble(tokens[1]);
        polyline.push_back(new Point(x, y));
        num_points++;
      }
      myfile.close();
    } else {
      cout << "File not opened" << endl;
    }
  }

  cout << "Number of constrained edges = " << polyline.size() << endl;
  polylines.push_back(polyline);

  Init();

  /*
   * Perform triangulation!
   */

  double init_time = glfwGetTime();

  /*
   * STEP 1: Create CDT and add primary polyline
   * NOTE: polyline must be a simple polygon. The polyline's points
   * constitute constrained edges. No repeat points!!!
   */
  CDT* cdt = new CDT(polyline);

  /*
   * STEP 2: Add holes or Steiner points if necessary
   */
  string s(argv[1]);
  if(s.find("dude.dat", 0) != string::npos) {
    // Add head hole
    vector<Point*> head_hole = CreateHeadHole();
    num_points += head_hole.size();
    cdt->AddHole(head_hole);
    // Add chest hole
    vector<Point*> chest_hole = CreateChestHole();
    num_points += chest_hole.size();
    cdt->AddHole(chest_hole);
    polylines.push_back(head_hole);
    polylines.push_back(chest_hole);
  } else if (random_distribution) {
    max-=(1e-4);
    min+=(1e-4);
    for(int i = 0; i < num_points; i++) {
      double x = Random(Fun, min, max);
      double y = Random(Fun, min, max);
      cdt->AddPoint(new Point(x, y));
    }
  }

  /*
   * STEP 3: Triangulate!
   */
  cdt->Triangulate();

  double dt = glfwGetTime() - init_time;

  triangles = cdt->GetTriangles();
  map = cdt->GetMap();

  cout << "Number of points = " << num_points << endl;
  cout << "Number of triangles = " << triangles.size() << endl;
  cout << "Elapsed time (ms) = " << dt*1000.0 << endl;

  MainLoop(zoom);

  ShutDown(0);
  return 0;
}

void Init()
{
  const int window_width = 800,
            window_height = 600;

  if (glfwInit() != GL_TRUE)
    ShutDown(1);
  // 800 x 600, 16 bit color, no depth, alpha or stencil buffers, windowed
  if (glfwOpenWindow(window_width, window_height, 5, 6, 5, 0, 0, 0, GLFW_WINDOW) != GL_TRUE)
    ShutDown(1);

  glfwSetWindowTitle("Poly2Tri - C++");
  glfwSwapInterval(1);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
}

void ShutDown(int return_code)
{
  glfwTerminate();
  exit(return_code);
}

void MainLoop(const double zoom)
{
  // the time of the previous frame
  double old_time = glfwGetTime();
  // this just loops as long as the program runs
  bool running = true;

  while (running) {
    // calculate time elapsed, and the amount by which stuff rotates
    double current_time = glfwGetTime(),
           delta_rotate = (current_time - old_time) * rotations_per_tick * 360;
    old_time = current_time;

    // escape to quit, arrow keys to rotate view
    // Check if ESC key was pressed or window was closed
    running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);

    if (glfwGetKey(GLFW_KEY_LEFT) == GLFW_PRESS)
      rotate_y += delta_rotate;
    if (glfwGetKey(GLFW_KEY_RIGHT) == GLFW_PRESS)
      rotate_y -= delta_rotate;
    // z axis always rotates
    rotate_z += delta_rotate;

    // Draw the scene
    if (draw_map) {
      DrawMap(zoom);
    } else {
      Draw(zoom);
    }

    // swap back and front buffers
    glfwSwapBuffers();
  }
}

void ResetZoom(double zoom, double cx, double cy, double width, double height)
{
  double left = -width / zoom;
  double right = width / zoom;
  double bottom = -height / zoom;
  double top = height / zoom;

  // Reset viewport
  glLoadIdentity();
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  // Reset ortho view
  glOrtho(left, right, bottom, top, 1, -1);
  glTranslatef(-cx, -cy, 0);
  glMatrixMode(GL_MODELVIEW);
  glDisable(GL_DEPTH_TEST);
  glLoadIdentity();

  // Clear the screen
  glClear(GL_COLOR_BUFFER_BIT);
}

void Draw(const double zoom)
{
  // reset zoom
  Point center = Point(cx, cy);

  ResetZoom(zoom, center.x, center.y, 800, 600);

  for (int i = 0; i < triangles.size(); i++) {
    Triangle& t = *triangles[i];
    Point& a = *t.GetPoint(0);
    Point& b = *t.GetPoint(1);
    Point& c = *t.GetPoint(2);

    // Red
    glColor3f(1, 0, 0);

    glBegin(GL_LINE_LOOP);
    glVertex2f(a.x, a.y);
    glVertex2f(b.x, b.y);
    glVertex2f(c.x, c.y);
    glEnd();
  }

  // green
  glColor3f(0, 1, 0);

  for(int i = 0; i < polylines.size(); i++) {
    vector<Point*> poly = polylines[i];
    glBegin(GL_LINE_LOOP);
      for(int j = 0; j < poly.size(); j++) {
        glVertex2f(poly[j]->x, poly[j]->y);
      }
    glEnd();
  }
}

void DrawMap(const double zoom)
{
  // reset zoom
  Point center = Point(cx, cy);

  ResetZoom(zoom, center.x, center.y, 800, 600);

  list<Triangle*>::iterator it;
  for (it = map.begin(); it != map.end(); it++) {
    Triangle& t = **it;
    Point& a = *t.GetPoint(0);
    Point& b = *t.GetPoint(1);
    Point& c = *t.GetPoint(2);

    ConstrainedColor(t.constrained_edge[2]);
    glBegin(GL_LINES);
    glVertex2f(a.x, a.y);
    glVertex2f(b.x, b.y);
    glEnd( );

    ConstrainedColor(t.constrained_edge[0]);
    glBegin(GL_LINES);
    glVertex2f(b.x, b.y);
    glVertex2f(c.x, c.y);
    glEnd( );

    ConstrainedColor(t.constrained_edge[1]);
    glBegin(GL_LINES);
    glVertex2f(c.x, c.y);
    glVertex2f(a.x, a.y);
    glEnd( );
  }
}

void ConstrainedColor(bool constrain)
{
  if (constrain) {
    // Green
    glColor3f(0, 1, 0);
  } else {
    // Red
    glColor3f(1, 0, 0);
  }
}

vector<Point*> CreateHeadHole() {

  vector<Point*> head_hole;
  head_hole.push_back(new Point(325, 437));
  head_hole.push_back(new Point(320, 423));
  head_hole.push_back(new Point(329, 413));
  head_hole.push_back(new Point(332, 423));

  return head_hole;
}

vector<Point*> CreateChestHole() {

  vector<Point*> chest_hole;
  chest_hole.push_back(new Point(320.72342,480));
  chest_hole.push_back(new Point(338.90617,465.96863));
  chest_hole.push_back(new Point(347.99754,480.61584));
  chest_hole.push_back(new Point(329.8148,510.41534));
  chest_hole.push_back(new Point(339.91632,480.11077));
  chest_hole.push_back(new Point(334.86556,478.09046));

  return chest_hole;

}

double StringToDouble(const std::string& s)
{
  std::istringstream i(s);
  double x;
  if (!(i >> x))
    return 0;
  return x;
}

double Fun(double x)
{
  return 2.5 + sin(10 * x) / x;
}

double Random(double (*fun)(double), double xmin = 0, double xmax = 1)
{
  static double (*Fun)(double) = NULL, YMin, YMax;
  static bool First = true;

  // Initialises random generator for first call
  if (First)
  {
    First = false;
    srand((unsigned) time(NULL));
  }

  // Evaluates maximum of function
  if (fun != Fun)
  {
    Fun = fun;
    YMin = 0, YMax = Fun(xmin);
    for (int iX = 1; iX < RAND_MAX; iX++)
    {
      double X = xmin + (xmax - xmin) * iX / RAND_MAX;
      double Y = Fun(X);
      YMax = Y > YMax ? Y : YMax;
    }
  }

  // Gets random values for X & Y
  double X = xmin + (xmax - xmin) * rand() / RAND_MAX;
  double Y = YMin + (YMax - YMin) * rand() / RAND_MAX;

  // Returns if valid and try again if not valid
  return Y < fun(X) ? X : Random(Fun, xmin, xmax);
}
<|endoftext|>