Ego::Math::Relation plane_intersects_aabb_max(const Plane3f& plane, const Vector3f& mins, const Vector3f& maxs) { int j; float dist, tmp; Ego::Math::Relation retval = Ego::Math::Relation::error; // find the point-plane distance for the most-positive points of the aabb dist = 0.0f; for (j = 0; j < 3; j++) { tmp = (plane.getNormal()[j] > 0.0f) ? maxs[j] : mins[j]; dist += tmp * plane.getNormal()[j]; } dist += plane.getDistance(); if (dist > 0.0f) { retval = Ego::Math::Relation::inside; } else if (dist < 0.0f) { retval = Ego::Math::Relation::outside; } else { retval = Ego::Math::Relation::intersect; } return retval; }
int main( int argc, char **argv ) { if(argc<2) { printf("Usage trimesh_base <meshfilename.ply>\n"); return -1; } MyMesh m,em,cm,full; if(tri::io::ImporterPLY<MyMesh>::Open(m,argv[1])!=0) { printf("Error reading file %s\n",argv[1]); exit(0); } tri::UpdateFlags<MyMesh>::FaceBorderFromFF(m); tri::UpdateNormals<MyMesh>::PerVertexNormalized(m); tri::UpdateBounding<MyMesh>::Box(m); printf("Input mesh vn:%i fn:%i\n",m.vn,m.fn); printf( "Mesh has %i vert and %i faces\n", m.vn, m.fn ); srand(time(0)); Plane3f slicingPlane; Point3f planeCenter = m.bbox.Center(); for(int i=0;i<10;++i) { cm.Clear(); em.Clear(); Point3f planeDir = Point3f(-0.5f+float(rand())/RAND_MAX,-0.5f+float(rand())/RAND_MAX,-0.5f+float(rand())/RAND_MAX); planeDir.Normalize(); printf("slicing dir %5.2f %5.2f %5.2f\n",planeDir[0],planeDir[1],planeDir[2]); slicingPlane.Init(planeCenter+planeDir*0.3f*m.bbox.Diag()*float(rand())/RAND_MAX,planeDir); vcg::IntersectionPlaneMesh<MyMesh, MyMesh, float>(m, slicingPlane, em ); tri::Clean<MyMesh>::RemoveDuplicateVertex(em); vcg::tri::CapEdgeMesh(em,cm); printf(" edge mesh vn %5i en %5i fn %5i\n",em.vn,em.en,em.fn); printf("sliced mesh vn %5i en %5i fn %5i\n",cm.vn,cm.en,cm.fn); tri::Append<MyMesh,MyMesh>::Mesh(full,cm); } tri::io::ExporterPLY<MyMesh>::Save(full,"out.ply",false); return 0; }
void GetRandPlane(Box3f &bb, Plane3f &plane) { Point3f planeCenter = bb.Center(); Point3f planeDir = Point3f(-0.5f+float(rand())/RAND_MAX,-0.5f+float(rand())/RAND_MAX,-0.5f+float(rand())/RAND_MAX); planeDir.Normalize(); plane.Init(planeCenter+planeDir*0.3f*bb.Diag()*float(rand())/RAND_MAX,planeDir); }
//---------------------------------------------------------------------------- void BouncingTetrahedra::CalculateNormal (const Vector3f* vertices, const Vector3f& closest, Contact& contact) { float diff = Mathf::MAX_REAL; for (int i = 0; i < 4; ++i) { Plane3f plane = Plane3f(vertices[mFaces[i][0]], vertices[mFaces[i][1]], vertices[mFaces[i][2]]); float temp = Mathf::FAbs(plane.DistanceTo(closest)); if (temp < diff) { contact.N = plane.Normal; diff = temp; } } }
int main( int argc, char **argv ) { if(argc<2) { printf("Usage trimesh_base <meshfilename.ply>\n"); return -1; } MyMesh m, // The loaded mesh em, // the 2D polyline representing the section slice, // the planar mesh resulting from the triangulation of the above sliced; // the 3D mesh resulting by the actual slicing of m into two capped sub pieces if(tri::io::ImporterPLY<MyMesh>::Open(m,argv[1])!=0) { printf("Error reading file %s\n",argv[1]); exit(0); } tri::UpdateBounding<MyMesh>::Box(m); printf("Input mesh vn:%i fn:%i\n",m.vn,m.fn); srand(time(0)); Plane3f slicingPlane; GetRandPlane(m.bbox,slicingPlane); printf("slicing dir %5.2f %5.2f %5.2f\n",slicingPlane.Direction()[0],slicingPlane.Direction()[1],slicingPlane.Direction()[2]); vcg::IntersectionPlaneMesh<MyMesh, MyMesh, float>(m, slicingPlane, em ); tri::Clean<MyMesh>::RemoveDuplicateVertex(em); vcg::tri::CapEdgeMesh(em,slice); printf("Slice mesh has %i vert and %i faces\n", slice.vn, slice.fn ); MyMesh A,B; bool ret=SplitMesh(m,A,B,slicingPlane); tri::UpdatePosition<MyMesh>::Translate(A, slicingPlane.Direction()*m.bbox.Diag()/80.0); tri::UpdatePosition<MyMesh>::Translate(B,-slicingPlane.Direction()*m.bbox.Diag()/80.0); tri::Append<MyMesh,MyMesh>::Mesh(sliced,A); tri::Append<MyMesh,MyMesh>::Mesh(sliced,B); printf("Sliced mesh has %i vert and %i faces\n", sliced.vn, sliced.fn ); tri::io::ExporterPLY<MyMesh>::Save(slice,"slice.ply",false); tri::io::ExporterPLY<MyMesh>::Save(sliced,"sliced.ply",false); return 0; }
// static bool GeometryUtils::rayPlaneIntersection( const Vector3f& rayOrigin, const Vector3f& rayDirection, const Plane3f& plane, float& t ) { // ray: P = O + tD // plane: P dot N + d = 0 // (O + tD) dot N + d = 0 // --> t = -(O dot N + d float den = Vector3f::dot( rayDirection, plane.normal() ); // TODO: epsilon if( abs( den ) > EPSILON ) { float num = -Vector3f::dot( rayOrigin, plane.normal() ) - plane.d; t = num / den; return ( t > 0 ); } return false; }
bool two_plane_intersection(Vector3f& p, Vector3f& d, const Plane3f& p0, const Plane3f& p1) { // Compute \f$\vec{d} = \hat{n}_0 \times \hat{n}_1\f$ const Vector3f &n0 = p0.getNormal(); const Vector3f &n1 = p1.getNormal(); d = n0.cross(n1); // If \f$\vec{v}\f$ is the zero vector, then the planes do not intersect. if (0 == d.normalize()) { return false; } if (0.0f != d[kZ]) { p[kX] = (n0[kY] * n1[kW] - n0[kW] * n1[kY]) / d[kZ]; p[kY] = (n0[kW] * n1[kX] - n0[kX] * n1[kW]) / d[kZ]; p[kZ] = 0.0f; } else { throw std::runtime_error("not yet supported"); } return true; }
bool three_plane_intersection(Vector3f& dst_pos, const Plane3f& p0, const Plane3f& p1, const Plane3f& p2) { Vector3f n0 = p0.getNormal(), n1 = p1.getNormal(), n2 = p2.getNormal(); float d0 = p0.getDistance(), d1 = p1.getDistance(), d2 = p2.getDistance(); // the determinant of the matrix float det = n0[kX] * (n1[kY] * n2[kZ] - n1[kZ] * n2[kY]) - n0[kY] * (n1[kX] * n2[kZ] - n2[kX] * n1[kZ]) + n0[kZ] * (n1[kX] * n2[kY] - n2[kX] * n1[kY]); // check for system that is too close to being degenerate if (std::abs(det) < 1e-6) return false; float tmp; // the x component tmp = d0 * (n1[kZ] * n2[kY] - n1[kY] * n2[kZ]) + d1 * (n0[kY] * n2[kZ] - n0[kZ] * n2[kY]) + d2 * (n0[kZ] * n1[kY] - n0[kY] * n1[kZ]); dst_pos[kX] = tmp / det; // the y component tmp = d0 * (n1[kX] * n2[kZ] - n1[kZ] * n2[kX]) + d1 * (n0[kZ] * n2[kX] - n0[kX] * n2[kZ]) + d2 * (n0[kX] * n1[kZ] - n0[kZ] * n1[kX]); dst_pos[kY] = tmp / det; // the z component tmp = d0 * (n1[kY] * n2[kX] - n1[kX] * n2[kY]) + d1 * (n0[kX] * n2[kY] - n0[kY] * n2[kX]) + d2 * (n0[kY] * n1[kX] - n0[kX] * n1[kY]); dst_pos[kZ] = tmp / det; return true; }
void Molecule3dConstraintsChecker::_cache (int idx) { if (_cache_v.find(idx) || _cache_l.find(idx) || _cache_p.find(idx)) return; const MC::Base &base = _constraints.at(idx); switch (base.type) { case MC::POINT_ATOM: { int atom_idx = ((const Molecule3dConstraints::PointByAtom &)base).atom_idx; _cache_v.insert(idx, _target->getAtomXyz(_mapping[atom_idx])); break; } case MC::POINT_DISTANCE: { const MC::PointByDistance &constr = (const MC::PointByDistance &)base; _cache(constr.beg_id); _cache(constr.end_id); const Vec3f &beg = _cache_v.at(constr.beg_id); const Vec3f &end = _cache_v.at(constr.end_id); Vec3f dir; dir.diff(end, beg); if (!dir.normalize()) throw Error("point-by-distance: degenerate case"); Vec3f res; res.lineCombin(beg, dir, constr.distance); _cache_v.insert(idx, res); break; } case MC::POINT_PERCENTAGE: { const MC::PointByPercentage &constr = (const MC::PointByPercentage &)base; _cache(constr.beg_id); _cache(constr.end_id); const Vec3f &beg = _cache_v.at(constr.beg_id); const Vec3f &end = _cache_v.at(constr.end_id); Vec3f dir; dir.diff(end, beg); if (!dir.normalize()) throw Error("point-by-percentage: degenerate case"); Vec3f res; res.lineCombin2(beg, 1.f - constr.percentage, end, constr.percentage); _cache_v.insert(idx, res); break; } case MC::POINT_NORMALE: { const MC::PointByNormale &constr = (const MC::PointByNormale &)base; _cache(constr.org_id); _cache(constr.norm_id); const Vec3f &org = _cache_v.at(constr.org_id); const Line3f &norm = _cache_l.at(constr.norm_id); Vec3f res; res.lineCombin(org, norm.dir, constr.distance); _cache_v.insert(idx, res); break; } case MC::POINT_CENTROID: { const MC::Centroid &constr = (const MC::Centroid &)base; Vec3f res; if (constr.point_ids.size() < 1) throw Error("centroid: have %d points", constr.point_ids.size()); for (int i = 0; i < constr.point_ids.size(); i++) { _cache(constr.point_ids[i]); const Vec3f &pt = _cache_v.at(constr.point_ids[i]); res.add(pt); } res.scale(1.f / constr.point_ids.size()); _cache_v.insert(idx, res); break; } case MC::LINE_NORMALE: { const MC::Normale &constr = (const MC::Normale &)base; _cache(constr.plane_id); _cache(constr.point_id); const Plane3f &plane = _cache_p.at(constr.plane_id); const Vec3f &point = _cache_v.at(constr.point_id); Vec3f projection; Line3f res; plane.projection(point, projection); res.dir.copy(plane.getNorm()); res.org.copy(projection); _cache_l.insert(idx, res); break; } case MC::LINE_BEST_FIT: { const MC::BestFitLine &constr = (const MC::BestFitLine &)base; if (constr.point_ids.size() < 2) throw Error("best fit line: only %d points", constr.point_ids.size()); QS_DEF(Array<Vec3f>, points); points.clear(); for (int i = 0; i < constr.point_ids.size(); i++) { _cache(constr.point_ids[i]); points.push(_cache_v.at(constr.point_ids[i])); } Line3f res; res.bestFit(points.size(), points.ptr(), 0); _cache_l.insert(idx, res); break; } case MC::PLANE_BEST_FIT: { const MC::BestFitPlane &constr = (const MC::BestFitPlane &)base; if (constr.point_ids.size() < 3) throw Error("best fit line: only %d points", constr.point_ids.size()); QS_DEF(Array<Vec3f>, points); points.clear(); for (int i = 0; i < constr.point_ids.size(); i++) { _cache(constr.point_ids[i]); points.push(_cache_v.at(constr.point_ids[i])); } Plane3f res; res.bestFit(points.size(), points.ptr(), 0); _cache_p.insert(idx, res); break; } case MC::PLANE_POINT_LINE: { const MC::PlaneByPoint &constr = (const MC::PlaneByPoint &)base; _cache(constr.point_id); _cache(constr.line_id); const Vec3f &point = _cache_v.at(constr.point_id); const Line3f &line = _cache_l.at(constr.line_id); Plane3f res; res.byPointAndLine(point, line); _cache_p.insert(idx, res); break; } default: throw Error("unknown constraint type %d", base.type); } }
bool ExtraFilter_SlicePlugin::applyFilter(QAction *filter, MeshDocument &m, RichParameterSet &parlst, vcg::CallBackPos *cb) { vcg::tri::UpdateBounding<CMeshO>::Box(m.mm()->cm); switch(ID(filter)) { case FP_WAFFLE_SLICE : { MeshModel* base = m.mm(); CMeshO &cmBase = base->cm; Box3f &bbox = m.mm()->cm.bbox; if (tri::Clean<CMeshO>::CountNonManifoldEdgeFF(cmBase)>0 || (tri::Clean<CMeshO>::CountNonManifoldVertexFF(cmBase,false) != 0)) { Log("Mesh is not two manifold, cannot apply filter"); return false; } if(parlst.getFloat("spacing") >= 1) { Log("the selected distance between the planes is greater than 1. The filter had no effect"); return false; } Point3f planeAxis(0,0,0); Axis axis = (Axis) parlst.getEnum("planeAxis"); planeAxis[axis] = 1.0f; float length = parlst.getFloat("length"); bool hideBase = parlst.getBool("hideBase"); bool hideEdge = parlst.getBool("hideEdge"); bool hidePlanes = parlst.getBool("hidePlanes"); bool hideExtrudes = parlst.getBool("hideExtrudes"); // set common SVG Properties const float maxdim=m.mm()->cm.bbox.Dim()[m.mm()->cm.bbox.MaxDim()]; Point3f sizeCm=m.mm()->cm.bbox.Dim()*(length/maxdim); // to check for dimensions with custom axis Axis axisOrthog, axisJoint; Point2f sizeCmOrth; switch(axis) { case X: { axisOrthog = (Axis) Succ<X>::value; axisJoint = (Axis) Succ<Succ<X>::value>::value; pr.sizeCm = Point2f(sizeCm[1],sizeCm[2]); sizeCmOrth.X()=sizeCm[0]; sizeCmOrth.Y()=sizeCm[2]; } break; case Y: { axisOrthog = (Axis) Succ<Y>::value; axisJoint = (Axis) Succ<Succ<Y>::value>::value; pr.sizeCm = Point2f(sizeCm[0],sizeCm[2]); sizeCmOrth.X()=sizeCm[0]; sizeCmOrth.Y()=sizeCm[1]; } break; case Z: { axisOrthog = (Axis) Succ<Z>::value; axisJoint = (Axis) Succ<Succ<Z>::value>::value; pr.sizeCm = Point2f(sizeCm[0],sizeCm[1]); sizeCmOrth.X()=sizeCm[1]; sizeCmOrth.Y()=sizeCm[2]; } break; } Log("sizecm %fx%f",pr.sizeCm[0],pr.sizeCm[1]); vector<CMeshO*> ev; const float planeDist = maxdim * parlst.getFloat("spacing"); const int planeNum = (planeDist == 0) ? 1 : ( ((bbox.Dim()*planeAxis)/planeDist)+1 ); //evito la divisione per 0 const float lengthDiag = bbox.Diag()/2.0; Segment2f lati[3]; //the rectangle is made up of three segments, the fourth side is ignored, so I never use it const float eps =planeDist*parlst.getFloat("eps"); float epsTmp; float start; int rectNum; if(parlst.getFloat("eps") < 1) { start = - (planeNum/2) * planeDist; //I have to go back from the center of half the length epsTmp = eps/2.0; generateRectSeg(0, epsTmp, bbox.Diag()*2, lati); rectNum = planeNum; } else { start = 0; epsTmp = bbox.Diag(); generateRectSeg(0, bbox.Diag()*2, bbox.Diag()*2, lati); rectNum = 1; Log("thickness is greater than 1: the extrusions will overlap"); } float planeOffset = parlst.getFloat("planeOffset"); pr.lineWidthPt=200; pr.scale=2/maxdim; pr.numCol=(int)(max((int)sqrt(planeNum*1.0f),2)+1); pr.numRow=(int)(planeNum*1.0f/pr.numCol)+1; pr.projDir = planeAxis; pr.projCenter = m.mm()->cm.bbox.Center(); pr.enumeration = true; MeshModel* cap, *cap2, *extr; QString layername; for(int pl = 0; pl < 2; ++pl) { // Log("################## PLANE %i", pl); Plane3f slicingPlane; Point3f planeCenter = bbox.Center() + planeAxis*planeOffset*lengthDiag; int numAdd = 0; // int i=4; //if I want to apply only the plan number i I decomment this variable and comment the cycle for(int i = 0; i < planeNum; ++i) //cropping the plans { // Log("######## LAYER %i", i); planeCenter[axis] = start + planeDist*i;; slicingPlane.Init(planeCenter,planeAxis); layername.sprintf("EdgeMesh_%d_%d",pl,numAdd); cap= m.addNewMesh("",qPrintable(layername)); vcg::IntersectionPlaneMesh<CMeshO, CMeshO, float>(base->cm, slicingPlane, cap->cm ); tri::Clean<CMeshO>::RemoveDuplicateVertex(cap->cm); if(cap->cm.edge.size()>= 3) { Incastri temp; // int j=1; //if I want to apply only the rectangle number j I decomment this variable and comment the cycle for(int j = 0; j <rectNum ; ++j) //clipping the rectangles { // Log("#### RECTANGLE %i", j); float newDist = start + planeDist*j; modifyOnY(lati, newDist+epsTmp, newDist-epsTmp); temp = subtraction(cap->cm, lati, axis, axisOrthog, axisJoint, planeCenter[axis]); if(temp == NOT_PLANE) {Log("ATTENTION! The IntersectionPlaneMesh did not return a plane silhouette in the current plane!"); m.delMesh(cap); break;} if(temp== NOT_SAGOME) {Log("ATTENTION! The IntersectionPlaneMesh did not return a simple closed silhouette for the plane %i, on axis %i",i, pl); m.delMesh(cap); break;} } if(temp > NOT_SAGOME) { ev.push_back(&(cap->cm)); //add the silhouette to those for export to SVG layername.sprintf("CappedSlice_%d_%d",pl,numAdd); //add the silhouettes converted in mesh cap2= m.addNewMesh("",qPrintable(layername)); tri::CapEdgeMesh(cap->cm, cap2->cm); layername.sprintf("Extruded_%d_%d",pl,numAdd++); //add the mesh extruded extr= m.addNewMesh("",qPrintable(layername)); cap2->updateDataMask(MeshModel::MM_FACEFACETOPO); extr->updateDataMask(MeshModel::MM_FACEFACETOPO); tri::UpdateTopology<CMeshO>::FaceFace(cap2->cm); tri::ExtrudeBoundary<CMeshO>(cap2->cm,extr->cm,eps,planeAxis); if(hideEdge) cap->visible =false; if(hidePlanes) cap2->visible =false; if(hideExtrudes) extr->visible =false; } }else m.delMesh(cap); //if the intersection does not exist I reject the result } QString fname;//= parlst.getSaveFileName("filename"); if(fname=="") fname.sprintf("Slice_%d.svg",pl); if (!fname.endsWith(".svg")) fname+=".svg"; tri::io::ExporterSVG<CMeshO>::Save(ev, fname.toStdString().c_str(), pr); ev.clear(); planeAxis[axis] = 0.0f; planeAxis[axisOrthog] = 1.0f; flipOnX(lati); pr.sizeCm = sizeCmOrth; pr.projDir = planeAxis; Axis aSwap = axis; axis = axisOrthog; axisOrthog = aSwap; } if(hideEdge) cap->visible =false; if(hidePlanes) cap2->visible =false; if(hideExtrudes) extr->visible =false; if(hideBase) base->visible =false; if(hideBase) base->visible =false; } break; } return true; }
// static float Plane3f::cosineDihedralAngle( const Plane3f& p0, const Plane3f& p1 ) { return Vector3f::dot( p0.unitNormal(), p1.unitNormal() ); }