<commit_before>#include "CScripting.h"
#include "CHandle.h"
#include "CQuery.h"
#include "CCallback.h"
#include "CResult.h"

// native ORM:orm_create(const table[], MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::orm_create)
{
	return 0;
}

// native orm_destroy(ORM:id);
AMX_DECLARE_NATIVE(Native::orm_destroy)
{
	return 0;
}

// native ORM_Error:orm_errno(ORM:id);
AMX_DECLARE_NATIVE(Native::orm_errno)
{
	return 0;
}

// native orm_apply_cache(ORM:id, row);
AMX_DECLARE_NATIVE(Native::orm_apply_cache)
{
	return 0;
}

// native orm_select(ORM:id, callback[], format[], {Float, _}:...);
AMX_DECLARE_NATIVE(Native::orm_select)
{
	return 0;
}

// native orm_update(ORM:id);
AMX_DECLARE_NATIVE(Native::orm_update)
{
	return 0;
}

// native orm_insert(ORM:id, callback[]="", format[]="", {Float, _}:...);
AMX_DECLARE_NATIVE(Native::orm_insert)
{
	return 0;
}

// native orm_delete(ORM:id, bool:clearvars=true);
AMX_DECLARE_NATIVE(Native::orm_delete)
{
	return 0;
}

// native orm_save(ORM:id, callback[]="", format[]="", {Float, _}:...);
AMX_DECLARE_NATIVE(Native::orm_save)
{
	return 0;
}

// native orm_addvar_int(ORM:id, &var, varname[]);
AMX_DECLARE_NATIVE(Native::orm_addvar_int)
{
	return 0;
}

// native orm_addvar_float(ORM:id, &Float:var, varname[]);
AMX_DECLARE_NATIVE(Native::orm_addvar_float)
{
	return 0;
}

// native orm_addvar_string(ORM:id, var[], var_maxlen, varname[]);
AMX_DECLARE_NATIVE(Native::orm_addvar_string)
{
	return 0;
}

// native orm_delvar(ORM:id, varname[]);
AMX_DECLARE_NATIVE(Native::orm_delvar)
{
	return 0;
}

// native orm_setkey(ORM:id, varname[]);
AMX_DECLARE_NATIVE(Native::orm_setkey)
{
	return 0;
}

// native mysql_log(E_LOGLEVEL:loglevel = ERROR | WARNING, E_LOGTYPE:logtype = TEXT);
AMX_DECLARE_NATIVE(Native::mysql_log)
{
	return 0;
}

// TODO: remove auto-reconnect option (moved to mysql_option)
// native MySQL:mysql_connect(const host[], const user[], const database[], const password[], port = 3306, bool:autoreconnect = true, pool_size = 2);
AMX_DECLARE_NATIVE(Native::mysql_connect)
{
	CHandle::Error handle_error;
	CHandle *handle = CHandleManager::Get()->Create(
		amx_GetCppString(amx, params[1]),
		amx_GetCppString(amx, params[2]),
		amx_GetCppString(amx, params[3]),
		amx_GetCppString(amx, params[4]),
		params[5],
		params[7],
		handle_error);

	if (handle_error != CHandle::Error::NONE)
		return 0; //TODO: error message

	assert(handle != nullptr); //should never happen

	return handle->GetId();
}

// native mysql_close(MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_close)
{
	CHandle *handle = CHandleManager::Get()->GetHandle(static_cast<CHandle::Id_t>(params[1]));
	if (handle == nullptr)
		return 0;

	return CHandleManager::Get()->Destroy(handle);
}

// native mysql_reconnect(MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_reconnect)
{
	return 0;
}

// native mysql_unprocessed_queries(MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_unprocessed_queries)
{
	return 0;
}

// native mysql_current_handle();
AMX_DECLARE_NATIVE(Native::mysql_current_handle)
{
	return 0;
}

// TODO: add auto reconnect option to mysql_option
// native mysql_option(E_MYSQL_OPTION:type, value);
AMX_DECLARE_NATIVE(Native::mysql_option)
{
	return 0;
}

// native mysql_pquery(MySQL:handle, const query[], const callback[] = "", const format[] = "", {Float,_}:...);
AMX_DECLARE_NATIVE(Native::mysql_pquery)
{
	return 0;
}

// native mysql_tquery(MySQL:handle, const query[], const callback[] = "", const format[] = "", {Float,_}:...);
AMX_DECLARE_NATIVE(Native::mysql_tquery)
{
	const CHandle::Id_t handle_id = static_cast<CHandle::Id_t>(params[1]);
	CHandle *handle = CHandleManager::Get()->GetHandle(handle_id);

	if (handle == nullptr)
		return 0;

	CCallback::Error callback_error;
	CCallback::Type_t callback = CCallback::Create(
		amx,
		amx_GetCppString(amx, params[3]),
		amx_GetCppString(amx, params[4]),
		params, 5,
		callback_error);

	if (callback_error != CCallback::Error::NONE &&
		callback_error != CCallback::Error::EMPTY_NAME)
		return 0; // TODO: log error with CCallbackManager::GetErrorString

	CQuery *query = CQuery::Create(amx_GetCppString(amx, params[2]));
	if (callback != nullptr)
	{
		query->OnExecutionFinished([=](const CResult *result)
		{
			// TODO: pre-execute: set active handle & result(cache)
			callback->Execute();
			// TODO: post-execute: unset active handle & result(cache) + delete result
		});
	}

	return handle->Execute(CHandle::ExecutionType::THREADED, query);
}

// native Cache:mysql_query(MySQL:handle, const query[], bool:use_cache = true);
AMX_DECLARE_NATIVE(Native::mysql_query)
{
	return 0;
}

// native mysql_errno(MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_errno)
{
	return 0;
}

// native mysql_format(MySQL:handle, output[], len, const format[], {Float,_}:...);
AMX_DECLARE_NATIVE(Native::mysql_format)
{
	return 0;
}

// native mysql_escape_string(const source[], destination[], max_len = sizeof(destination), MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_escape_string)
{
	return 0;
}

// native mysql_set_charset(const charset[], MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_set_charset)
{
	return 0;
}

// native mysql_get_charset(destination[], max_len = sizeof(destination), MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_get_charset)
{
	return 0;
}

// native mysql_stat(destination[], max_len = sizeof(destination), MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_stat)
{
	return 0;
}

// native cache_get_data(&num_rows, &num_fields);
AMX_DECLARE_NATIVE(Native::cache_get_data)
{
	return 0;
}

// native cache_get_row_count();
AMX_DECLARE_NATIVE(Native::cache_get_row_count)
{
	return 0;
}

// native cache_get_field_count();
AMX_DECLARE_NATIVE(Native::cache_get_field_count)
{
	return 0;
}

// native cache_get_field_name(field_index, destination[], max_len = sizeof(destination))
AMX_DECLARE_NATIVE(Native::cache_get_field_name)
{
	return 0;
}

// native cache_get_row(row_idx, field_idx, destination[], max_len=sizeof(destination));
AMX_DECLARE_NATIVE(Native::cache_get_row)
{
	return 0;
}

// native cache_get_row_int(row_idx, field_idx);
AMX_DECLARE_NATIVE(Native::cache_get_row_int)
{
	return 0;
}

// native Float:cache_get_row_float(row_idx, field_idx);
AMX_DECLARE_NATIVE(Native::cache_get_row_float)
{
	return 0;
}

// native cache_get_field_content(row_idx, const field_name[], destination[], max_len=sizeof(destination));
AMX_DECLARE_NATIVE(Native::cache_get_field_content)
{
	return 0;
}

// native cache_get_field_content_int(row_idx, const field_name[]);
AMX_DECLARE_NATIVE(Native::cache_get_field_content_int)
{
	return 0;
}

// native Float:cache_get_field_content_float(row_idx, const field_name[]);
AMX_DECLARE_NATIVE(Native::cache_get_field_content_float)
{
	return 0;
}

// native Cache:cache_save();
AMX_DECLARE_NATIVE(Native::cache_save)
{
	return 0;
}

// native cache_delete(Cache:cache_id, MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::cache_delete)
{
	return 0;
}

// native cache_set_active(Cache:cache_id, MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::cache_set_active)
{
	return 0;
}

// native cache_is_valid(Cache:cache_id, MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::cache_is_valid)
{
	return 0;
}

// native cache_affected_rows();
AMX_DECLARE_NATIVE(Native::cache_affected_rows)
{
	return 0;
}

// native cache_warning_count();
AMX_DECLARE_NATIVE(Native::cache_warning_count)
{
	return 0;
}

// native cache_insert_id();
AMX_DECLARE_NATIVE(Native::cache_insert_id)
{
	return 0;
}

// native cache_get_query_exec_time(E_EXECTIME_UNIT:unit = MICROSECONDS);
AMX_DECLARE_NATIVE(Native::cache_get_query_exec_time)
{
	return 0;
}

// native cache_get_query_string(destination[], max_len = sizeof(destination));
AMX_DECLARE_NATIVE(Native::cache_get_query_string)
{
	return 0;
}
<commit_msg>fix wrong parameter order in mysql_connect<commit_after>#include "CScripting.h"
#include "CHandle.h"
#include "CQuery.h"
#include "CCallback.h"
#include "CResult.h"

// native ORM:orm_create(const table[], MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::orm_create)
{
	return 0;
}

// native orm_destroy(ORM:id);
AMX_DECLARE_NATIVE(Native::orm_destroy)
{
	return 0;
}

// native ORM_Error:orm_errno(ORM:id);
AMX_DECLARE_NATIVE(Native::orm_errno)
{
	return 0;
}

// native orm_apply_cache(ORM:id, row);
AMX_DECLARE_NATIVE(Native::orm_apply_cache)
{
	return 0;
}

// native orm_select(ORM:id, callback[], format[], {Float, _}:...);
AMX_DECLARE_NATIVE(Native::orm_select)
{
	return 0;
}

// native orm_update(ORM:id);
AMX_DECLARE_NATIVE(Native::orm_update)
{
	return 0;
}

// native orm_insert(ORM:id, callback[]="", format[]="", {Float, _}:...);
AMX_DECLARE_NATIVE(Native::orm_insert)
{
	return 0;
}

// native orm_delete(ORM:id, bool:clearvars=true);
AMX_DECLARE_NATIVE(Native::orm_delete)
{
	return 0;
}

// native orm_save(ORM:id, callback[]="", format[]="", {Float, _}:...);
AMX_DECLARE_NATIVE(Native::orm_save)
{
	return 0;
}

// native orm_addvar_int(ORM:id, &var, varname[]);
AMX_DECLARE_NATIVE(Native::orm_addvar_int)
{
	return 0;
}

// native orm_addvar_float(ORM:id, &Float:var, varname[]);
AMX_DECLARE_NATIVE(Native::orm_addvar_float)
{
	return 0;
}

// native orm_addvar_string(ORM:id, var[], var_maxlen, varname[]);
AMX_DECLARE_NATIVE(Native::orm_addvar_string)
{
	return 0;
}

// native orm_delvar(ORM:id, varname[]);
AMX_DECLARE_NATIVE(Native::orm_delvar)
{
	return 0;
}

