00001 #include "PKDNode.h"
00002
00003 using namespace std;
00004
00005 namespace rcrt{
00006
00007 PKDNode::PKDNode(std::list<PKDSplitPlane*>* splits, const float& maxRadius, const AABB& bbox )
00008 {
00009 if(splits->size() == 3){
00010
00011
00012 children[0] = 0;
00013 children[1] = 0;
00014 photon = splits->back()->p;
00015 splitAxis = splits->back()->axis;
00016
00017 for(list<PKDSplitPlane* >::iterator iter = splits->begin(); iter != splits->end(); ++iter){
00018 delete (*iter);
00019 }
00020 delete splits;
00021 return;
00022 }
00023
00024
00025
00026
00027
00028
00029 const int N = splits->size() / 3;
00030 int N_l[3] = {0,0,0};
00031 int N_r[3] = {N-1,N-1,N-1};
00032 const Point3D& bMin(bbox.getMinP());
00033 const Point3D& bMax(bbox.getMaxP());
00034 PKDSplitPlane* bestSplit = 0;
00035 float Cmin = numeric_limits<float>::infinity();
00036
00037 for(list<PKDSplitPlane* >::const_iterator iter = splits->begin(); iter != splits->end(); ++iter){
00038 PKDSplitPlane* split = *iter;
00039 const Axis splitAxis = split->axis;
00040 const float& pos = split->p->getPos()[splitAxis];
00041
00042 float cost = 0;
00043
00044 if(N_l[splitAxis] != 0){
00045
00046 float V_l = 1;
00047 for(int k = 0; k < 3; k++){
00048 if(k == splitAxis)
00049
00050 V_l *= (pos-bMin[splitAxis] + 2 * maxRadius);
00051 else
00052 V_l *= (bMax[k]-bMin[k] + 2 * maxRadius);
00053 }
00054 cost += V_l * N_l[splitAxis];
00055 }
00056
00057 if(N_r[splitAxis] != 0){
00058
00059 float V_r = 1;
00060 for(int k = 0; k < 3; k++){
00061 if(k == splitAxis)
00062
00063 V_r *= (bMax[splitAxis] - pos + 2 * maxRadius);
00064 else
00065 V_r *= (bMax[k]-bMin[k] + 2 * maxRadius);
00066 }
00067 cost += V_r * N_r[splitAxis];
00068 }
00069
00070 if(cost < Cmin){
00071 Cmin = cost;
00072 bestSplit = split;
00073 }
00074
00075
00076 N_l[splitAxis]++;
00077 N_r[splitAxis]--;
00078 }
00079
00080
00081 std::list<PKDSplitPlane* >* leftList = new std::list<PKDSplitPlane* >();
00082 std::list<PKDSplitPlane* >* rightList = new std::list<PKDSplitPlane* >();
00083
00084
00085 photon = bestSplit->p;
00086 splitAxis = bestSplit->axis;
00087
00088
00089 AABB leftBox;
00090 AABB rightBox;
00091
00092
00093 const float splitValue = photon->getPos()[splitAxis];
00094 for(list<PKDSplitPlane* >::const_iterator iter = splits->begin(); iter != splits->end(); ++iter){
00095 PKDSplitPlane* split = *iter;
00096
00097 if(split->p == photon)
00098 continue;
00099
00100
00101 if(split->p->getPos()[splitAxis] < splitValue){
00102 leftList->push_back(split);
00103
00104 leftBox.extend(split->p->getPos());
00105 }else{
00106 rightList->push_back(split);
00107 rightBox.extend(split->p->getPos());
00108 }
00109 }
00110
00111 delete splits;
00112
00113
00114 if(leftList->size() != 0)
00115 children[0] = new PKDNode(leftList, maxRadius, leftBox);
00116 else
00117 children[0] = 0;
00118
00119 if(rightList->size() != 0)
00120 children[1] = new PKDNode(rightList, maxRadius, rightBox);
00121 else
00122 children[1] = 0;
00123 }
00124
00125 PKDNode::~PKDNode()
00126 {
00127 if(children[0]) delete children[0];
00128 if(children[1]) delete children[1];
00129 }
00130
00131 bool PKDNode::isLeaf() const
00132 {
00133 return children[0] == 0 && children[1] == 0;
00134 }
00135
00136 void PKDNode::getKNearest(std::vector<PKDSearchP>* result, const unsigned int& k,
00137 const Point3D& pos, const Vec3D& normal, const float& maxRadiusSqr,
00138 const float& flat) const
00139 {
00140 const Point3D& pPos(photon->getPos());
00141 const float dx(pPos[0]-pos[0]);
00142 const float dy(pPos[1]-pos[1]);
00143 const float dz(pPos[2]-pos[2]);
00144 float distSqr(dx*dx+dy*dy+dz*dz);
00145 if(flat != 0){
00146 const float dotP(normal * (pPos - pos));
00147 const float ellipse(dotP * distSqr * 16 * flat);
00148 distSqr += ellipse;
00149 }
00150
00151 float newMaxRadiusSqr = maxRadiusSqr;
00152 if(distSqr < maxRadiusSqr && normal * photon->getDir() < 0){
00153
00154
00155 if(result->size() == k-1){
00156
00157 result->push_back(PKDSearchP(photon, distSqr));
00158 make_heap(result->begin(), result->end());
00159
00160
00161 newMaxRadiusSqr = result->front().distSqr;
00162 }
00163 else if(result->size() >= k){
00164
00165
00166 if(distSqr < result->front().distSqr) {
00167
00168 pop_heap(result->begin(), result->end());
00169 result->pop_back();
00170 result->push_back(PKDSearchP(photon, distSqr));
00171 push_heap(result->begin(), result->end());
00172 }
00173 newMaxRadiusSqr = result->front().distSqr;
00174 } else {
00175
00176 result->push_back(PKDSearchP(photon, distSqr));
00177
00178 }
00179
00180 }
00181
00182 if(!isLeaf()){
00183 const float dist1D = pPos[splitAxis]-pos[splitAxis];
00184 int near = (dist1D > 0) ? 0 : 1;
00185
00186 if(children[near] != 0)
00187 children[near]->getKNearest(result, k, pos, normal, newMaxRadiusSqr, flat);
00188
00189 if(dist1D*dist1D <= newMaxRadiusSqr)
00190 if(children[1-near] != 0)
00191 children[1-near]->getKNearest(result, k, pos, normal, newMaxRadiusSqr, flat);
00192 }
00193 }
00194
00195 }