void test(const shared_ptr< DistanceOctree< MeshType > > & distanceOctree, const MeshType & mesh, const AABB & domainAABB, Vector3<uint_t> numBlocks) { Vector3<real_t> blockSize(domainAABB.xSize() / real_c(numBlocks[0]), domainAABB.ySize() / real_c(numBlocks[1]), domainAABB.zSize() / real_c(numBlocks[2])); real_t maxError = blockSize.min() / real_t(10); SetupBlockForest setupBlockforest; setupBlockforest.addRootBlockExclusionFunction(F(distanceOctree, maxError)); setupBlockforest.addWorkloadMemorySUIDAssignmentFunction(blockforest::uniformWorkloadAndMemoryAssignment); setupBlockforest.init(domainAABB, numBlocks[0], numBlocks[1], numBlocks[2], false, false, false); WALBERLA_LOG_DEVEL(setupBlockforest.toString()); std::vector< Vector3<real_t> > vertexPositions; vertexPositions.reserve(mesh.n_vertices()); for (auto vIt = mesh.vertices_begin(); vIt != mesh.vertices_end(); ++vIt) { vertexPositions.push_back(toWalberla(mesh.point(*vIt))); } std::vector< const blockforest::SetupBlock* > setupBlocks; setupBlockforest.getBlocks(setupBlocks); // Check wether all vertices are located in allocated blocks std::vector< Vector3<real_t> > uncoveredVertices(vertexPositions); for (auto bIt = setupBlocks.begin(); bIt != setupBlocks.end(); ++bIt) { const AABB & aabb = (*bIt)->getAABB(); uncoveredVertices.erase(std::remove_if(uncoveredVertices.begin(), uncoveredVertices.end(), PointInAABB(aabb)), uncoveredVertices.end()); } WALBERLA_CHECK(uncoveredVertices.empty(), "Not all vertices of the mesh are located in allocated blocks!"); //setupBlockforest.assignAllBlocksToRootProcess(); //setupBlockforest.writeVTKOutput( "setupblockforest" ); }

/// [groupSyntax] bool Triangle::Intersects(const AABB &aabb) const { /** The AABB-Triangle test implementation is based on the pseudo-code in Christer Ericson's Real-Time Collision Detection, pp. 169-172. */ ///@todo The Triangle-AABB intersection test can be greatly optimized by manually unrolling loops, trivial math and by avoiding /// unnecessary copying. float t1, t2, a1, a2; const float3 e[3] = { float3(1,0,0), float3(0,1,0), float3(0,0,1) }; for(int i = 0; i < 3; ++i) { ProjectToAxis(e[i], t1, t2); aabb.ProjectToAxis(e[i], a1, a2); if (!RangesOverlap(t1, t2, a1, a2)) return false; } float3 n = UnnormalizedNormalCCW(); ProjectToAxis(n, t1, t2); aabb.ProjectToAxis(n, a1, a2); if (!RangesOverlap(t1, t2, a1, a2)) return false; const float3 t[3] = { b-a, c-a, c-b }; for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) { float3 axis = Cross(e[i], t[j]); float len = axis.LengthSq(); if (len <= 1e-4f) continue; // Ignore tests on degenerate axes. ProjectToAxis(axis, t1, t2); aabb.ProjectToAxis(axis, a1, a2); if (!RangesOverlap(t1, t2, a1, a2)) return false; } // No separating axis exists, the AABB and triangle intersect. return true; }

void LightFieldCube::read(File *file, size_t head_address, AABB aabb) { file->readInt32BE(&type); file->readInt32BE(&value); point = aabb.center(); if (type != LIBGENS_LIGHTFIELD_CUBE_NO_SPLIT) { left = new LightFieldCube(); right = new LightFieldCube(); file->goToAddress(head_address + LIBGENS_LIGHTFIELD_CUBE_SIZE * value); left->read(file, head_address, aabb.half(type, LIBGENS_MATH_SIDE_LEFT)); file->goToAddress(head_address + LIBGENS_LIGHTFIELD_CUBE_SIZE * (value+1)); right->read(file, head_address, aabb.half(type, LIBGENS_MATH_SIDE_RIGHT)); } else { } }

_Use_decl_annotations_ void BIH::Query(const AABB& test, uint32_t* numTriangles) { *numTriangles = 0; if (!test.Intersects(_bounds)) { return; } Query(test, _root, numTriangles); }

int BroadPhaseBasic::cull_segment(const Vector3& p_from, const Vector3& p_to,CollisionObjectSW** p_results,int p_max_results,int *p_result_indices) { int rc=0; for (Map<ID,Element>::Element *E=element_map.front();E;E=E->next()) { const AABB aabb=E->get().aabb; if (aabb.intersects_segment(p_from,p_to)) { p_results[rc]=E->get().owner; p_result_indices[rc]=E->get().subindex; rc++; if (rc>=p_max_results) break; } } return rc; }

AABB MOFMesh::getBoudingBox() { AABB aabb; Vector3D min; Vector3D max; if(this->m_numMeshes>0) aabb = this->getSubmesh(0)->getBoudingBox(); for(int i=0; i<this->m_numMeshes; ++i) { MOFSubmesh *smesh; smesh = this->getSubmesh(i); AABB sAABB = smesh->getBoudingBox(); aabb.load(sAABB); } return aabb; }

bool cull(const AABB& aabb) const { if (aabb.isNull()) return false; for(unsigned i=0; i<planes().size(); ++i) { if ( plane(i).isOutside(aabb) ) return true; } return false; }

AABB AABB::GetTransformedAABB(const Matrix4x4f &mat) const { AABB transformedAABB; Vec3f newCenter(mat * m_center); transformedAABB.m_lowerBound = newCenter; transformedAABB.m_upperBound = newCenter; // Loop through all corners, transform, and compare for(int x = -1; x <= 1; x += 2) for(int y = -1; y <= 1; y += 2) for(int z = -1; z <= 1; z += 2) { Vec3f corner(x * m_halfDims.x + m_center.x, y * m_halfDims.y + m_center.y, z * m_halfDims.z + m_center.z); // Transform the corner corner = mat * corner; // Compare bounds if(corner.x > transformedAABB.m_upperBound.x) transformedAABB.m_upperBound.x = corner.x; if(corner.y > transformedAABB.m_upperBound.y) transformedAABB.m_upperBound.y = corner.y; if(corner.z > transformedAABB.m_upperBound.z) transformedAABB.m_upperBound.z = corner.z; if(corner.x < transformedAABB.m_lowerBound.x) transformedAABB.m_lowerBound.x = corner.x; if(corner.y < transformedAABB.m_lowerBound.y) transformedAABB.m_lowerBound.y = corner.y; if(corner.z < transformedAABB.m_lowerBound.z) transformedAABB.m_lowerBound.z = corner.z; } // Move from local into world space transformedAABB.CalculateHalfDims(); transformedAABB.CalculateCenter(); return transformedAABB; }

/// NOTE: Expects @param nodes to be a link list along the left child AABB::AABB(AABB *nodes) : left(0), right(0), move(0) { if (!nodes) return; // Compute bounds unsigned count = 0; for (AABB *it = nodes; it; it = it->left) { if (it->right) THROW("Unexpected right-hand AABB node"); add(*it); count++; } // Degenerate cases if (count < 3) { if (count == 2) right = nodes->left; left = nodes->prepend(0); return; } // Decide split unsigned axis = getDimensions().findLargest(); real cut = getMax()[axis] + getMin()[axis]; // Partition nodes AABB *lessThan = 0; AABB *greaterThan = 0; unsigned lessCount = 0; unsigned greaterCount = 0; for (AABB *it = nodes; it;) { AABB *next = it->left; bool less = it->getMax()[axis] + it->getMin()[axis] < cut; if (less) {lessThan = it->prepend(lessThan); lessCount++;} else {greaterThan = it->prepend(greaterThan); greaterCount++;} it = next; } // Check for bad partition if (!lessThan) lessThan = greaterThan->split(greaterCount / 2); if (!greaterThan) greaterThan = lessThan->split(lessCount / 2); // Recur left = new AABB(lessThan); right = new AABB(greaterThan); }

void Mesh::add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes,bool p_alphasort) { ERR_FAIL_COND(p_arrays.size()!=ARRAY_MAX); Surface s; VisualServer::get_singleton()->mesh_add_surface(mesh,(VisualServer::PrimitiveType)p_primitive, p_arrays,p_blend_shapes,p_alphasort); surfaces.push_back(s); /* make aABB? */ { DVector<Vector3> vertices=p_arrays[ARRAY_VERTEX]; int len=vertices.size(); ERR_FAIL_COND(len==0); DVector<Vector3>::Read r=vertices.read(); const Vector3 *vtx=r.ptr(); // check AABB AABB aabb; for (int i=0;i<len;i++) { if (i==0) aabb.pos=vtx[i]; else aabb.expand_to(vtx[i]); } surfaces[surfaces.size()-1].aabb=aabb; surfaces[surfaces.size()-1].alphasort=p_alphasort; _recompute_aabb(); } triangle_mesh=Ref<TriangleMesh>(); _change_notify(); }

/** * @return The axis-aligned bounding box (AABB) of the body in world-space coordinates */ AABB CollisionBody::getAABB() const { AABB bodyAABB; if (mProxyCollisionShapes == NULL) return bodyAABB; mProxyCollisionShapes->getCollisionShape()->computeAABB(bodyAABB, mTransform * mProxyCollisionShapes->getLocalToBodyTransform()); // For each proxy shape of the body for (ProxyShape* shape = mProxyCollisionShapes->mNext; shape != NULL; shape = shape->mNext) { // Compute the world-space AABB of the collision shape AABB aabb; shape->getCollisionShape()->computeAABB(aabb, mTransform * shape->getLocalToBodyTransform()); // Merge the proxy shape AABB with the current body AABB bodyAABB.mergeWithAABB(aabb); } return bodyAABB; }

bool World::overlapsCollidableTiles(int centerX, int centerY, int nodeWidth, int nodeHeight) { vector<WorldLayer*>::iterator it = layers->begin(); while (it != layers->end()) { WorldLayer *layer = (*it); if (layer->hasCollidableTiles()) { AABB aabb; aabb.setCenterX((float)centerX); aabb.setCenterY((float)centerY); aabb.setWidth((float)nodeWidth); aabb.setHeight((float)nodeHeight); bool overlaps = layer->overlapsCollidableTile(aabb); if (overlaps) return true; } it++; } return false; }

bool CScene::CollisionCheck( CGameObject *pObj1, CGameObject *pObj2 ) { // 충돌되면 true 반환 AABB playerBox = pObj1->m_bcMeshBoundingCube; AABB objBox = pObj2->m_bcMeshBoundingCube; // AABB를 해당 오브젝트에 맞게 변환 -> 물체를 생성할 때 위치를 잡고나면 update하지 않아도 되야 하는데 자꾸 초기화됨 playerBox.Update( &( pObj1->m_mtxWorld ) ); objBox.Update( &( pObj2->m_mtxWorld ) ); // AABB 출돌 검사 if (playerBox.m_vMax.x < objBox.m_vMin.x) return true; if (playerBox.m_vMax.y < objBox.m_vMin.y) return true; if (playerBox.m_vMax.z < objBox.m_vMin.z) return true; if (playerBox.m_vMin.x > objBox.m_vMax.x) return true; if (playerBox.m_vMin.y > objBox.m_vMax.y) return true; if (playerBox.m_vMin.z > objBox.m_vMax.z) return true; // 아무런 체크도 되지 않으면 충돌하지 않은 것 return false; }

pair<double, SplitSide> SAH(SplitPlane plane, AABB box, int left, int right, int planar) { pair<AABB, AABB> boxes = box.split(plane); double area = surfaceArea(box); double ratioLeft = surfaceArea(boxes.first) / area; double ratioRight = surfaceArea(boxes.second) / area; double costLeft = cost(ratioLeft, ratioRight, left + planar, right); double costRight = cost(ratioLeft, ratioRight, left, planar + right); if (costLeft < costRight) return make_pair(costLeft, LEFT); else return make_pair(costRight, RIGHT); }

/// Determines whether a point is outside of a AABB bool AABB::outside(const AABB& a, const Point3d& point, double tol) { const unsigned THREE_D = 3; assert(a.get_relative_pose() == point.pose); for (unsigned i=0; i< THREE_D; i++) if (point[i] < a.minp[i] - tol || point[i] > a.maxp[i] + tol) return true; return false; }

AABB AnimatedTransform::getSpatialBounds(const AABB &aabb) const { AABB result; if (m_tracks.size() == 0) { for (int j=0; j<8; ++j) result.expandBy(m_transform(aabb.getCorner(j))); } else { /* Compute approximate bounds */ int nSteps = 100; AABB1 timeBounds = getTimeBounds(); Float step = timeBounds.getExtents().x / (nSteps-1); for (int i=0; i<nSteps; ++i) { const Transform &trafo = eval(timeBounds.min.x + step * i); for (int j=0; j<8; ++j) result.expandBy(trafo(aabb.getCorner(j))); } } return result; }

void PUBaseCollider::populateAlignedBox( AABB& box, const Vec3& position, const float width, const float height, const float depth ) { float halfWidth = 0.5f * width; float halfHeight = 0.5f * height; float halfDepth = 0.5f * depth; box.set(Vec3(position.x - halfWidth, position.y - halfHeight, position.z - halfDepth), Vec3(position.x + halfWidth, position.y + halfHeight, position.z + halfDepth)); }

AABB Mesh::generateBoundingAABB() const { AABB bounds; if (vertices.empty()) return bounds; vec3 minimum(std::numeric_limits<float>::max()); vec3 maximum(std::numeric_limits<float>::min()); for (auto& v : vertices) { minimum = min(minimum, v.position); maximum = max(maximum, v.position); } bounds.setBounds(minimum.x, minimum.y, minimum.z, maximum.x, maximum.y, maximum.z); return bounds; }

//============================================================================= // AABB同士の当たり判定 //============================================================================= bool CCollisionManager::JudgeAABBCross( const VECTOR3& p1, const AABB& b1, const VECTOR3& p2, const AABB& b2) { VECTOR3 min_pos1; VECTOR3 min_pos2; min_pos1._x = p1._x + b1.Min._x; min_pos1._y = p1._y + b1.Min._y; min_pos1._z = p1._z + b1.Min._z; min_pos2._x = p2._x + b2.Min._x; min_pos2._y = p2._y + b2.Min._y; min_pos2._z = p2._z + b2.Min._z; bool bHitX = min_pos1._x <= min_pos2._x + b2.width() && min_pos1._x >= min_pos2._x - b1.width(); bool bHitY = min_pos1._y <= min_pos2._y + b2.height() && min_pos1._y >= min_pos2._y - b1.height(); bool bHitZ = min_pos1._z <= min_pos2._z + b2.depth() && min_pos1._z >= min_pos2._z - b1.depth(); if(!bHitX || !bHitY || !bHitZ) { return false; } return true; }

bool AABB::CheckCollision(AABB otherBox) { // // b0--------b1 // | | // a0---|----a1 | // | | | | // | b3--------b2 // | | // | | // a3--------a2 // // (a0.x is less than b1.x and a1.x is greater than b0.x) collided in x axis // (a0.y is less than b3.y and a3.y is greater than b0.y) collided in y axis // if ((_x < otherBox.GetX() + otherBox.GetWidth() && _x + _width > otherBox.GetX()) && (_y < otherBox.GetY() + otherBox.GetHeight() && _y + _height > otherBox.GetY())) { // we collided return true; } else { return false; } }

bool Ray::intersectAABB(const AABB &aabb) const { Vector3d dirFrac; dirFrac.x() = 1.0f / _direction.x(); dirFrac.y() = 1.0f / _direction.y(); dirFrac.z() = 1.0f / _direction.z(); float t1 = (aabb.getMin().x() - _origin.x()) * dirFrac.x(); float t2 = (aabb.getMax().x() - _origin.x()) * dirFrac.x(); float t3 = (aabb.getMin().y() - _origin.y()) * dirFrac.y(); float t4 = (aabb.getMax().y() - _origin.y()) * dirFrac.y(); float t5 = (aabb.getMin().z() - _origin.z()) * dirFrac.z(); float t6 = (aabb.getMax().z() - _origin.z()) * dirFrac.z(); float tMin = MAX(MAX(MIN(t1, t2), MIN(t3, t4)), MIN(t5, t6)); float tMax = MIN(MIN(MAX(t1, t2), MAX(t3, t4)), MAX(t5, t6)); // If tMax < 0, the ray is intersecting the AABB, but the whole AABB is in the opposite direction if (tMax < 0) { return false; } // If tMin > tMax, the ray doesn't intersect the AABB if (tMin > tMax) { return false; } return true; }

bool VolMeshIO::fitmesh(VolMesh* vm, const AABB& toBox) { if(!toBox.isValid()) return false; AABB curBox = vm->computeAABB(); vec3f s = vec3f::div(toBox.extent(), curBox.extent()); double minScaleFactor = MATHMIN(MATHMIN(s.x, s.y), s.z); vec3d scale(minScaleFactor); vec3f t = toBox.lower() - curBox.lower(); vec3d translate(t.x, t.y, t.z); //first translate all nodes for(U32 i=0; i < vm->countNodes(); i++) { NODE& p = vm->nodeAt(i); //translate p.pos = p.pos + translate; p.restpos = p.restpos + translate; //scale p.pos = p.pos * minScaleFactor; p.restpos = p.restpos * minScaleFactor; } return true; }

CollisionData iTest(const AABB & rect, const Circle & circle) { CollisionData cd = { false, 0, 0, 0 }; cd.pointOfContact = { clamp(circle.pos.x, rect.min().x, rect.max().x), clamp(circle.pos.y, rect.min().y, rect.max().y) }; if (cd.pointOfContact == circle.pos) { float dX = (cd.pointOfContact.x - rect.min().x < rect.max().x - cd.pointOfContact.x) ? rect.min().x : rect.max().x; float dY = (cd.pointOfContact.y - rect.min().y < rect.max().y - cd.pointOfContact.y) ? rect.min().y : rect.max().y; if (abs(dX - cd.pointOfContact.x) < abs(dY - cd.pointOfContact.y)) cd.pointOfContact.x = dX; else cd.pointOfContact.y = dY; } float dist = pow(circle.pos.x - cd.pointOfContact.x, 2) + pow(circle.pos.y - cd.pointOfContact.y, 2); float radius = pow(circle.radius, 2); cd.penetrationDepth = radius - dist; if (dist < radius) cd.inOverlap = true; cd.collisionNormal = (circle.pos - cd.pointOfContact).normal(); return cd; }

AABB operator*(const Mat3 &m, const AABB &a) { Vec2 omin = a.min(); Vec2 omax = a.max(); Vec2 rmin = m[2].xy; Vec2 rmax = m[2].xy; float p, q; for (unsigned j = 0; j < 2; ++j) for (unsigned i = 0; i < 2; ++i) { p = omin[i] * m[i][j]; q = omax[i] * m[i][j]; if (p < q) std::swap(p, q); rmin[j] += p; rmax[j] += q; } return{ (rmin + rmax) / 2, (rmin - rmax) / 2 }; }

Frustum::IntersectResult Frustum::intersectAABB(const AABB& aabb) const { IntersectResult result = IntersectResult::INSIDE; int indexFirst = static_cast<int>(FrustumPlane::FRUSTUM_NEAR); int indexNumber = static_cast<int>(FrustumPlane::FRUSTUM_NUMBER); for(int planeIndex = indexFirst; planeIndex < indexNumber; ++planeIndex) { kmPlane plane = _frustumPlanes[static_cast<FrustumPlane>(planeIndex)]; kmVec3 normal = {plane.a, plane.b, plane.c}; kmVec3Normalize(&normal, &normal); kmVec3 positivePoint = aabb.getPositivePoint(normal); kmVec3 negativePoint = aabb.getNegativePoint(normal); if(kmPlaneDotCoord(&plane, &positivePoint) < 0) return IntersectResult::OUTSIDE; if(kmPlaneDotCoord(&plane, &negativePoint) < 0) result = IntersectResult::INTERSECT; } return result; }

Vec3 GetTargetPos( SActivationInfo* pActInfo ) { EntityId targetId = GetPortEntityId(pActInfo, IN_TARGETID); Vec3 targetPos(0,0,0); if (targetId) { IEntity* pTarget = gEnv->pEntitySystem->GetEntity(targetId); if (pTarget) { AABB box; pTarget->GetWorldBounds(box); targetPos = box.GetCenter(); } } else { targetPos = GetPortVec3(pActInfo, IN_TARGETPOS); } return targetPos; }

int Frustum::boxInFrustum(const AABB& bbox) { int result = INSIDE; for(unsigned int i=0; i<PLANECOUNT; i++) { if(planes[i]->isBehind(bbox.positiveVertex(planes[i]->normal))) { return OUTSIDE; } } return result; }

/** * @sa ProcessModels */ static void ProcessSubModel (int entityNum) { const entity_t* e; int start, end; tree_t* tree; bspbrush_t* list; AABB aabb; BeginModel(entityNum); e = &entities[entityNum]; #if 0 Com_Printf("Processing entity: %i into model %i (%s:%s)\n", entityNum, curTile->nummodels, e->epairs->key, e->epairs->value); #endif start = e->firstbrush; end = start + e->numbrushes; aabb.reset(); aabb.expand(MAX_WORLD_WIDTH); /* every level (-1) */ list = MakeBspBrushList(start, end, -1, aabb); if (!config.nocsg) list = ChopBrushes(list); tree = BuildTree(list, aabb.mins, aabb.maxs); assert(tree); assert(tree->headnode); if (tree->headnode->planenum == PLANENUM_LEAF) Sys_Error("No head node bmodel of %s (%i)\n", ValueForKey(e, "classname"), entityNum); MakeTreePortals(tree); MarkVisibleSides(tree, start, end); MakeFaces(tree->headnode); FixTjuncs(tree->headnode); curTile->models[curTile->nummodels].headnode = WriteBSP(tree->headnode); FreeTree(tree); EndModel(); }

void Flunence2ParticleProcess::init(Float emitterArea, const AABB &volumeAABB, const Vector3u &volumeReso) { switch ( m_emitterMode ) { case Fluence2ParticleTracer::EMITTER_AREA: m_surfScale = 1.0f/(emitterArea*M_PI*static_cast<Float>(m_workCount)); //m_volScale = static_cast<Float>(volumeReso.x*volumeReso.y*volumeReso.z)/ // (static_cast<Float>(m_workCount)*volumeAABB.getVolume()); m_volScale = static_cast<Float>(volumeReso.x*volumeReso.y*volumeReso.z)/ (emitterArea*M_PI*static_cast<Float>(m_workCount)*volumeAABB.getVolume()); break; case Fluence2ParticleTracer::EMITTER_POINT: m_surfScale = 1.0f/static_cast<Float>(m_workCount); m_volScale = static_cast<Float>(volumeReso.x*volumeReso.y*volumeReso.z)/ (static_cast<Float>(m_workCount)*volumeAABB.getVolume()); break; default: m_surfScale = m_volScale = 1.0f; } }

_Use_decl_annotations_ void BIH::Query(const AABB& test, uint32_t nodeIndex, uint32_t* numTriangles) { Node& node = _nodes[nodeIndex]; if (node.Axis == 3) { // Leaf *numTriangles += node.NumTriangles; } else { if (*(&test.GetMin().x + node.Axis) < node.Max) { Query(test, nodeIndex + 1, numTriangles); } if (*(&test.GetMax().x + node.Axis) > node.Min) { Query(test, node.MaxNode, numTriangles); } } }