// native orm_setkey(ORM:id, varname[]);
AMX_DECLARE_NATIVE(Native::orm_setkey)
{
	return 0;
}

// native mysql_log(E_LOGLEVEL:loglevel = ERROR | WARNING, E_LOGTYPE:logtype = TEXT);
AMX_DECLARE_NATIVE(Native::mysql_log)
{
	return 0;
}

// TODO: remove auto-reconnect option (moved to mysql_option)
// native MySQL:mysql_connect(const host[], const user[], const database[], const password[], port = 3306, bool:autoreconnect = true, pool_size = 2);
AMX_DECLARE_NATIVE(Native::mysql_connect)
{
	CHandle::Error handle_error;
	CHandle *handle = CHandleManager::Get()->Create(
		amx_GetCppString(amx, params[1]),
		amx_GetCppString(amx, params[2]),
		amx_GetCppString(amx, params[4]),
		amx_GetCppString(amx, params[3]),
		params[5],
		params[7],
		handle_error);

	if (handle_error != CHandle::Error::NONE)
		return 0; //TODO: error message

	assert(handle != nullptr); //should never happen

	return handle->GetId();
}

// native mysql_close(MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_close)
{
	CHandle *handle = CHandleManager::Get()->GetHandle(static_cast<CHandle::Id_t>(params[1]));
	if (handle == nullptr)
		return 0;

	return CHandleManager::Get()->Destroy(handle);
}

// native mysql_reconnect(MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_reconnect)
{
	return 0;
}

// native mysql_unprocessed_queries(MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_unprocessed_queries)
{
	return 0;
}

// native mysql_current_handle();
AMX_DECLARE_NATIVE(Native::mysql_current_handle)
{
	return 0;
}

// TODO: add auto reconnect option to mysql_option
// native mysql_option(E_MYSQL_OPTION:type, value);
AMX_DECLARE_NATIVE(Native::mysql_option)
{
	return 0;
}

// native mysql_pquery(MySQL:handle, const query[], const callback[] = "", const format[] = "", {Float,_}:...);
AMX_DECLARE_NATIVE(Native::mysql_pquery)
{
	return 0;
}

// native mysql_tquery(MySQL:handle, const query[], const callback[] = "", const format[] = "", {Float,_}:...);
AMX_DECLARE_NATIVE(Native::mysql_tquery)
{
	const CHandle::Id_t handle_id = static_cast<CHandle::Id_t>(params[1]);
	CHandle *handle = CHandleManager::Get()->GetHandle(handle_id);

	if (handle == nullptr)
		return 0;

	CCallback::Error callback_error;
	CCallback::Type_t callback = CCallback::Create(
		amx,
		amx_GetCppString(amx, params[3]),
		amx_GetCppString(amx, params[4]),
		params, 5,
		callback_error);

	if (callback_error != CCallback::Error::NONE &&
		callback_error != CCallback::Error::EMPTY_NAME)
		return 0; // TODO: log error with CCallbackManager::GetErrorString

	CQuery *query = CQuery::Create(amx_GetCppString(amx, params[2]));
	if (callback != nullptr)
	{
		query->OnExecutionFinished([=](const CResult *result)
		{
			// TODO: pre-execute: set active handle & result(cache)
			callback->Execute();
			// TODO: post-execute: unset active handle & result(cache) + delete result
		});
	}

	return handle->Execute(CHandle::ExecutionType::THREADED, query);
}

// native Cache:mysql_query(MySQL:handle, const query[], bool:use_cache = true);
AMX_DECLARE_NATIVE(Native::mysql_query)
{
	return 0;
}

// native mysql_errno(MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_errno)
{
	return 0;
}

// native mysql_format(MySQL:handle, output[], len, const format[], {Float,_}:...);
AMX_DECLARE_NATIVE(Native::mysql_format)
{
	return 0;
}

// native mysql_escape_string(const source[], destination[], max_len = sizeof(destination), MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_escape_string)
{
	return 0;
}

// native mysql_set_charset(const charset[], MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_set_charset)
{
	return 0;
}

// native mysql_get_charset(destination[], max_len = sizeof(destination), MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_get_charset)
{
	return 0;
}

// native mysql_stat(destination[], max_len = sizeof(destination), MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::mysql_stat)
{
	return 0;
}

// native cache_get_data(&num_rows, &num_fields);
AMX_DECLARE_NATIVE(Native::cache_get_data)
{
	return 0;
}

// native cache_get_row_count();
AMX_DECLARE_NATIVE(Native::cache_get_row_count)
{
	return 0;
}

// native cache_get_field_count();
AMX_DECLARE_NATIVE(Native::cache_get_field_count)
{
	return 0;
}

// native cache_get_field_name(field_index, destination[], max_len = sizeof(destination))
AMX_DECLARE_NATIVE(Native::cache_get_field_name)
{
	return 0;
}

// native cache_get_row(row_idx, field_idx, destination[], max_len=sizeof(destination));
AMX_DECLARE_NATIVE(Native::cache_get_row)
{
	return 0;
}

// native cache_get_row_int(row_idx, field_idx);
AMX_DECLARE_NATIVE(Native::cache_get_row_int)
{
	return 0;
}

// native Float:cache_get_row_float(row_idx, field_idx);
AMX_DECLARE_NATIVE(Native::cache_get_row_float)
{
	return 0;
}

// native cache_get_field_content(row_idx, const field_name[], destination[], max_len=sizeof(destination));
AMX_DECLARE_NATIVE(Native::cache_get_field_content)
{
	return 0;
}

// native cache_get_field_content_int(row_idx, const field_name[]);
AMX_DECLARE_NATIVE(Native::cache_get_field_content_int)
{
	return 0;
}

// native Float:cache_get_field_content_float(row_idx, const field_name[]);
AMX_DECLARE_NATIVE(Native::cache_get_field_content_float)
{
	return 0;
}

// native Cache:cache_save();
AMX_DECLARE_NATIVE(Native::cache_save)
{
	return 0;
}

// native cache_delete(Cache:cache_id, MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::cache_delete)
{
	return 0;
}

// native cache_set_active(Cache:cache_id, MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::cache_set_active)
{
	return 0;
}

// native cache_is_valid(Cache:cache_id, MySQL:handle = DEFAULT_MYSQL_HANDLE);
AMX_DECLARE_NATIVE(Native::cache_is_valid)
{
	return 0;
}

// native cache_affected_rows();
AMX_DECLARE_NATIVE(Native::cache_affected_rows)
{
	return 0;
}

// native cache_warning_count();
AMX_DECLARE_NATIVE(Native::cache_warning_count)
{
	return 0;
}

// native cache_insert_id();
AMX_DECLARE_NATIVE(Native::cache_insert_id)
{
	return 0;
}

// native cache_get_query_exec_time(E_EXECTIME_UNIT:unit = MICROSECONDS);
AMX_DECLARE_NATIVE(Native::cache_get_query_exec_time)
{
	return 0;
}

// native cache_get_query_string(destination[], max_len = sizeof(destination));
AMX_DECLARE_NATIVE(Native::cache_get_query_string)
{
	return 0;
}
<|endoftext|>


<commit_before>//#####################################################################
// Class TriangleMesh
//#####################################################################
#include <other/core/mesh/TriangleMesh.h>
#include <other/core/mesh/SegmentMesh.h>
#include <other/core/array/sort.h>
#include <other/core/array/view.h>
#include <other/core/structure/Hashtable.h>
#include <other/core/python/Class.h>
namespace other {

using std::cout;
using std::endl;
typedef real T;
typedef Vector<T,3> TV3;

OTHER_DEFINE_TYPE(TriangleMesh)
const int TriangleMesh::d;

TriangleMesh::TriangleMesh(Array<const Vector<int,3> > elements)
  : vertices(scalar_view_own(elements))
  , elements(elements)
  , bending_quadruples_valid(false) {
  // Assert validity and compute counts
  node_count = 0;
  for (int i=0;i<vertices.size();i++) {
    OTHER_ASSERT(vertices[i]>=0);
    node_count = max(node_count,vertices[i]+1);
  }
}

TriangleMesh::~TriangleMesh() {}

Ref<const SegmentMesh> TriangleMesh::segment_mesh() const {
  if (!segment_mesh_) {
    Hashtable<Vector<int,2> > hash;
    Array<Vector<int,2> > segments;
    for (int t=0;t<elements.size();t++) {
      for (int i=0;i<3;i++) {
        Vector<int,2> segment = vec(elements[t][i],elements[t][(i+1)%3]).sorted();
        if (hash.set(segment)) segments.append(segment);
      }
    }
    segment_mesh_ = new_<SegmentMesh>(segments);
  }
  return ref(segment_mesh_);
}

NestedArray<const int> TriangleMesh::incident_elements() const {
  if (!incident_elements_.size() && nodes()) {
    Array<int> lengths(nodes());
    for (int i=0;i<vertices.size();i++)
      lengths[vertices[i]]++;
    incident_elements_ = NestedArray<int>(lengths);
    for (int t=0;t<elements.size();t++) for(int i=0;i<3;i++) {
      int p = elements[t][i];
      incident_elements_(p,incident_elements_.size(p)-lengths[p]--)=t;
    }
  }
  return incident_elements_;
}

Array<const Vector<int,3> > TriangleMesh::adjacent_elements() const {
  if (!adjacent_elements_.size() && nodes()) {
    adjacent_elements_.resize(elements.size(),false,false);
    NestedArray<const int> incident = incident_elements();
    for (int t=0;t<elements.size();t++) {
      Vector<int,3> tri = elements[t];
      for (int j=0,i=2;j<3;i=j++) {
        for (int t2 : incident[tri[i]])
          if (t!=t2) {
            int a = elements[t2].find(tri[i]);
            if (elements[t2][(a+2)%3]==tri[j])  {
              adjacent_elements_[t][i] = t2;
              goto found;
            }
          }
        adjacent_elements_[t][i] = -1;
        found:;
      }
    }
  }
  return adjacent_elements_;
}

Ref<SegmentMesh> TriangleMesh::boundary_mesh() const {
  if (!boundary_mesh_) {
    Hashtable<Vector<int,2>,int> hash;
    for (int t=0;t<elements.size();t++)
      for (int i=0;i<3;i++) {
        int a = elements[t][i],
            b = elements[t][(i+1)%3];
        hash.get_or_insert(vec(a,b))++;
        hash.get_or_insert(vec(b,a))+=2;
      }
    Array<Vector<int,2> > segments;
    Ref<const SegmentMesh> segment_mesh_ = segment_mesh();
    for (int s=0;s<segment_mesh_->elements.size();s++) {
      int i,j;segment_mesh_->elements[s].get(i,j);
      if (hash.get_default(vec(i,j))==1)
        segments.append(vec(i,j));
      else if (hash.get_default(vec(j,i))==1)
        segments.append(vec(j,i));
    }
    boundary_mesh_ = new_<SegmentMesh>(segments);
  }
  return ref(boundary_mesh_);
}

Array<const Vector<int,4> > TriangleMesh::bending_quadruples() const {
  if (!bending_quadruples_valid) {
    Hashtable<Vector<int,2>,Array<int> > edge_to_face;
    for (int t=0;t<elements.size();t++) {
      Vector<int,3> nodes = elements[t];
      for (int a=0;a<3;a++)
        edge_to_face.get_or_insert(vec(nodes[a],nodes[(a+1)%3]).sorted()).append(t);
    }
    for (const auto& it : edge_to_face) {
      Vector<int,2> sn = it.key;
      RawArray<const int> tris(it.data);
      int other[tris.size()];
      bool flipped[tris.size()];
      for (int a=0;a<tris.size();a++) {
        Vector<int,3> tn = elements[tris[a]];
        int b = !sn.contains(tn[0])?0:!sn.contains(tn[1])?1:2;
        other[a] = tn[b];
        flipped[a] = tn[(b+1)%3]!=sn[0];
        assert(tn[(b+1)%3]==sn[flipped[a]] && tn[(b+2)%3]==sn[1-flipped[a]]);}
      for (int a=0;a<tris.size();a++) for (int b=a+1;b<tris.size();b++)
        bending_quadruples_.append(vec(other[a],sn[flipped[a]],sn[1-flipped[a]],other[b]));
    }
    bending_quadruples_valid = true;
  }
  return bending_quadruples_;
}

Array<const int> TriangleMesh::nodes_touched() const {
  if (!nodes_touched_.size() && elements.size()) {
    Hashtable<int> hash;
    for (int t=0;t<elements.size();t++) for (int i=0;i<3;i++)
      if (hash.set(elements[t][i]))
        nodes_touched_.append(elements[t][i]);
    sort(nodes_touched_);
  }
  return nodes_touched_;
}

NestedArray<const int> TriangleMesh::sorted_neighbors() const {
  if (!sorted_neighbors_.size() && elements.size()) {
    Hashtable<Vector<int,2>,int> next; // next[(i,j)] = k if (i,j,k) is a triangle
    Hashtable<Vector<int,2>,int> prev; // prev[(i,k)] = j if (i,j,k) is a triangle
    for (const Vector<int,3>& tri : elements) {
      next.set(vec(tri[0],tri[1]),tri[2]);
      next.set(vec(tri[1],tri[2]),tri[0]);
      next.set(vec(tri[2],tri[0]),tri[1]);
      prev.set(vec(tri[0],tri[2]),tri[1]);
      prev.set(vec(tri[1],tri[0]),tri[2]);
      prev.set(vec(tri[2],tri[1]),tri[0]);
    }
    NestedArray<const int> neighbors = segment_mesh()->neighbors();
    NestedArray<int> sorted_neighbors = NestedArray<int>::empty_like(neighbors);
    Hashtable<Vector<int,2> > done;
    for (int i=0;i<node_count;i++) {
      if (!neighbors.size(i))
        continue;
      // Find a node with no predecessor if one exists
      int j = neighbors(i,0);
      for (int a=1;a<neighbors.size(i);a++) {
        if (int* p = prev.get_pointer(vec(i,j)))
          j = *p;
        else
          break;
      }
      // Walk around boundary.  Note that we assume the mesh is manifold (possibly with boundary)
      sorted_neighbors(i,0) = j;
      for (int a=1;a<neighbors.size(i);a++) {
        j = next.get(vec(i,j));
        sorted_neighbors(i,a) = j;
      }
    }
    sorted_neighbors_ = sorted_neighbors;
  }
  return sorted_neighbors_;
}

T TriangleMesh::area(RawArray<const TV2> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  T sum = 0;
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    sum += cross(X[j]-X[i],X[k]-X[i]);
  }
  return (T).5*sum;
}

