/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include #include #include #include "core/path_kdtree.h" #include "core/geometry.h" #include "log/log.h" #include "core/renderer_toolbox.h" using namespace GS; using namespace GS::Core; using GS::Render::Renderer; PathKdtree::KDTreeNode::KDTreeNode():m_KDTREE_NODE_ID_SEGMENT(NULL){ memset(m_KDTREE_NODE_ID_ROPE, -1, sizeof(int)*6);}; #define KDTREE_MAX_DEPTH 20 #define KDTREE_MAX_POLY_PER_NODE 5 void PathKdtree::DrawKdtreeNode(Renderer &render, int _CurrentNode, Matrix4& m) { MinMax min_max; min_max.mn.x = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_LEFT]; min_max.mn.y = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_BOTTOM]; min_max.mn.z = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_BACK]; min_max.mx.x = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_RIGHT]; min_max.mx.y = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_TOP]; min_max.mx.z = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_FRONT]; min_max.mn = min_max.mn*m; min_max.mx = min_max.mx*m; RendererToolbox::DrawAABB(render, min_max); if(!m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF) { DrawKdtreeNode(render, m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT, m); DrawKdtreeNode(render, m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT, m); } } void PathKdtree::draw_scene_debug(Renderer &render, Matrix4& m) { DrawKdtreeNode(render, 0, m); } void PathKdtree::NearestQuadtreeTreeNode(Vector4 p, SharedArrayList &list_segment) //------------------------------------------------------------------------------------------------------------------------ { // go inside the quadtree ArrayList list_id_segment; if(segment_list.GetCount() <= 0) return; int l_CurrentNode = 0; while(!m_NodeTree[l_CurrentNode].m_KDTREE_NODE_IS_LEAF) { switch (m_NodeTree[l_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT) { case KDTREE_X_AXIS: { float l_X = p.x ; if(l_X == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) l_X += 0.001f; if(l_X > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT; else l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT; } break; case KDTREE_Y_AXIS: { float l_Y = p.y ; if(l_Y == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) l_Y += 0.001f; if(l_Y > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT; else l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT; } break; case KDTREE_Z_AXIS: { float l_Z = p.z; if(l_Z == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) l_Z += 0.001f; if(l_Z > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT) l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT; else l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT; } break; } } int* l_TempPntIdSegment = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_SEGMENT; int l_CountSegment = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_COUNT_SEGMENT; for(int i=0; i< l_CountSegment; ++i) { list_segment.Add(segment_list[*l_TempPntIdSegment]); ++l_TempPntIdSegment; } } //------------------------------------------------------------------- void PathKdtree::IncreaseSizeNodeKdtreeBuffer(int _IncreaseSize) //------------------------------------------------------------------- { KDTreeNode* l_tempCopy = new KDTreeNode[m_SizeTree + _IncreaseSize]; memcpy(l_tempCopy, m_NodeTree, sizeof(KDTreeNode)*m_SizeTree); for(int i=0; i= KDTREE_MAX_DEPTH /*|| fabs(l_TempAABB[KDTREE_SIDE_LEFT] - l_TempAABB[KDTREE_SIDE_RIGHT]) < 0.1f || fabs(l_TempAABB[KDTREE_SIDE_BOTTOM] - l_TempAABB[KDTREE_SIDE_TOP]) < 0.1f || fabs(l_TempAABB[KDTREE_SIDE_BACK] - l_TempAABB[KDTREE_SIDE_FRONT]) < 0.1f*/) { // check if there is a minimum of place for all the poly if(m_SizeTree < (_CurrentNode + _CountSegment)) { IncreaseSizeNodeKdtreeBuffer(10000 + _CountSegment); } m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF = true; m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT = -1; m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT = -1; m_NodeTree[_CurrentNode].m_KDTREE_NODE_COUNT_SEGMENT = _CountSegment; m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_SEGMENT = new int[_CountSegment]; memcpy( m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_SEGMENT, _IdSegment, sizeof(int)*_CountSegment); // set the new id to set back ++_CurrentNode; } else { m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF = false; //find the correct split axe X or Z float l_TempValueSplit = 0.0f; int l_CountSegmentOnX = 0; int l_CountSegmentOnZ = 0; // get the middle of the aabb float l_X_MiddleAABB = (l_TempAABB[KDTREE_X_AXIS*2] + l_TempAABB[KDTREE_X_AXIS*2+1])*0.5f; float l_Z_MiddleAABB = (l_TempAABB[KDTREE_Z_AXIS*2] + l_TempAABB[KDTREE_Z_AXIS*2+1])*0.5f; for(int i=0; i<_CountSegment; ++i) { if(segment_list[_IdSegment[i]]->bounding_box.GetCenter().x > l_X_MiddleAABB) ++l_CountSegmentOnX; else --l_CountSegmentOnX; if(segment_list[_IdSegment[i]]->bounding_box.GetCenter().z > l_Z_MiddleAABB) ++l_CountSegmentOnZ; else --l_CountSegmentOnZ; } //set new axis int l_NewAxis; if(Types::Abs(l_CountSegmentOnX) < Types::Abs(l_CountSegmentOnZ)) l_NewAxis = KDTREE_X_AXIS; else l_NewAxis = KDTREE_Z_AXIS; // problem , we need absolutly leaf with some path inside, bad split function, so patch it if((l_NewAxis == KDTREE_X_AXIS && _CountSegment == Types::Abs(l_CountSegmentOnX)) || (l_NewAxis == KDTREE_Z_AXIS && _CountSegment == Types::Abs(l_CountSegmentOnZ))) { CreateNodeKdtree(_CurrentNode, _IdSegment, _CountSegment, _CurrentDepth, true ); return; } // axis check with the length and width float diff_axis_aabb = (l_TempAABB[KDTREE_X_AXIS*2+1] - l_TempAABB[KDTREE_X_AXIS*2]) / (l_TempAABB[KDTREE_Z_AXIS*2+1] - l_TempAABB[KDTREE_Z_AXIS*2]); if(diff_axis_aabb > 1.5) l_NewAxis = KDTREE_X_AXIS; if(diff_axis_aabb < 0.66) l_NewAxis = KDTREE_Z_AXIS; m_NodeTree[_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT = l_NewAxis; // get the middle of the aabb float l_MiddleAABB = (l_TempAABB[l_NewAxis*2] + l_TempAABB[l_NewAxis*2+1])*0.5f; l_TempValueSplit = l_MiddleAABB; m_NodeTree[_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT = l_TempValueSplit; // create the 2 childs // create the 2 child list int l_IdInBigArray; // left node { int l_NewIdChildLeft = _CurrentNode + 1; m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT = l_NewIdChildLeft; // set the new aabb float * l_TempAABBLeftChild = m_NodeTree[l_NewIdChildLeft].m_KDTREE_NODE_AABB; l_TempAABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB; memcpy(l_TempAABBLeftChild, l_TempAABB, sizeof(float)*6); l_TempAABBLeftChild[l_NewAxis*2+1] = l_TempValueSplit; int *l_IdLeftSegmentList = new int [_CountSegment]; int l_IdLeftCount = 0; for(int i=0; i<_CountSegment; ++i) { bool l_Include = false; switch(l_NewAxis) { case KDTREE_X_AXIS: if(segment_list[_IdSegment[i]]->a.x <= l_TempValueSplit || segment_list[_IdSegment[i]]->b.x <= l_TempValueSplit) l_Include = true; break; case KDTREE_Z_AXIS: if(segment_list[_IdSegment[i]]->a.z <= l_TempValueSplit || segment_list[_IdSegment[i]]->b.z <= l_TempValueSplit) l_Include = true; break; } if(l_Include) { l_IdLeftSegmentList[l_IdLeftCount] = _IdSegment[i]; ++l_IdLeftCount; } } // copy the strict minimum, not good, because it's fragment memory, but it's just for the creation { int* l_tempCopy = new int[l_IdLeftCount]; memcpy(l_tempCopy, l_IdLeftSegmentList, sizeof(int)*l_IdLeftCount); delete []l_IdLeftSegmentList; l_IdLeftSegmentList = l_tempCopy; } CreateNodeKdtree(l_NewIdChildLeft, l_IdLeftSegmentList, l_IdLeftCount, _CurrentDepth+1); l_IdInBigArray = l_NewIdChildLeft; delete []l_IdLeftSegmentList; } // right node { if(m_SizeTree < l_IdInBigArray + 3) IncreaseSizeNodeKdtreeBuffer(10000); int l_NewIdChildRight = l_IdInBigArray; m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT = l_NewIdChildRight; // set the new aabb float * l_TempAABBRightChild = m_NodeTree[l_NewIdChildRight].m_KDTREE_NODE_AABB; l_TempAABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB; memcpy(l_TempAABBRightChild, l_TempAABB, sizeof(float)*6); l_TempAABBRightChild[l_NewAxis*2] = l_TempValueSplit; int *l_IdRightSegmentList = new int [_CountSegment]; int l_IdRightCount = 0; for(int i=0; i<_CountSegment; ++i) { bool l_Include = false; switch(l_NewAxis) { case KDTREE_X_AXIS: if(segment_list[_IdSegment[i]]->a.x >= l_TempValueSplit || segment_list[_IdSegment[i]]->b.x >= l_TempValueSplit) l_Include = true; break; case KDTREE_Z_AXIS: if(segment_list[_IdSegment[i]]->a.z >= l_TempValueSplit || segment_list[_IdSegment[i]]->b.z >= l_TempValueSplit) l_Include = true; break; } if(l_Include) { l_IdRightSegmentList[l_IdRightCount] = _IdSegment[i]; ++l_IdRightCount; } } // copy the strict minimum, not good, because it's fragment memory, but it's just for the creation { int* l_tempCopy = new int[l_IdRightCount]; memcpy(l_tempCopy, l_IdRightSegmentList, sizeof(int)*l_IdRightCount); delete []l_IdRightSegmentList; l_IdRightSegmentList = l_tempCopy; } CreateNodeKdtree(l_NewIdChildRight, l_IdRightSegmentList, l_IdRightCount, _CurrentDepth+1); //set the new id for the next node in the stack _CurrentNode = l_NewIdChildRight; delete []l_IdRightSegmentList; } } } //-------------------------------------------------------------------------------- void PathKdtree::BuildQuadtree() //-------------------------------------------------------------------------------- { if(segment_list.GetCount() <= 0) return; //very not powerful kdtree construction m_SizeTree = segment_list.GetCount()*4; m_NodeTree = new KDTreeNode[m_SizeTree]; int m_CurrentNode = 0; m_NodeTree[m_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT = KDTREE_X_AXIS; // find the big bounding box MinMax max_min_max = segment_list[0]->GetBoundingBox(); ArrayListForeachPtr(nMSegment*, segment, segment_list) { max_min_max.Grow(segment->GetBoundingBox()); } max_min_max.mn.y -= 100.0f; max_min_max.mx.y += 100.0f; float * l_TempAABB = m_NodeTree[m_CurrentNode].m_KDTREE_NODE_AABB; l_TempAABB[KDTREE_SIDE_LEFT] = max_min_max.mn.x; l_TempAABB[KDTREE_SIDE_BOTTOM] = max_min_max.mn.y; l_TempAABB[KDTREE_SIDE_BACK] = max_min_max.mn.z; l_TempAABB[KDTREE_SIDE_RIGHT] = max_min_max.mx.x; l_TempAABB[KDTREE_SIDE_TOP] = max_min_max.mx.y; l_TempAABB[KDTREE_SIDE_FRONT] = max_min_max.mx.z; // to build the kdtree: id of the poly int* l_IdSegment = new int[segment_list.GetCount()]; for(uint i=0; i _segment_list) //------------------------------------------------------------------------------------------ { ArrayListForeachPtr(nMSegment*, segment, _segment_list) segment_list.Add(segment); return true; } //--------------------------------------------------- bool PathKdtree::InsideKdTree(const Vector4 &s) //--------------------------------------------------- { if(m_NodeTree[0].m_KDTREE_NODE_AABB[0] <= s.x && s.x <= m_NodeTree[0].m_KDTREE_NODE_AABB[1] && m_NodeTree[0].m_KDTREE_NODE_AABB[2] <= s.y && s.y <= m_NodeTree[0].m_KDTREE_NODE_AABB[3] && m_NodeTree[0].m_KDTREE_NODE_AABB[4] <= s.z && s.z <= m_NodeTree[0].m_KDTREE_NODE_AABB[5] ) return true; else return false; } //----------------------------------------- void PathKdtree::Free() //----------------------------------------- { _safe_delete_array(m_NodeTree); m_count_bih = 0; } PathKdtree::PathKdtree() { m_NodeTree = NULL; m_count_bih = 0; }