static void ClipPolygon(PODVector<DecalVertex>& dest, const PODVector<DecalVertex>& src, const Plane& plane, bool skinned) { unsigned last = 0; float lastDistance = 0.0f; dest.Clear(); if (src.Empty()) return; for (unsigned i = 0; i < src.Size(); ++i) { float distance = plane.Distance(src[i].position_); if (distance >= 0.0f) { if (lastDistance < 0.0f) dest.Push(ClipEdge(src[last], src[i], lastDistance, distance, skinned)); dest.Push(src[i]); } else { if (lastDistance >= 0.0f && i != 0) dest.Push(ClipEdge(src[last], src[i], lastDistance, distance, skinned)); } last = i; lastDistance = distance; } // Recheck the distances of the last and first vertices and add the final clipped vertex if applicable float distance = plane.Distance(src[0].position_); if ((lastDistance < 0.0f && distance >= 0.0f) || (lastDistance >= 0.0f && distance < 0.0f)) dest.Push(ClipEdge(src[last], src[0], lastDistance, distance, skinned)); }
static sdword VPlaneSideEps(const Point& v, const Plane& plane, float epsilon) { // Compute distance from current vertex to the plane float Dist = plane.Distance(v); // Compute side: // 1 = the vertex is on the positive side of the plane // -1 = the vertex is on the negative side of the plane // 0 = the vertex is on the plane (within epsilon) return Dist > epsilon ? 1 : Dist < -epsilon ? -1 : 0; }
void Render(MeshIndex*& pindex, HVector& vec) { if (m_plane.Distance(vec) >= 0) { m_pback->Render(pindex, vec); m_pfront->Render(pindex, vec); } else { m_pfront->Render(pindex, vec); m_pback->Render(pindex, vec); } }
bool Polygon::IsPlanar(float epsilon) const { if (p.empty()) return false; if (p.size() <= 3) return true; Plane plane = PlaneCCW(); for(size_t i = 3; i < p.size(); ++i) if (plane.Distance(p[i]) > epsilon) return false; return true; }
bool Polygon::Contains(const LineSegment &worldSpaceLineSegment, float polygonThickness) const { if (p.size() < 3) return false; Plane plane = PlaneCCW(); if (plane.Distance(worldSpaceLineSegment.a) > polygonThickness || plane.Distance(worldSpaceLineSegment.b) > polygonThickness) return false; // For robustness, project onto the polygon plane. LineSegment l = plane.Project(worldSpaceLineSegment); if (!Contains(l.a) || !Contains(l.b)) return false; for(int i = 0; i < (int)p.size(); ++i) if (plane.Project(Edge(i)).Intersects(l)) return false; return true; }
bool Polyhedron::FacesAreNondegeneratePlanar(float epsilon) const { for(int i = 0; i < (int)f.size(); ++i) { const Face &face = f[i]; if (face.v.size() < 3) return false; if (face.v.size() >= 4) { Plane facePlane = FacePlane(i); for(int j = 0; j < (int)face.v.size(); ++j) if (facePlane.Distance(v[face.v[j]]) > epsilon) return false; } } return true; }
float float3::Distance(const Plane &rhs) const { return rhs.Distance(*this); }
float Sphere::Distance(const Plane &plane) const { return plane.Distance(*this); }
float Capsule::Distance(const Plane &plane) const { return plane.Distance(*this); }
void Polyhedron::Clip(const Plane& plane, Vector<Vector3>& clippedVertices, Vector<Vector3>& outFace) { clippedVertices.Clear(); for (size_t i = 0; i < faces.Size(); ++i) { Vector<Vector3>& face = faces[i]; Vector3 lastVertex; float lastDistance = 0.0f; outFace.Clear(); for (size_t j = 0; j < face.Size(); ++j) { float distance = plane.Distance(face[j]); if (distance >= 0.0f) { if (lastDistance < 0.0f) { float t = lastDistance / (lastDistance - distance); Vector3 clippedVertex = lastVertex + t * (face[j] - lastVertex); outFace.Push(clippedVertex); clippedVertices.Push(clippedVertex); } outFace.Push(face[j]); } else { if (lastDistance >= 0.0f && j != 0) { float t = lastDistance / (lastDistance - distance); Vector3 clippedVertex = lastVertex + t * (face[j] - lastVertex); outFace.Push(clippedVertex); clippedVertices.Push(clippedVertex); } } lastVertex = face[j]; lastDistance = distance; } // Recheck the distances of the last and first vertices and add the final clipped vertex if applicable float distance = plane.Distance(face[0]); if ((lastDistance < 0.0f && distance >= 0.0f) || (lastDistance >= 0.0f && distance < 0.0f)) { float t = lastDistance / (lastDistance - distance); Vector3 clippedVertex = lastVertex + t * (face[0] - lastVertex); outFace.Push(clippedVertex); clippedVertices.Push(clippedVertex); } // Do not keep faces which are less than triangles if (outFace.Size() < 3) outFace.Clear(); face = outFace; } // Remove empty faces for (size_t i = faces.Size() - 1; i < faces.Size(); --i) { if (faces[i].IsEmpty()) faces.Erase(i); } // Create a new face from the clipped vertices. First remove duplicates for (size_t i = 0; i < clippedVertices.Size(); ++i) { for (size_t j = clippedVertices.Size() - 1; j > i; --j) { if (clippedVertices[j].Equals(clippedVertices[i])) clippedVertices.Erase(j); } } if (clippedVertices.Size() > 3) { outFace.Clear(); // Start with the first vertex outFace.Push(clippedVertices.Front()); clippedVertices.Erase(0); while (!clippedVertices.IsEmpty()) { // Then add the vertex which is closest to the last added const Vector3& lastAdded = outFace.Back(); float bestDistance = M_INFINITY; size_t bestIndex = 0; for (size_t i = 0; i < clippedVertices.Size(); ++i) { float distance = (clippedVertices[i] - lastAdded).LengthSquared(); if (distance < bestDistance) { bestDistance = distance; bestIndex = i; } } outFace.Push(clippedVertices[bestIndex]); clippedVertices.Erase(bestIndex); } faces.Push(outFace); } }
void ConePrimitiveShape::SuggestSimplifications(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end, float distThresh, MiscLib::Vector< MiscLib::RefCountPtr< PrimitiveShape > > *suggestions) const { // sample the bounding box in parameter space at 25 locations // these points are used to estimate the other shapes // if the shapes succeed the suggestion is returned MiscLib::Vector< Vec3f > samples(2 * 25); float uStep = (m_extBbox.Max()[0] - m_extBbox.Min()[0]) / 4; float vStep = (m_extBbox.Max()[1] - m_extBbox.Min()[1]) / 4; float u = m_extBbox.Min()[0]; for(unsigned int i = 0; i < 5; ++i, u += uStep) { float v = m_extBbox.Min()[1]; for(unsigned int j = 0; j < 5; ++j, v += vStep) { float bmpu, bmpv; if(m_cone.Angle() >= M_PI / 4) { bmpu = std::sin(v) * u; bmpv = std::cos(v) * u; } else { bmpu = u; float r = m_cone.RadiusAtLength(u); bmpv = (v - float(M_PI)) * r; } InSpace(bmpu, bmpv, &samples[i * 5 + j], &samples[i * 5 + j + 25]); } } size_t c = samples.size() / 2; // now check all the shape types Cylinder cylinder; if(cylinder.InitAverage(samples)) { cylinder.LeastSquaresFit(samples.begin(), samples.begin() + c); bool failed = false; for(size_t i = 0; i < c; ++i) if(cylinder.Distance(samples[i]) > distThresh) { failed = true; break; } if(!failed) { suggestions->push_back(new CylinderPrimitiveShape(cylinder)); suggestions->back()->Release(); } } Sphere sphere; if(sphere.Init(samples)) { sphere.LeastSquaresFit(samples.begin(), samples.begin() + c); bool failed = false; for(size_t i = 0; i < c; ++i) if(sphere.Distance(samples[i]) > distThresh) { failed = true; break; } if(!failed) { suggestions->push_back(new SpherePrimitiveShape(sphere)); suggestions->back()->Release(); } } Plane plane; if(plane.LeastSquaresFit(samples.begin(), samples.begin() + c)) { bool failed = false; for(size_t i = 0; i < c; ++i) if(plane.Distance(samples[i]) > distThresh) { failed = true; break; } if(!failed) { suggestions->push_back(new PlanePrimitiveShape(plane)); suggestions->back()->Release(); } } /*// simpler shapes are suggested if the maximal curvature of the cone // is small compared to the extend in relation to the distThresh float meanRadius, length, meanLength, radialExtent; // the cone is parameterized as length and angle // in this case the cone is parametrized as length and arclength meanRadius = (m_cone.RadiusAtLength(m_extBbox.Min()[0]) + m_cone.RadiusAtLength(m_extBbox.Max()[0])) / 2; length = m_extBbox.Max()[0] - m_extBbox.Min()[0]; meanLength = (m_extBbox.Max()[0] + m_extBbox.Min()[0]) / 2; // the radial extent radialExtent = m_extBbox.Max()[1] - m_extBbox.Min()[1]; // We suggest a cylinder if the opening angle of the cone is so small // that over the whole height the difference is less than distThresh if(std::sin(m_cone.Angle()) * length / 2 < distThresh) { // construct the cylinder // it has the same axis as the cone // and we use the average radius of the cone Cylinder cylinder(m_cone.AxisDirection(), m_cone.Center(), meanRadius); suggestions->push_back(new CylinderPrimitiveShape(cylinder)); suggestions->back()->Release(); } // We suggest a sphere if a curvature of mean radius along the height // does not introduce too large an error float sphereRadius = std::tan(m_cone.Angle()) * meanLength; float radiusDiff = (std::sqrt(sphereRadius * sphereRadius + length * length / 4) - sphereRadius) / 2; if(radiusDiff < distThresh) { // the center of the sphere is given as the point on the axis // with the height of the mean length Vec3f center = (meanLength / std::cos(m_cone.Angle())) * m_cone.AxisDirection() + m_cone.Center(); Sphere sphere(center, sphereRadius + radiusDiff); suggestions->push_back(new SpherePrimitiveShape(sphere)); suggestions->back()->Release(); } // We suggest a plane if the mean radius causes only a small error // for this we need the angular extent in the curved direction of the cone radiusDiff = meanRadius - std::sin(radialExtent) * meanRadius; if(radiusDiff < distThresh) { GfxTL::Vector2Df bboxCenter; m_extBbox.Center(&bboxCenter); Vec3f pos, normal; InSpace(bboxCenter[0], bboxCenter[1] * m_cone.RadiusAtLength(bboxCenter[0]), &pos, &normal); Plane plane(pos, normal); suggestions->push_back(new PlanePrimitiveShape(plane)); suggestions->back()->Release(); }*/ }
float float3::Distance(const Plane &rhs) const { return rhs.Distance(POINT_VEC(*this)); }
void CylinderPrimitiveShape::SuggestSimplifications(const PointCloud &pc, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end, float distThresh, MiscLib::Vector< MiscLib::RefCountPtr< PrimitiveShape > > *suggestions) const { // sample the bounding box in parameter space at 25 locations // these points are used to estimate the other shapes // if the shapes succeed the suggestion is returned MiscLib::Vector< Vec3f > samples(2 * 25); float uStep = (m_extBbox.Max()[0] - m_extBbox.Min()[0]) / 4; float vStep = (m_extBbox.Max()[1] - m_extBbox.Min()[1]) / 4; float u = m_extBbox.Min()[0]; for(unsigned int i = 0; i < 5; ++i, u += uStep) { float v = m_extBbox.Min()[1]; for(unsigned int j = 0; j < 5; ++j, v += vStep) InSpace(u, v * m_cylinder.Radius(), &samples[i * 5 + j], &samples[i * 5 + j + 25]); } size_t c = samples.size() / 2; // now check all the shape types Sphere sphere; if(sphere.Init(samples)) { sphere.LeastSquaresFit(samples.begin(), samples.begin() + c); bool failed = false; for(size_t i = 0; i < c; ++i) if(sphere.Distance(samples[i]) > distThresh) { failed = true; break; } if(!failed) { suggestions->push_back(new SpherePrimitiveShape(sphere)); suggestions->back()->Release(); } } Plane plane; if(plane.LeastSquaresFit(samples.begin(), samples.begin() + c)) { bool failed = false; for(size_t i = 0; i < c; ++i) if(plane.Distance(samples[i]) > distThresh) { failed = true; break; } if(!failed) { suggestions->push_back(new PlanePrimitiveShape(plane)); suggestions->back()->Release(); } } /*// We suggest a sphere if a curvature of radius along the height // does not introduce too large an error float length = m_extBbox.Max()[0] - m_extBbox.Min()[0]; float meanLength = (m_extBbox.Max()[0] + m_extBbox.Min()[0]) / 2; float radiusDiff = (std::sqrt(m_cylinder.Radius() * m_cylinder.Radius() + length * length / 4) - m_cylinder.Radius()) / 2; float radialExtent = m_extBbox.Max()[1] - m_extBbox.Min()[1]; if(radiusDiff < distThresh) { // the center of the sphere is given as the point on the axis // with the height of the mean length Vec3f center = meanLength * m_cylinder.AxisDirection() + m_cylinder.AxisPosition(); Sphere sphere(center, m_cylinder.Radius() + radiusDiff); suggestions->push_back(new SpherePrimitiveShape(sphere)); suggestions->back()->Release(); } // We suggest a plane if the mean radius causes only a small error // for this we need the angular extent in the curved direction of the cone radiusDiff = (m_cylinder.Radius() - std::cos(radialExtent / 2) * m_cylinder.Radius()) / 2; if(radiusDiff < distThresh) { GfxTL::Vector2Df bboxCenter; m_extBbox.Center(&bboxCenter); Vec3f pos, normal; InSpace(bboxCenter[0], bboxCenter[1] * m_cylinder.Radius(), &pos, &normal); // offset position pos -= radiusDiff * normal; Plane plane(pos, normal); suggestions->push_back(new PlanePrimitiveShape(plane)); suggestions->back()->Release(); }*/ }