T TriangleMesh::volume(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  // If S is the surface and I is the interior, Stokes theorem gives
  //     V = int_I dV = 1/3 int_I (div x) dV = 1/3 int_S x . dA
  //       = 1/3 sum_t c_t . A_t
  //       = 1/18 sum_t (a + b + c) . (b - a) x (c - a)
  //       = 1/18 sum_t det (a+b+c, b-a, c-a)
  //       = 1/18 sum_t det (3a, b-a, c-a)
  //       = 1/6 sum_t det (a,b,c)
  // where a,b,c are the vertices of each triangle.
  T sum = 0;
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    sum += det(X[i],X[j],X[k]);
  }
  return T(1./6)*sum;
}

T TriangleMesh::surface_area(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  T sum = 0;
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    sum += magnitude(cross(X[j]-X[i],X[k]-X[i]));
  }
  return T(.5)*sum;
}

Array<T> TriangleMesh::vertex_areas(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  Array<T> areas(X.size());
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    T area = T(1./6)*magnitude(cross(X[j]-X[i],X[k]-X[i]));
    areas[i] += area;
    areas[j] += area;
    areas[k] += area;
  }
  return areas;
}

Array<TV3> TriangleMesh::vertex_normals(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  Array<TV3> normals(X.size());
  for(int t=0;t<elements.size();t++){
    int i,j,k;elements[t].get(i,j,k);
    TV3 n = cross(X[j]-X[i],X[k]-X[i]);
    normals[i]+=n;normals[j]+=n;normals[k]+=n;
  }
  for(int i=0;i<X.size();i++)
    normals[i].normalize();
  return normals;
}

Array<TV3> TriangleMesh::element_normals(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  Array<TV3> normals(elements.size(),false);
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    normals[t] = cross(X[j]-X[i],X[k]-X[i]).normalized();
  }
  return normals;
}

Array<int> TriangleMesh::nonmanifold_nodes(bool allow_boundary) const {
  Array<int> nonmanifold;
  NestedArray<const int> incident_elements = this->incident_elements();
  Array<Vector<int,2> > ring;
  Hashtable<int,Vector<int,2> > neighbors(32); // prev,next for each node in the ring
  const Vector<int,2> none(-1,-1);
  for (int i=0;i<incident_elements.size();i++) {
    RawArray<const int> incident = incident_elements[i];
    if (!incident.size())
      continue;
    // Collect oriented boundary segments of the one ring
    ring.resize(incident.size(),false,false);
    for (int t=0;t<incident.size();t++) {
      Vector<int,3> tri = elements[incident[t]];
      if (tri.x==tri.y || tri.x==tri.z || tri.y==tri.z)
        goto bad;
      ring[t] = tri.x==i?vec(tri.y,tri.z):tri.y==i?vec(tri.z,tri.x):vec(tri.x,tri.y);
    }
    // Determine topology
    neighbors.clear();
    for (int t=0;t<ring.size();t++) {
      Vector<int,2>& nx = neighbors.get_or_insert(ring[t].x,none);
      if (nx.y>=0) goto bad; // node already has a next
      nx.y = ring[t].y;
      Vector<int,2>& ny = neighbors.get_or_insert(ring[t].y,none);
      if (ny.x>=0) goto bad; // node already has a prev
      ny.x = ring[t].x;
    }
    // At this point the ring is definitely a 1-manifold with boundary, possibly consisting of many component curves.
    if (neighbors.size()==ring.size()) { // All components are closed loops
      // Ensure there's only component by checking the size of one of them
      int start = ring[0].x, node = ring[0].y, steps = ring.size()-2;
      for (int j=0;j<steps;j++) {
        node = neighbors.get(node).y;
        if (node==start)
          goto bad;
      }
    } else if (neighbors.size()>ring.size()+1) // There are least two open curves
      goto bad;
    else { // There's exactly one open curve
      if (!allow_boundary)
        goto bad;
      // Ensure there's only one component by checking the size of one of them
      int middle = ring[0].x, count = 2;
      for (int start=middle;;) {
        start = neighbors.get(start).x;
        if (start<0) break;
        if (start==middle) goto bad; // Loop is closed, so there must be two components
        count++;
      }
      for (int end=ring[0].y;;) {
        end = neighbors.get(end).y;
        if (end<0) break;
        // No need to check for middle since we know the curve is open
        count++;
      }
      if (count!=neighbors.size())
        goto bad;
    }
    continue; // manifold node
    bad: nonmanifold.append(i);
  }
  return nonmanifold;
}

}
using namespace other;

void wrap_triangle_mesh() {
  typedef TriangleMesh Self;
  Class<Self>("TriangleMesh")
    .OTHER_INIT(Array<const Vector<int,3> >)
    .OTHER_FIELD(d)
    .OTHER_FIELD(elements)
    .OTHER_FIELD(vertices)
    .OTHER_METHOD(segment_mesh)
    .OTHER_METHOD(triangle_mesh)
    .OTHER_METHOD(incident_elements)
    .OTHER_METHOD(adjacent_elements)
    .OTHER_METHOD(boundary_mesh)
    .OTHER_METHOD(bending_quadruples)
    .OTHER_METHOD(nodes_touched)
    .OTHER_METHOD(area)
    .OTHER_METHOD(volume)
    .OTHER_METHOD(surface_area)
    .OTHER_METHOD(vertex_areas)
    .OTHER_METHOD(vertex_normals)
    .OTHER_METHOD(element_normals)
    .OTHER_METHOD(nodes)
    .OTHER_METHOD(nonmanifold_nodes)
    ;
}
<commit_msg>TriangleMesh: Report which node caused sorted_neighbors to fail<commit_after>//#####################################################################
// Class TriangleMesh
//#####################################################################
#include <other/core/mesh/TriangleMesh.h>
#include <other/core/mesh/SegmentMesh.h>
#include <other/core/array/sort.h>
#include <other/core/array/view.h>
#include <other/core/structure/Hashtable.h>
#include <other/core/python/Class.h>
namespace other {

using std::cout;
using std::endl;
typedef real T;
typedef Vector<T,3> TV3;

OTHER_DEFINE_TYPE(TriangleMesh)
const int TriangleMesh::d;

TriangleMesh::TriangleMesh(Array<const Vector<int,3> > elements)
  : vertices(scalar_view_own(elements))
  , elements(elements)
  , bending_quadruples_valid(false) {
  // Assert validity and compute counts
  node_count = 0;
  for (int i=0;i<vertices.size();i++) {
    OTHER_ASSERT(vertices[i]>=0);
    node_count = max(node_count,vertices[i]+1);
  }
}

TriangleMesh::~TriangleMesh() {}

Ref<const SegmentMesh> TriangleMesh::segment_mesh() const {
  if (!segment_mesh_) {
    Hashtable<Vector<int,2> > hash;
    Array<Vector<int,2> > segments;
    for (int t=0;t<elements.size();t++) {
      for (int i=0;i<3;i++) {
        Vector<int,2> segment = vec(elements[t][i],elements[t][(i+1)%3]).sorted();
        if (hash.set(segment)) segments.append(segment);
      }
    }
    segment_mesh_ = new_<SegmentMesh>(segments);
  }
  return ref(segment_mesh_);
}

NestedArray<const int> TriangleMesh::incident_elements() const {
  if (!incident_elements_.size() && nodes()) {
    Array<int> lengths(nodes());
    for (int i=0;i<vertices.size();i++)
      lengths[vertices[i]]++;
    incident_elements_ = NestedArray<int>(lengths);
    for (int t=0;t<elements.size();t++) for(int i=0;i<3;i++) {
      int p = elements[t][i];
      incident_elements_(p,incident_elements_.size(p)-lengths[p]--)=t;
    }
  }
  return incident_elements_;
}

Array<const Vector<int,3> > TriangleMesh::adjacent_elements() const {
  if (!adjacent_elements_.size() && nodes()) {
    adjacent_elements_.resize(elements.size(),false,false);
    NestedArray<const int> incident = incident_elements();
    for (int t=0;t<elements.size();t++) {
      Vector<int,3> tri = elements[t];
      for (int j=0,i=2;j<3;i=j++) {
        for (int t2 : incident[tri[i]])
          if (t!=t2) {
            int a = elements[t2].find(tri[i]);
            if (elements[t2][(a+2)%3]==tri[j])  {
              adjacent_elements_[t][i] = t2;
              goto found;
            }
          }
        adjacent_elements_[t][i] = -1;
        found:;
      }
    }
  }
  return adjacent_elements_;
}

Ref<SegmentMesh> TriangleMesh::boundary_mesh() const {
  if (!boundary_mesh_) {
    Hashtable<Vector<int,2>,int> hash;
    for (int t=0;t<elements.size();t++)
      for (int i=0;i<3;i++) {
        int a = elements[t][i],
            b = elements[t][(i+1)%3];
        hash.get_or_insert(vec(a,b))++;
        hash.get_or_insert(vec(b,a))+=2;
      }
    Array<Vector<int,2> > segments;
    Ref<const SegmentMesh> segment_mesh_ = segment_mesh();
    for (int s=0;s<segment_mesh_->elements.size();s++) {
      int i,j;segment_mesh_->elements[s].get(i,j);
      if (hash.get_default(vec(i,j))==1)
        segments.append(vec(i,j));
      else if (hash.get_default(vec(j,i))==1)
        segments.append(vec(j,i));
    }
    boundary_mesh_ = new_<SegmentMesh>(segments);
  }
  return ref(boundary_mesh_);
}

Array<const Vector<int,4> > TriangleMesh::bending_quadruples() const {
  if (!bending_quadruples_valid) {
    Hashtable<Vector<int,2>,Array<int> > edge_to_face;
    for (int t=0;t<elements.size();t++) {
      Vector<int,3> nodes = elements[t];
      for (int a=0;a<3;a++)
        edge_to_face.get_or_insert(vec(nodes[a],nodes[(a+1)%3]).sorted()).append(t);
    }
    for (const auto& it : edge_to_face) {
      Vector<int,2> sn = it.key;
      RawArray<const int> tris(it.data);
      int other[tris.size()];
      bool flipped[tris.size()];
      for (int a=0;a<tris.size();a++) {
        Vector<int,3> tn = elements[tris[a]];
        int b = !sn.contains(tn[0])?0:!sn.contains(tn[1])?1:2;
        other[a] = tn[b];
        flipped[a] = tn[(b+1)%3]!=sn[0];
        assert(tn[(b+1)%3]==sn[flipped[a]] && tn[(b+2)%3]==sn[1-flipped[a]]);}
      for (int a=0;a<tris.size();a++) for (int b=a+1;b<tris.size();b++)
        bending_quadruples_.append(vec(other[a],sn[flipped[a]],sn[1-flipped[a]],other[b]));
    }
    bending_quadruples_valid = true;
  }
  return bending_quadruples_;
}

Array<const int> TriangleMesh::nodes_touched() const {
  if (!nodes_touched_.size() && elements.size()) {
    Hashtable<int> hash;
    for (int t=0;t<elements.size();t++) for (int i=0;i<3;i++)
      if (hash.set(elements[t][i]))
        nodes_touched_.append(elements[t][i]);
    sort(nodes_touched_);
  }
  return nodes_touched_;
}

NestedArray<const int> TriangleMesh::sorted_neighbors() const {
  if (!sorted_neighbors_.size() && elements.size()) {
    Hashtable<Vector<int,2>,int> next; // next[(i,j)] = k if (i,j,k) is a triangle
    Hashtable<Vector<int,2>,int> prev; // prev[(i,k)] = j if (i,j,k) is a triangle
    for (const Vector<int,3>& tri : elements) {
      next.set(vec(tri[0],tri[1]),tri[2]);
      next.set(vec(tri[1],tri[2]),tri[0]);
      next.set(vec(tri[2],tri[0]),tri[1]);
      prev.set(vec(tri[0],tri[2]),tri[1]);
      prev.set(vec(tri[1],tri[0]),tri[2]);
      prev.set(vec(tri[2],tri[1]),tri[0]);
    }
    NestedArray<const int> neighbors = segment_mesh()->neighbors();
    NestedArray<int> sorted_neighbors = NestedArray<int>::empty_like(neighbors);
    Hashtable<Vector<int,2> > done;
    for (int i=0;i<node_count;i++) {
      if (!neighbors.size(i))
        continue;
      // Find a node with no predecessor if one exists
      int j = neighbors(i,0);
      for (int a=1;a<neighbors.size(i);a++) {
        if (int* p = prev.get_pointer(vec(i,j)))
          j = *p;
        else
          break;
      }
      // Walk around boundary.  Note that we assume the mesh is manifold (possibly with boundary)
      sorted_neighbors(i,0) = j;
      try {
        for (int a=1;a<neighbors.size(i);a++) {
          j = next.get(vec(i,j));
          sorted_neighbors(i,a) = j;
        }
      } catch (const KeyError&) {
        throw RuntimeError(format("TriangleMesh::sorted_neighbors failed: node %d",i));
      }
    }
    sorted_neighbors_ = sorted_neighbors;
  }
  return sorted_neighbors_;
}

T TriangleMesh::area(RawArray<const TV2> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  T sum = 0;
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    sum += cross(X[j]-X[i],X[k]-X[i]);
  }
  return (T).5*sum;
}

T TriangleMesh::volume(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  // If S is the surface and I is the interior, Stokes theorem gives
  //     V = int_I dV = 1/3 int_I (div x) dV = 1/3 int_S x . dA
  //       = 1/3 sum_t c_t . A_t
  //       = 1/18 sum_t (a + b + c) . (b - a) x (c - a)
  //       = 1/18 sum_t det (a+b+c, b-a, c-a)
  //       = 1/18 sum_t det (3a, b-a, c-a)
  //       = 1/6 sum_t det (a,b,c)
  // where a,b,c are the vertices of each triangle.
  T sum = 0;
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    sum += det(X[i],X[j],X[k]);
  }
  return T(1./6)*sum;
}

T TriangleMesh::surface_area(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  T sum = 0;
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    sum += magnitude(cross(X[j]-X[i],X[k]-X[i]));
  }
  return T(.5)*sum;
}

Array<T> TriangleMesh::vertex_areas(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  Array<T> areas(X.size());
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    T area = T(1./6)*magnitude(cross(X[j]-X[i],X[k]-X[i]));
    areas[i] += area;
    areas[j] += area;
    areas[k] += area;
  }
  return areas;
}

Array<TV3> TriangleMesh::vertex_normals(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  Array<TV3> normals(X.size());
  for(int t=0;t<elements.size();t++){
    int i,j,k;elements[t].get(i,j,k);
    TV3 n = cross(X[j]-X[i],X[k]-X[i]);
    normals[i]+=n;normals[j]+=n;normals[k]+=n;
  }
  for(int i=0;i<X.size();i++)
    normals[i].normalize();
  return normals;
}

Array<TV3> TriangleMesh::element_normals(RawArray<const TV3> X) const {
  OTHER_ASSERT(X.size()>=nodes());
  Array<TV3> normals(elements.size(),false);
  for (int t=0;t<elements.size();t++) {
    int i,j,k;elements[t].get(i,j,k);
    normals[t] = cross(X[j]-X[i],X[k]-X[i]).normalized();
  }
  return normals;
}

Array<int> TriangleMesh::nonmanifold_nodes(bool allow_boundary) const {
  Array<int> nonmanifold;
  NestedArray<const int> incident_elements = this->incident_elements();
  Array<Vector<int,2> > ring;
  Hashtable<int,Vector<int,2> > neighbors(32); // prev,next for each node in the ring
  const Vector<int,2> none(-1,-1);
  for (int i=0;i<incident_elements.size();i++) {
    RawArray<const int> incident = incident_elements[i];
    if (!incident.size())
      continue;
    // Collect oriented boundary segments of the one ring
    ring.resize(incident.size(),false,false);
    for (int t=0;t<incident.size();t++) {
      Vector<int,3> tri = elements[incident[t]];
      if (tri.x==tri.y || tri.x==tri.z || tri.y==tri.z)
        goto bad;
      ring[t] = tri.x==i?vec(tri.y,tri.z):tri.y==i?vec(tri.z,tri.x):vec(tri.x,tri.y);
    }
    // Determine topology
    neighbors.clear();
    for (int t=0;t<ring.size();t++) {
      Vector<int,2>& nx = neighbors.get_or_insert(ring[t].x,none);
      if (nx.y>=0) goto bad; // node already has a next
      nx.y = ring[t].y;
      Vector<int,2>& ny = neighbors.get_or_insert(ring[t].y,none);
      if (ny.x>=0) goto bad; // node already has a prev
      ny.x = ring[t].x;
    }
    // At this point the ring is definitely a 1-manifold with boundary, possibly consisting of many component curves.
    if (neighbors.size()==ring.size()) { // All components are closed loops
      // Ensure there's only component by checking the size of one of them
      int start = ring[0].x, node = ring[0].y, steps = ring.size()-2;
      for (int j=0;j<steps;j++) {
        node = neighbors.get(node).y;
        if (node==start)
          goto bad;
      }
    } else if (neighbors.size()>ring.size()+1) // There are least two open curves
      goto bad;
    else { // There's exactly one open curve
      if (!allow_boundary)
        goto bad;
      // Ensure there's only one component by checking the size of one of them
      int middle = ring[0].x, count = 2;
      for (int start=middle;;) {
        start = neighbors.get(start).x;
        if (start<0) break;
        if (start==middle) goto bad; // Loop is closed, so there must be two components
        count++;
      }
      for (int end=ring[0].y;;) {
        end = neighbors.get(end).y;
        if (end<0) break;
        // No need to check for middle since we know the curve is open
        count++;
      }
      if (count!=neighbors.size())
        goto bad;
    }
    continue; // manifold node
    bad: nonmanifold.append(i);
  }
  return nonmanifold;
}

}
using namespace other;

void wrap_triangle_mesh() {
  typedef TriangleMesh Self;
  Class<Self>("TriangleMesh")
    .OTHER_INIT(Array<const Vector<int,3> >)
    .OTHER_FIELD(d)
    .OTHER_FIELD(elements)
    .OTHER_FIELD(vertices)
    .OTHER_METHOD(segment_mesh)
    .OTHER_METHOD(triangle_mesh)
    .OTHER_METHOD(incident_elements)
    .OTHER_METHOD(adjacent_elements)
    .OTHER_METHOD(boundary_mesh)
    .OTHER_METHOD(bending_quadruples)
    .OTHER_METHOD(nodes_touched)
    .OTHER_METHOD(area)
    .OTHER_METHOD(volume)
    .OTHER_METHOD(surface_area)
    .OTHER_METHOD(vertex_areas)
    .OTHER_METHOD(vertex_normals)
    .OTHER_METHOD(element_normals)
    .OTHER_METHOD(nodes)
    .OTHER_METHOD(nonmanifold_nodes)
    ;
}
<|endoftext|>


<commit_before>/*
 * PlayerObjectMenuComponent.cpp
 *
 *  Created on: 26/05/2011
 *      Author: victor
 */

#include "PlayerObjectMenuComponent.h"
#include "server/zone/objects/scene/components/ObjectMenuComponent.h"
#include "server/zone/packets/object/ObjectMenuResponse.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/objects/group/GroupObject.h"
#include "server/zone/objects/player/sui/listbox/teachplayerlistbox/TeachPlayerListBox.h"

void PlayerObjectMenuComponent::fillObjectMenuResponse(SceneObject* sceneObject, ObjectMenuResponse* menuResponse, CreatureObject* player) {
	if (!sceneObject->isCreatureObject())
		return;

	CreatureObject* creature = (CreatureObject*) sceneObject;
	GroupObject* group = creature->getGroup();

	if (group != NULL) {
		if (group->hasMember(player))
			menuResponse->addRadialMenuItem(51, 3, "@sui:teach");
	}

	if (creature->isPlayingMusic()) {
		if (!player->isListening())
			menuResponse->addRadialMenuItem(113, 3, "@radial_performance:listen");
		else
			menuResponse->addRadialMenuItem(115, 3, "@radial_performance:listen_stop");
	}

	if (creature->isDancing()) {
		if (!player->isWatching())
			menuResponse->addRadialMenuItem(114, 3, "@radial_performance:watch");
		else
			menuResponse->addRadialMenuItem(116, 3, "@radial_performance:watch_stop");
	}

}

int PlayerObjectMenuComponent::handleObjectMenuSelect(SceneObject* sceneObject, CreatureObject* player, byte selectedID) {
	CreatureObject* ownerPlayer = dynamic_cast<CreatureObject*>(sceneObject);
	PlayerObject* ghost = ownerPlayer->getPlayerObject();

	switch(selectedID) {
	case 113:
		player->executeObjectControllerAction(String("listen").hashCode(), sceneObject->getObjectID(), "");
		break;
	case 115:
		player->executeObjectControllerAction(String("stoplistening").hashCode(), sceneObject->getObjectID(), "");
		break;

	case 114:
		player->executeObjectControllerAction(String("watch").hashCode(), sceneObject->getObjectID(), "");
		break;

	case 116:
		player->executeObjectControllerAction(String("stopwatching").hashCode(), sceneObject->getObjectID(), "");
		break;

	case 51:

			if (ghost->isTeachingOrLearning() || ghost->isTeachingOrLearning()) {
				player->sendSystemMessage("teaching", "teaching_failed");
				return 1;
			}

			ghost->setTeachingOrLearning(true);

			ManagedReference<TeachPlayerListBox*> teachPlayerListBox = new TeachPlayerListBox(player);
			teachPlayerListBox->setCancelButton(true, "");

			bool completed = teachPlayerListBox->generateSkillList(player, ownerPlayer);

			if(!completed)
				ghost->setTeachingOrLearning(false);

		break;
	}

	return 0;
}

<commit_msg>[fixed] Radial menu for players cleaned up at back end. [changed] Option "Teach" now using new code path (work in progress).<commit_after>/*
 Copyright (C) 2007-2011 <SWGEmu>

 This File is part of Core3.

 This program is free software; you can redistribute
 it and/or modify it under the terms of the GNU Lesser
 General Public License as published by the Free Software
 Foundation; either version 2 of the License,
 or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 See the GNU Lesser General Public License for
 more details.

 You should have received a copy of the GNU Lesser General
 Public License along with this program; if not, write to
 the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

 Linking Engine3 statically or dynamically with other modules
 is making a combined work based on Engine3.
 Thus, the terms and conditions of the GNU Lesser General Public License
 cover the whole combination.

 In addition, as a special exception, the copyright holders of Engine3
 give you permission to combine Engine3 program with free software
 programs or libraries that are released under the GNU LGPL and with
 code included in the standard release of Core3 under the GNU LGPL
 license (or modified versions of such code, with unchanged license).
 You may copy and distribute such a system following the terms of the
 GNU LGPL for Engine3 and the licenses of the other code concerned,
 provided that you include the source code of that other code when
 and as the GNU LGPL requires distribution of source code.

 Note that people who make modified versions of Engine3 are not obligated
 to grant this special exception for their modified versions;
 it is their choice whether to do so. The GNU Lesser General Public License
 gives permission to release a modified version without this exception;
 this exception also makes it possible to release a modified version
 which carries forward this exception.
 */

#include "PlayerObjectMenuComponent.h"
#include "server/zone/objects/scene/components/ObjectMenuComponent.h"
#include "server/zone/packets/object/ObjectMenuResponse.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/objects/group/GroupObject.h"

void PlayerObjectMenuComponent::fillObjectMenuResponse(
		SceneObject* sceneObject, ObjectMenuResponse* menuResponse,
		CreatureObject* player) {
	if (!sceneObject->isCreatureObject())
		return;

	CreatureObject* creature = (CreatureObject*) sceneObject;
	GroupObject* group = creature->getGroup();

	if (group != NULL) {
		if (group->hasMember(player))
			menuResponse->addRadialMenuItem(51, 3, "@sui:teach");
	}

	if (creature->isPlayingMusic()) {
		if (!player->isListening())
			menuResponse->addRadialMenuItem(113, 3,
					"@radial_performance:listen");
		else
			menuResponse->addRadialMenuItem(115, 3,
					"@radial_performance:listen_stop");
	}

	if (creature->isDancing()) {
		if (!player->isWatching())
			menuResponse->addRadialMenuItem(114, 3, "@radial_performance:watch");
		else
			menuResponse->addRadialMenuItem(116, 3,
					"@radial_performance:watch_stop");
	}

}

int PlayerObjectMenuComponent::handleObjectMenuSelect(SceneObject* sceneObject,
		CreatureObject* player, byte selectedID) {
	CreatureObject* ownerPlayer = dynamic_cast<CreatureObject*> (sceneObject);
	PlayerObject* ghost = ownerPlayer->getPlayerObject();

	switch (selectedID) {
	case 113:
		player->executeObjectControllerAction(0x5855BB1B,
				sceneObject->getObjectID(), ""); // listen
		break;
	case 115:
		player->executeObjectControllerAction(0xC2E4D4D0,
				sceneObject->getObjectID(), ""); // stoplistening
		break;

	case 114:
		player->executeObjectControllerAction(0xEC93CA43,
				sceneObject->getObjectID(), ""); // watch
		break;

	case 116:
		player->executeObjectControllerAction(0x6651AD9A,
				sceneObject->getObjectID(), ""); // stopwatching
		break;

	case 51:
		player->executeObjectControllerAction(0x5041F83A,
				sceneObject->getObjectID(), ""); // teach
		break;

	}

	return 0;
}

<|endoftext|>


<commit_before>#include "nodes/node.h"

#include <cmath>
#include <iostream>

#include <QDebug>
#include <QGraphicsDropShadowEffect>

#include "ui/colors.h"
#include "ui/package_view.h"

namespace nodes {

constexpr qreal ICON_OFFSET{ 25.0 };
constexpr QSizeF ICON_SIZE{ 50.0 + ICON_OFFSET, 25.0 + ICON_OFFSET };
constexpr qreal ROUND_FACTOR{ 15.0 };

Node::Node(QGraphicsItem *a_parent)
  : QGraphicsItem{ a_parent }
{
  setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
  //  m_boundingRect = QRectF(QPointF{ 0.0, 0.0 }, ICON_SIZE);

  QGraphicsDropShadowEffect *const effect{ new QGraphicsDropShadowEffect };
  //  effect->setColor(QColor(103, 117, 126, 255));
  QColor color(58, 66, 71, 255); // DARK GREY
  effect->setColor(color);
  //  effect->setOffset(0.0, 0.0);
  //  effect->setBlurRadius(64.0);
  effect->setBlurRadius(15.0);
  effect->setColor(QColor("#99121212"));
  setGraphicsEffect(effect);

  iconify();
}

Node::~Node() {}

QRectF Node::boundingRect() const
{
  return m_boundingRect;
}

void Node::paint(QPainter *a_painter, QStyleOptionGraphicsItem const *a_option, QWidget *a_widget)
{
  (void)a_painter;
  (void)a_option;
  (void)a_widget;

  //  QPen pen{ color };
  QPen pen{ get_color(Color::eSocketBorder) };
  pen.setWidth(2);
  QColor color{ 105, 105, 105, 128 };
  QBrush brush{ color };
  a_painter->setPen(pen);
  a_painter->setBrush(brush);
  a_painter->drawRoundedRect(m_boundingRect, ROUND_FACTOR, ROUND_FACTOR);

  //  pen.setColor(QColor(54, 54, 54, 255));
  //  pen.setColor(isSelected() ? QColor(95, 124, 136, 255) : QColor(58, 66, 71, 255));
  pen.setColor(isSelected() ? QColor(156, 156, 156, 255) : QColor(58, 66, 71, 255));
  pen.setWidth(2);
  a_painter->setPen(pen);
  a_painter->setBrush(Qt::NoBrush);
  a_painter->drawRoundedRect(m_boundingRect, ROUND_FACTOR, ROUND_FACTOR);

  auto size = m_icon.size();
  auto size2 = size / 2.0;

  //  a_painter->translate(m_boundingRect.width() / 2.0 - size.width() / 4.0, m_boundingRect.height() / 2.0 -
  //  size.height() / 4.0); a_painter->drawPixmap(0, 0, size.width() / 2.0, size.height() / 2.0, m_icon);
  auto const x = static_cast<int>(-size2.width() / 2.0);
  auto const y = static_cast<int>(-size2.height() / 2.0);
  auto const w = size2.width();
  auto const h = size2.height();
  a_painter->drawPixmap(x, y, w, h, m_icon);
}

QVariant Node::itemChange(QGraphicsItem::GraphicsItemChange a_change, QVariant const &a_value)
{
  (void)a_change;
  (void)a_value;

  switch (a_change) {
    case QGraphicsItem::ItemPositionChange: {
      if (m_packageView && m_packageView->snapToGrid()) {
        QPointF const position{ a_value.toPointF() };
        qreal const x{ std::round(position.x() / 10.0) * 10.0 };
        qreal const y{ std::round(position.y() / 10.0) * 10.0 };
        return QPointF{ x, y };
      }
      break;
    }
    default: break;
  }

  return QGraphicsItem::itemChange(a_change, a_value);
}

void Node::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *a_event)
{
  (m_mode == Mode::eIconified) ? expand() : iconify();

  QGraphicsItem::mouseDoubleClickEvent(a_event);
}

void Node::setElement(elements::Element *const a_element)
{
  if (m_element) qDebug() << "Already have element!";

  m_element = a_element;

  auto const &inputs = m_element->inputs();
  auto const &outputs = m_element->outputs();

  switch (m_type) {
    case Type::eElement:
      for (size_t i = 0; i < inputs.size(); ++i) {
        QString const name = QString::fromStdString(inputs[i].name);
        addSocket(SocketType::eInput, static_cast<uint8_t>(i), name, inputs[i].type);
      }
      for (size_t i = 0; i < outputs.size(); ++i) {
        QString const name = QString::fromStdString(outputs[i].name);
        addSocket(SocketType::eOutput, static_cast<uint8_t>(i), name, outputs[i].type);
      }
      break;
    case Type::eInputs:
      for (size_t i = 0; i < inputs.size(); ++i) {
        QString const name = QString::fromStdString(inputs[i].name);
        addSocket(SocketType::eOutput, static_cast<uint8_t>(i), name, inputs[i].type);
      }
      break;
    case Type::eOutputs:
      for (size_t i = 0; i < outputs.size(); ++i) {
        QString const name = QString::fromStdString(outputs[i].name);
        addSocket(SocketType::eInput, static_cast<uint8_t>(i), name, outputs[i].type);
      }
      break;
  }

  m_element->onChange([&](elements::Element *const a_changed) {
    auto const &changedOutputs = a_changed->outputs();
    for (size_t i = 0; i < changedOutputs.size(); ++i) {
      switch (changedOutputs[i].type) {
        case ValueType::eBool: {
          bool const signal{ std::get<bool>(changedOutputs[i].value) };
          m_outputs[static_cast<int>(i)]->setSignal(signal);
          break;
        }
        default: break;
      }
    }
  });

  calculateBoundingRect();
}

void Node::setIcon(QString a_icon)
{
  m_icon.load(a_icon);
}

void Node::iconify()
{
  m_mode = Mode::eIconified;

  for (auto &&input : m_inputs) input->hideName();
  for (auto &&output : m_outputs) output->hideName();

  prepareGeometryChange();
  calculateBoundingRect();
}

void Node::expand()
{
  m_mode = Mode::eExpanded;

  for (auto &&input : m_inputs) input->showName();
  for (auto &&output : m_outputs) output->showName();

  prepareGeometryChange();
  calculateBoundingRect();
}

void Node::addSocket(SocketType const a_type, uint8_t const a_id, QString const a_name, ValueType const a_valueType)
{
  auto *const socket{ new SocketItem{ a_type, this } };
  socket->setElementId(m_element->id());
  socket->setSocketId(a_id);

  switch (a_valueType) {
    case ValueType::eBool: socket->setColors(get_color(Color::eBoolSignalOff), get_color(Color::eBoolSignalOn)); break;
    case ValueType::eFloat:
      socket->setColors(get_color(Color::eFloatSignalOff), get_color(Color::eFloatSignalOn));
      break;
    case ValueType::eInt:
      socket->setColors(get_color(Color::eIntegerSignalOff), get_color(Color::eIntegerSignalOn));
      break;
  }

  socket->setName(a_name);
  if (a_type == SocketType::eInput)
    m_inputs.push_back(socket);
  else
    m_outputs.push_back(socket);
}

void Node::calculateBoundingRect()
{
  auto const inputsCount = m_inputs.count();
  auto const outputsCount = m_outputs.count();
  auto const socketsCount = std::max(inputsCount, outputsCount);

  constexpr int32_t const SPACING_ICONIFIED = 5;
  constexpr int32_t const SPACING_EXPANED = 15;
  constexpr int32_t const SOCKET_SIZE = SocketItem::SIZE;
  //  int32_t const horizontalAdjust = 0;

  QSizeF size{};

  int32_t spacing{};
  switch (m_mode) {
    case Mode::eIconified: {
      spacing = SPACING_ICONIFIED;
      if (socketsCount < 2)
        size = ICON_SIZE;
      else {
        size.rwidth() = ICON_SIZE.width();
        size.rheight() = ROUND_FACTOR + ROUND_FACTOR;
        size.rheight() += socketsCount * SOCKET_SIZE + (socketsCount - 1) * spacing;
      }
      break;
    }
    case Mode::eExpanded: {
      spacing = SPACING_EXPANED;
      size = ICON_SIZE;
      size.rheight() += 50;
      size.rwidth() += 100;
      break;
    }
  }

  QRectF const rect{ QPointF{ -size.width() / 2.0, -size.height() / 2.0 }, size };

  auto const inputsHeight = inputsCount * SOCKET_SIZE + (inputsCount - 1) * spacing;
  auto const outputsHeight = outputsCount * SOCKET_SIZE + (outputsCount - 1) * spacing;

  qreal offset{ -inputsHeight / 2.0 };
  for (auto &&input : m_inputs) {
    input->setPos(-rect.width() / 2.0, offset);
    offset += spacing + SOCKET_SIZE;
  }

  offset = -outputsHeight / 2.0;
  for (auto &&output : m_outputs) {
    output->setPos(rect.width() / 2.0, offset);
    offset += spacing + SOCKET_SIZE;
  }

  m_boundingRect = rect;

  update();
}

} // namespace nodes
<commit_msg>Synchronize Node with Element<commit_after>#include "nodes/node.h"

#include <cmath>
#include <iostream>

#include <QDebug>
#include <QGraphicsDropShadowEffect>

#include "elements/package.h"
#include "ui/colors.h"
#include "ui/package_view.h"

namespace nodes {

constexpr qreal ICON_OFFSET{ 25.0 };
constexpr QSizeF ICON_SIZE{ 50.0 + ICON_OFFSET, 25.0 + ICON_OFFSET };
constexpr qreal ROUND_FACTOR{ 15.0 };

Node::Node(QGraphicsItem *a_parent)
  : QGraphicsItem{ a_parent }
{
  setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
  //  m_boundingRect = QRectF(QPointF{ 0.0, 0.0 }, ICON_SIZE);

  QGraphicsDropShadowEffect *const effect{ new QGraphicsDropShadowEffect };
  //  effect->setColor(QColor(103, 117, 126, 255));
  QColor color(58, 66, 71, 255); // DARK GREY
  effect->setColor(color);
  //  effect->setOffset(0.0, 0.0);
  //  effect->setBlurRadius(64.0);
  effect->setBlurRadius(15.0);
  effect->setColor(QColor("#99121212"));
  setGraphicsEffect(effect);

  iconify();
}

Node::~Node() {}

QRectF Node::boundingRect() const
{
  return m_boundingRect;
}

void Node::paint(QPainter *a_painter, QStyleOptionGraphicsItem const *a_option, QWidget *a_widget)
{
  (void)a_painter;
  (void)a_option;
  (void)a_widget;

  //  QPen pen{ color };
  QPen pen{ get_color(Color::eSocketBorder) };
  pen.setWidth(2);
  QColor color{ 105, 105, 105, 128 };
  QBrush brush{ color };
  a_painter->setPen(pen);
  a_painter->setBrush(brush);
  a_painter->drawRoundedRect(m_boundingRect, ROUND_FACTOR, ROUND_FACTOR);

  //  pen.setColor(QColor(54, 54, 54, 255));
  //  pen.setColor(isSelected() ? QColor(95, 124, 136, 255) : QColor(58, 66, 71, 255));
  pen.setColor(isSelected() ? QColor(156, 156, 156, 255) : QColor(58, 66, 71, 255));
  pen.setWidth(2);
  a_painter->setPen(pen);
  a_painter->setBrush(Qt::NoBrush);
  a_painter->drawRoundedRect(m_boundingRect, ROUND_FACTOR, ROUND_FACTOR);

  auto size = m_icon.size();
  auto size2 = size / 2.0;

  //  a_painter->translate(m_boundingRect.width() / 2.0 - size.width() / 4.0, m_boundingRect.height() / 2.0 -
  //  size.height() / 4.0); a_painter->drawPixmap(0, 0, size.width() / 2.0, size.height() / 2.0, m_icon);
  auto const x = static_cast<int>(-size2.width() / 2.0);
  auto const y = static_cast<int>(-size2.height() / 2.0);
  auto const w = size2.width();
  auto const h = size2.height();
  a_painter->drawPixmap(x, y, w, h, m_icon);
}

QVariant Node::itemChange(QGraphicsItem::GraphicsItemChange a_change, QVariant const &a_value)
{
  (void)a_change;
  (void)a_value;

  switch (a_change) {
    case QGraphicsItem::ItemPositionChange: {
      if (m_packageView && m_packageView->snapToGrid()) {
        QPointF const position{ a_value.toPointF() };
        qreal const x{ std::round(position.x() / 10.0) * 10.0 };
        qreal const y{ std::round(position.y() / 10.0) * 10.0 };
        return QPointF{ x, y };
      }
      break;
    }
    case QGraphicsItem::ItemPositionHasChanged: {
      if (m_element) {
        QPointF const position{ a_value.toPointF() };
        switch (m_type) {
          case Type::eElement: m_element->setPosition(position.x(), position.y()); break;
          case Type::eInputs: {
            auto const package = reinterpret_cast<elements::Package *const>(m_element);
            package->setInputsPosition(position.x(), position.y());
            break;
          }
          case Type::eOutputs: {
            auto const package = reinterpret_cast<elements::Package *const>(m_element);
            package->setOutputsPosition(position.x(), position.y());
            break;
          }
        }
      }
      break;
    }
    default: break;
  }

  return QGraphicsItem::itemChange(a_change, a_value);
}

void Node::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *a_event)
{
  (m_mode == Mode::eIconified) ? expand() : iconify();

  QGraphicsItem::mouseDoubleClickEvent(a_event);
}

void Node::setElement(elements::Element *const a_element)
{
  if (m_element) qDebug() << "Already have element!";

  m_element = a_element;

  auto const &inputs = m_element->inputs();
  auto const &outputs = m_element->outputs();

  switch (m_type) {
    case Type::eElement:
      for (size_t i = 0; i < inputs.size(); ++i) {
        QString const name = QString::fromStdString(inputs[i].name);
        addSocket(SocketType::eInput, static_cast<uint8_t>(i), name, inputs[i].type);
      }
      for (size_t i = 0; i < outputs.size(); ++i) {
        QString const name = QString::fromStdString(outputs[i].name);
        addSocket(SocketType::eOutput, static_cast<uint8_t>(i), name, outputs[i].type);
      }
      break;
    case Type::eInputs:
      for (size_t i = 0; i < inputs.size(); ++i) {
        QString const name = QString::fromStdString(inputs[i].name);
        addSocket(SocketType::eOutput, static_cast<uint8_t>(i), name, inputs[i].type);
      }
      break;
    case Type::eOutputs:
      for (size_t i = 0; i < outputs.size(); ++i) {
        QString const name = QString::fromStdString(outputs[i].name);
        addSocket(SocketType::eInput, static_cast<uint8_t>(i), name, outputs[i].type);
      }
      break;
  }

  m_element->onChange([&](elements::Element *const a_changed) {
    auto const &changedOutputs = a_changed->outputs();
    for (size_t i = 0; i < changedOutputs.size(); ++i) {
      switch (changedOutputs[i].type) {
        case ValueType::eBool: {
          bool const signal{ std::get<bool>(changedOutputs[i].value) };
          m_outputs[static_cast<int>(i)]->setSignal(signal);
          break;
        }
        default: break;
      }
    }
  });

  m_element->setPosition(x(), y());
  m_element->iconify(m_mode == Mode::eIconified);

  calculateBoundingRect();
}

void Node::setIcon(QString a_icon)
{
  m_iconPath = a_icon;
  m_icon.load(a_icon);
}

void Node::iconify()
{
  if (m_element) m_element->iconify(true);
  m_mode = Mode::eIconified;

  for (auto &&input : m_inputs) input->hideName();
  for (auto &&output : m_outputs) output->hideName();

  prepareGeometryChange();
  calculateBoundingRect();
}

void Node::expand()
{
  if (m_element) m_element->iconify(false);
  m_mode = Mode::eExpanded;

  for (auto &&input : m_inputs) input->showName();
  for (auto &&output : m_outputs) output->showName();

  prepareGeometryChange();
  calculateBoundingRect();
}

void Node::addSocket(SocketType const a_type, uint8_t const a_id, QString const a_name, ValueType const a_valueType)
{
  auto *const socket{ new SocketItem{ a_type, this } };
  socket->setElementId(m_element->id());
  socket->setSocketId(a_id);

  switch (a_valueType) {
    case ValueType::eBool: socket->setColors(get_color(Color::eBoolSignalOff), get_color(Color::eBoolSignalOn)); break;
    case ValueType::eFloat:
      socket->setColors(get_color(Color::eFloatSignalOff), get_color(Color::eFloatSignalOn));
      break;
    case ValueType::eInt:
      socket->setColors(get_color(Color::eIntegerSignalOff), get_color(Color::eIntegerSignalOn));
      break;
  }

  socket->setName(a_name);
  if (a_type == SocketType::eInput)
    m_inputs.push_back(socket);
  else
    m_outputs.push_back(socket);
}

void Node::calculateBoundingRect()
{
  auto const inputsCount = m_inputs.count();
  auto const outputsCount = m_outputs.count();
  auto const socketsCount = std::max(inputsCount, outputsCount);

  constexpr int32_t const SPACING_ICONIFIED = 5;
  constexpr int32_t const SPACING_EXPANED = 15;
  constexpr int32_t const SOCKET_SIZE = SocketItem::SIZE;
  //  int32_t const horizontalAdjust = 0;

  QSizeF size{};

  int32_t spacing{};
  switch (m_mode) {
    case Mode::eIconified: {
      spacing = SPACING_ICONIFIED;
      if (socketsCount < 2)
        size = ICON_SIZE;
      else {
        size.rwidth() = ICON_SIZE.width();
        size.rheight() = ROUND_FACTOR + ROUND_FACTOR;
        size.rheight() += socketsCount * SOCKET_SIZE + (socketsCount - 1) * spacing;
      }
      break;
    }
    case Mode::eExpanded: {
      spacing = SPACING_EXPANED;
      size = ICON_SIZE;
      size.rheight() += 50;
      size.rwidth() += 100;
      break;
    }
  }

  QRectF const rect{ QPointF{ -size.width() / 2.0, -size.height() / 2.0 }, size };

  auto const inputsHeight = inputsCount * SOCKET_SIZE + (inputsCount - 1) * spacing;
  auto const outputsHeight = outputsCount * SOCKET_SIZE + (outputsCount - 1) * spacing;

  qreal offset{ -inputsHeight / 2.0 };
  for (auto &&input : m_inputs) {
    input->setPos(-rect.width() / 2.0, offset);
    offset += spacing + SOCKET_SIZE;
  }

  offset = -outputsHeight / 2.0;
  for (auto &&output : m_outputs) {
    output->setPos(rect.width() / 2.0, offset);
    offset += spacing + SOCKET_SIZE;
  }

  m_boundingRect = rect;

  update();
}

} // namespace nodes
<|endoftext|>


<commit_before>/*
 * For licensing please refer to the LICENSE.md file
 */

#pragma once

#include <string>
#include <vector>
#include <valarray>
#include <fstream>
#include <map>

namespace neon
{
struct ElementData
{
    ElementData(int numberOfNodes, int numberOfTags, int elementType, int id) :
        tags(numberOfTags, 0),
        nodalConnectivity(numberOfNodes, 0),
        elementType(elementType),
        id(id)
    {
    }
    std::vector<int> tags;
    std::vector<int> nodalConnectivity;
    int elementType;
    int id;
};

struct NodeData
{
    int id;
    std::array<double, 3> coordinates;
};

/*!
 * \class GmshReader
 * \brief Parses Gmsh format and returns the data structures of the mesh
 * in a format for neon to process
 */
class GmshReader
{
public:

    using StringKey = std::string;
    using Value     = std::vector<ElementData>;

public:

    GmshReader(const std::string& fileName);

    ~GmshReader() = default;

    /** Gmsh element numbering scheme */
    enum { LINE2 = 1, TRI3, QUAD4, TETRA4, HEX8, PRISM6, TRI6 = 9, TETRA10 = 11};

    const std::map<StringKey, Value>& mesh() const {return gmshMesh;}

private:

    /**
     * Parse the gmsh file as provided by the filename with the appended file
     * extension (.msh)
     * @param file name of the mesh to open
     * @return true if the read was successful
     */
     bool parse(const std::string& fileName);

    /**
     * Provide a reference to the nodes and dimensions that will be populated
     * with the correct data based on the elementType
     * @param Gmsh element number
     * @return number of nodes per element
     */
    short mapElementData(int elementType);

    /**
     * Check the version of gmsh is support otherwise print out a warning
     * @param gmshVersion
     */
    void checkSupportedGmsh(float gmshVersion);

    void fillMesh();

private:

    std::map<StringKey, Value> gmshMesh;
    std::map<int, std::string> physicalGroupMap;

    std::vector<NodeData> nodeList;

    std::string fileName;   //!< File name of gmsh file
    std::fstream gmshFile;  //!< Hold an object to the file stream

};
}
<commit_msg>Added array include<commit_after>/*
 * For licensing please refer to the LICENSE.md file
 */

#pragma once

#include <string>
#include <vector>
#include <valarray>
#include <array>
#include <fstream>
#include <map>

namespace neon
{
struct ElementData
{
    ElementData(int numberOfNodes, int numberOfTags, int elementType, int id) :
        tags(numberOfTags, 0),
        nodalConnectivity(numberOfNodes, 0),
        elementType(elementType),
        id(id)
    {
    }
    std::vector<int> tags;
    std::vector<int> nodalConnectivity;
    int elementType;
    int id;
};

struct NodeData
{
    int id;
    std::array<double, 3> coordinates;
};

/*!
 * \class GmshReader
 * \brief Parses Gmsh format and returns the data structures of the mesh
 * in a format for neon to process
 */
class GmshReader
{
public:

    using StringKey = std::string;
    using Value     = std::vector<ElementData>;

public:

    GmshReader(const std::string& fileName);

    ~GmshReader() = default;

    /** Gmsh element numbering scheme */
    enum { LINE2 = 1, TRI3, QUAD4, TETRA4, HEX8, PRISM6, TRI6 = 9, TETRA10 = 11};

    const std::map<StringKey, Value>& mesh() const {return gmshMesh;}

private:

    /**
     * Parse the gmsh file as provided by the filename with the appended file
     * extension (.msh)
     * @param file name of the mesh to open
     * @return true if the read was successful
     */
     bool parse(const std::string& fileName);

    /**
     * Provide a reference to the nodes and dimensions that will be populated
     * with the correct data based on the elementType
     * @param Gmsh element number
     * @return number of nodes per element
     */
    short mapElementData(int elementType);

    /**
     * Check the version of gmsh is support otherwise print out a warning
     * @param gmshVersion
     */
    void checkSupportedGmsh(float gmshVersion);

    void fillMesh();

private:

    std::map<StringKey, Value> gmshMesh;
    std::map<int, std::string> physicalGroupMap;

    std::vector<NodeData> nodeList;

    std::string fileName;   //!< File name of gmsh file
    std::fstream gmshFile;  //!< Hold an object to the file stream

};
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 IT+Robotics Srl
// Copyright (c) 2015 Francesco Pretto
// This file is subject to the MIT license

#include "precmp.h"
#include "ITRLogging.h"
#include <fstream>
#include <cstdlib>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/propertyconfigurator.h>
#include "xfactory.h"
#include "xlogger.h"
#include "xlevel.h"

#ifdef __linux__
#include <unistd.h>
#endif

using namespace std;
using namespace ITR;
using namespace log4cxx;
using namespace log4cxx::helpers;

#define ITR_CONFIG_FILE "itr-logging.conf"
#define UPDATE_CONFIG_FILE_DELAY 5000 // 5s

static void replace_all(string &s, const string &search, const string &replace);
static string demangle(const char* name);

// NB: These has to be done before first configuration so the
// log4cxx class loader will work
IMPLEMENT_LOG4CXX_OBJECT(XFactory);
IMPLEMENT_LOG4CXX_OBJECT(XLogger)
IMPLEMENT_LOG4CXX_LEVEL(XLevel)

LoggingInit::LoggingInit()
{
  char * config_file_dir = NULL;
  char * config_file = NULL;
  char * config_file_delay = NULL;

#ifdef _WIN32
  char config_file_dir_[1024] = { 0 };
  char config_file_[1024] = { 0 };
  char config_file_delay_[1024] = { 0 };
  GetEnvironmentVariableA("ITR_LOGGING_CONFIG_FILE_DIR",
    config_file_dir_, sizeof(config_file_dir_));
  GetEnvironmentVariableA("ITR_LOGGING_CONFIG_FILE",
    config_file_, sizeof(config_file_));
  GetEnvironmentVariableA("ITR_LOGGING_CONFIG_FILE_DELAY",
    config_file_delay_, sizeof(config_file_delay_));
  if (strlen(config_file_dir_) != 0)
    config_file_dir = config_file_dir_;
  if (strlen(config_file_) != 0)
    config_file = config_file_;
  if (strlen(config_file_delay_) != 0)
    config_file_delay = config_file_delay_;
#else
  config_file_dir = getenv("ITR_LOGGING_CONFIG_FILE_DIR");
  config_file = getenv("ITR_LOGGING_CONFIG_FILE");
  config_file_delay = getenv("ITR_LOGGING_CONFIG_FILE_DELAY");
#endif

  string configFileDir;

  // TODO Mac and BSD
  char exe[1024];
  memset(exe, 0, sizeof(exe));
#ifdef __linux
  readlink("/proc/self/exe", exe, sizeof(str));
#elif _WIN32
  GetModuleFileNameA(NULL, exe, sizeof(exe));
#endif

  configFileDir = exe;
  configFileDir = configFileDir.substr(0, configFileDir.find_last_of("\\/") + 1);

  string configFile = ITR_CONFIG_FILE;
  long configFileDelay = UPDATE_CONFIG_FILE_DELAY;

  if (config_file_dir != NULL)
  {
    configFileDir = config_file_dir;
    char last = *configFileDir.rbegin();
#ifdef _WIN32
    if (last != '\\')
      configFileDir + '\\';
#else // Unix
    if (last != '/')
      configFileDir + '/';
#endif
  }

  if (config_file != NULL)
    configFile = config_file;

  if (config_file_delay != NULL)
  {
    char *invalid;
    long delay = strtol(config_file_delay, &invalid, 10);
    if (invalid != NULL)
      configFileDelay = delay;
  }

  string configFilePath = configFileDir + configFile;

  PropertyConfigurator::configureAndWatch(configFilePath, configFileDelay);
}

namespace ITR
{
  LoggingInit __LoggingInitObj;

  std::string DemangleTypeName(const char *name)
  {
    return demangle(name);
  }

  class ITRLogger
  {
  private:
    log4cxx::XLoggerPtr p_Logger;
  public:
    ITRLogger(const char *name)
    {
      p_Logger = log4cxx::XLogger::getLogger(name);
    }

    log4cxx::XLoggerPtr & operator->()
    {
      return p_Logger;
    }
  };
}

#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>

struct handle
{
    char* p;
    handle(char* ptr) : p(ptr) { }
    ~handle() { std::free(p); }
};

string demangle(const char* name)
{
  int status = -1;
  handle result( abi::__cxa_demangle(name, NULL, NULL, &status) );

  if (status == 0)
  {
    string type = result.p;
    replace_all(type, "::", ".");
    return type;
  }
  else
  {
    return name;
  }
}

#endif

#ifdef _MSC_VER

std::string demangle(const char* name)
{
  std::string type = name;
  if (type[0] == 'c')
    type = type.substr(6);
  else if (type[0] == 's')
    type = type.substr(7);

  replace_all(type, "::", ".");
  return type;
}

#endif

void replace_all(string &s, const string &search, const string &replace)
{
  for( size_t pos = 0; ; pos += replace.length() )
  {
    // Locate the substring to replace
    pos = s.find( search, pos );
    if( pos == string::npos )
      break;

    // Replace by erasing and inserting
    s.erase( pos, search.length() );
    s.insert( pos, replace );
  }
}

extern "C"
{
  HLOGGER NewITRLogger(const char* name)
  {
    return new ITRLogger(name);
  }

  void FreeITRLogger(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    delete logger;
  }

  void ITRLogVisualization(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_VISUALIZATION_GENERIC((*logger), message, false);
  }

  void ITRLogFlow(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_FLOW_GENERIC((*logger), message, false);
  }

  void ITRLogMoreDetail(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_MOREDETAIL_GENERIC((*logger), message, false);
  }

  void ITRLogDetail(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_DETAIL_GENERIC((*logger), message, false);
  }

  void ITRLogWarn(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_WARN_GENERIC((*logger), message, false);
  }

  void ITRLogError(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_ERROR_GENERIC((*logger), message, false);
  }

  void ITRLogVisualizationForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_VISUALIZATION_FORCED((*logger), message, false);
  }

  void ITRLogFlowForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_FLOW_FORCED((*logger), message, false);
  }

  void ITRLogMoreDetailForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_MOREDETAIL_FORCED((*logger), message, false);
  }

  void ITRLogDetailForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_DETAIL_FORCED((*logger), message, false);
  }

  void ITRLogWarnForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_WARN_FORCED((*logger), message, false);
  }

  void ITRLogErrorForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_ERROR_FORCED((*logger), message, false);
  }

  int ITREnabledVisualization(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_VISUALIZATION_ACTUAL((*logger));
  }

  int ITREnabledFlow(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_FLOW_ACTUAL((*logger));
  }

  int ITREnabledMoreDetail(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_MOREDETAIL_ACTUAL((*logger));
  }

  int ITREnabledDetail(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_DETAIL_ACTUAL((*logger));
  }

  int ITREnabledWarn(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_WARN_ACTUAL((*logger));
  }

  int ITREnabledError(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_ERROR_ACTUAL((*logger));
  }
}
<commit_msg>Fixed linux build<commit_after>// Copyright (c) 2014 IT+Robotics Srl
// Copyright (c) 2015 Francesco Pretto
// This file is subject to the MIT license

#include "precmp.h"
#include "ITRLogging.h"
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/propertyconfigurator.h>
#include "xfactory.h"
#include "xlogger.h"
#include "xlevel.h"

#ifdef __linux__
#include <unistd.h>
#endif

using namespace std;
using namespace ITR;
using namespace log4cxx;
using namespace log4cxx::helpers;

#define ITR_CONFIG_FILE "itr-logging.conf"
#define UPDATE_CONFIG_FILE_DELAY 5000 // 5s

static void replace_all(string &s, const string &search, const string &replace);
static string demangle(const char* name);

// NB: These has to be done before first configuration so the
// log4cxx class loader will work
IMPLEMENT_LOG4CXX_OBJECT(XFactory);
IMPLEMENT_LOG4CXX_OBJECT(XLogger)
IMPLEMENT_LOG4CXX_LEVEL(XLevel)

LoggingInit::LoggingInit()
{
  char * config_file_dir = NULL;
  char * config_file = NULL;
  char * config_file_delay = NULL;

#ifdef _WIN32
  char config_file_dir_[1024] = { 0 };
  char config_file_[1024] = { 0 };
  char config_file_delay_[1024] = { 0 };
  GetEnvironmentVariableA("ITR_LOGGING_CONFIG_FILE_DIR",
    config_file_dir_, sizeof(config_file_dir_));
  GetEnvironmentVariableA("ITR_LOGGING_CONFIG_FILE",
    config_file_, sizeof(config_file_));
  GetEnvironmentVariableA("ITR_LOGGING_CONFIG_FILE_DELAY",
    config_file_delay_, sizeof(config_file_delay_));
  if (strlen(config_file_dir_) != 0)
    config_file_dir = config_file_dir_;
  if (strlen(config_file_) != 0)
    config_file = config_file_;
  if (strlen(config_file_delay_) != 0)
    config_file_delay = config_file_delay_;
#else
  config_file_dir = getenv("ITR_LOGGING_CONFIG_FILE_DIR");
  config_file = getenv("ITR_LOGGING_CONFIG_FILE");
  config_file_delay = getenv("ITR_LOGGING_CONFIG_FILE_DELAY");
#endif

  string configFileDir;

  // TODO Mac and BSD
  char exe[1024];
  memset(exe, 0, sizeof(exe));
#ifdef __linux
  readlink("/proc/self/exe", exe, sizeof(exe));
#elif _WIN32
  GetModuleFileNameA(NULL, exe, sizeof(exe));
#endif

  configFileDir = exe;
  configFileDir = configFileDir.substr(0, configFileDir.find_last_of("\\/") + 1);

  string configFile = ITR_CONFIG_FILE;
  long configFileDelay = UPDATE_CONFIG_FILE_DELAY;

  if (config_file_dir != NULL)
  {
    configFileDir = config_file_dir;
    char last = *configFileDir.rbegin();
#ifdef _WIN32
    if (last != '\\')
      configFileDir + '\\';
#else // Unix
    if (last != '/')
      configFileDir + '/';
#endif
  }

  if (config_file != NULL)
    configFile = config_file;

  if (config_file_delay != NULL)
  {
    char *invalid;
    long delay = strtol(config_file_delay, &invalid, 10);
    if (invalid != NULL)
      configFileDelay = delay;
  }

  string configFilePath = configFileDir + configFile;

  PropertyConfigurator::configureAndWatch(configFilePath, configFileDelay);
}

namespace ITR
{
  LoggingInit __LoggingInitObj;

  std::string DemangleTypeName(const char *name)
  {
    return demangle(name);
  }

  class ITRLogger
  {
  private:
    log4cxx::XLoggerPtr p_Logger;
  public:
    ITRLogger(const char *name)
    {
      p_Logger = log4cxx::XLogger::getLogger(name);
    }

    log4cxx::XLoggerPtr & operator->()
    {
      return p_Logger;
    }
  };
}

#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>

struct handle
{
    char* p;
    handle(char* ptr) : p(ptr) { }
    ~handle() { std::free(p); }
};

string demangle(const char* name)
{
  int status = -1;
  handle result( abi::__cxa_demangle(name, NULL, NULL, &status) );

  if (status == 0)
  {
    string type = result.p;
    replace_all(type, "::", ".");
    return type;
  }
  else
  {
    return name;
  }
}

#endif

#ifdef _MSC_VER

std::string demangle(const char* name)
{
  std::string type = name;
  if (type[0] == 'c')
    type = type.substr(6);
  else if (type[0] == 's')
    type = type.substr(7);

  replace_all(type, "::", ".");
  return type;
}

#endif

void replace_all(string &s, const string &search, const string &replace)
{
  for( size_t pos = 0; ; pos += replace.length() )
  {
    // Locate the substring to replace
    pos = s.find( search, pos );
    if( pos == string::npos )
      break;

    // Replace by erasing and inserting
    s.erase( pos, search.length() );
    s.insert( pos, replace );
  }
}

extern "C"
{
  HLOGGER NewITRLogger(const char* name)
  {
    return new ITRLogger(name);
  }

  void FreeITRLogger(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    delete logger;
  }

  void ITRLogVisualization(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_VISUALIZATION_GENERIC((*logger), message, false);
  }

  void ITRLogFlow(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_FLOW_GENERIC((*logger), message, false);
  }

  void ITRLogMoreDetail(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_MOREDETAIL_GENERIC((*logger), message, false);
  }

  void ITRLogDetail(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_DETAIL_GENERIC((*logger), message, false);
  }

  void ITRLogWarn(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_WARN_GENERIC((*logger), message, false);
  }

  void ITRLogError(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_ERROR_GENERIC((*logger), message, false);
  }

  void ITRLogVisualizationForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_VISUALIZATION_FORCED((*logger), message, false);
  }

  void ITRLogFlowForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_FLOW_FORCED((*logger), message, false);
  }

  void ITRLogMoreDetailForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_MOREDETAIL_FORCED((*logger), message, false);
  }

  void ITRLogDetailForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_DETAIL_FORCED((*logger), message, false);
  }

  void ITRLogWarnForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_WARN_FORCED((*logger), message, false);
  }

  void ITRLogErrorForced(HLOGGER logger_, const char* message)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    __ITR_LOG_ERROR_FORCED((*logger), message, false);
  }

  int ITREnabledVisualization(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_VISUALIZATION_ACTUAL((*logger));
  }

  int ITREnabledFlow(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_FLOW_ACTUAL((*logger));
  }

  int ITREnabledMoreDetail(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_MOREDETAIL_ACTUAL((*logger));
  }

  int ITREnabledDetail(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_DETAIL_ACTUAL((*logger));
  }

  int ITREnabledWarn(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_WARN_ACTUAL((*logger));
  }

  int ITREnabledError(HLOGGER logger_)
  {
    ITRLogger *logger = (ITRLogger *)logger_;
    return __ITR_ENABLED_ERROR_ACTUAL((*logger));
  }
}
<|endoftext|>