//=========================================================================== DirectionCone Torus::tangentCone(bool pardir_is_u) const //=========================================================================== { if (isSwapped()) pardir_is_u = !pardir_is_u; if (pardir_is_u) { double par = domain_.umin() - parbound_.umin()*(domain_.umax()-domain_.umin())/(parbound_.umax()-parbound_.umin()); shared_ptr<Circle> circle = getMajorCircle(par); return circle->directionCone(); } else { DirectionCone normals = normalCone(); double angle = normals.angle(); RectDomain domain = parameterDomain(); double umid = 0.5 * (domain.umax() + domain.umin()); double vmid = 0.5 * (domain.vmax() + domain.vmin()); vector<Point> pts(3); point(pts, umid, vmid, 1); return DirectionCone(pts[2], angle); } }
//=========================================================================== void VolumeModel::setBoundarySfs() //=========================================================================== { // Fetch all faces lying at outer boundaries, i.e. all faces with no twin vector<shared_ptr<ftSurface> > bd_faces = getBoundaryFaces(); #ifdef DEBUG_VOL2 std::ofstream of("bd_sfs.g2"); #endif // Make copy of all faces to avoid destroying existing topology // information in the shells of the solids vector<shared_ptr<ftSurface> > bd_faces2(bd_faces.size()); for (size_t ki=0; ki<bd_faces.size(); ++ki) { bd_faces2[ki] = shared_ptr<ftSurface>(new ftSurface(bd_faces[ki]->surface(), (int)ki)); bd_faces2[ki]->setBody(bd_faces[ki]->getBody()); #ifdef DEBUG_VOL2 shared_ptr<ParamSurface> surf = bd_faces[ki]->surface(); shared_ptr<SurfaceOnVolume> vsurf = dynamic_pointer_cast<SurfaceOnVolume,ParamSurface>(surf); if (vsurf.get()) { vsurf->spaceSurface()->writeStandardHeader(of); vsurf->spaceSurface()->write(of); } else { surf->writeStandardHeader(of); surf->write(of); } #endif } // Represent the outer boundaries as a SurfaceModel shared_ptr<SurfaceModel> sfmodel = shared_ptr<SurfaceModel>(new SurfaceModel(toptol_.gap, toptol_.gap, toptol_.neighbour, toptol_.kink, toptol_.bend, bd_faces2)); // Fetch all connected models vector<shared_ptr<SurfaceModel> > models = sfmodel->getConnectedModels(); if (models.size() == 1) boundary_shells_.push_back(models); else { // Sort models into connected submodels and inner and outer shells // First get maximum size of model BoundingBox box = boundingBox(); // Classify shells for (size_t ki=0; ki<models.size(); ++ki) { // Check if the current model is already classified size_t kj, kr; bool found = findBoundaryShell(models[ki], kj, kr); if (found) continue; // Shell already classified if (models[ki]->nmbEntities() == 0) continue; // Empty model // Make linear curve through current model shared_ptr<ftSurface> face = models[ki]->getFace(0); // Fetch a point on this face Point pnt, norm; shared_ptr<ParamSurface> srf = face->surface(); RectDomain dom = srf->containingDomain(); double upar = 0.5*(dom.umin()+dom.umax()); double vpar = 0.5*(dom.vmin()+dom.vmax()); Point pnt0 = srf->point(upar, vpar); double dist; face->closestPoint(pnt0, upar, vpar, pnt, dist, toptol_.gap); norm = face->normal(upar, vpar); // Make large enough curve double len = box.low().dist(box.high()); // Estimated box size norm.normalize(); Point pt1 = pnt - len*norm; Point pt2 = pnt + len*norm; shared_ptr<SplineCurve> crv = shared_ptr<SplineCurve>(new SplineCurve(pt1, pt2)); // Get model intersections vector<intersection_point> int_pts = getIntSfModelsCrv(models, crv); // Sort intersection points according to curve parameter std::sort(int_pts.begin(), int_pts.end(), par_compare); size_t i1, i2, i3, i4; for (kj=0; kj<int_pts.size(); ++kj) { // Find the next intersection with the same model for (kr=kj+1; kr<int_pts.size(); ++kr) if (int_pts[kj].shell_idx == int_pts[kr].shell_idx) break; if (kr == int_pts.size()) kr = kj; found = findBoundaryShell(models[int_pts[kj].shell_idx], i1, i2); if (!found) { vector<shared_ptr<SurfaceModel> > curr; curr.push_back(models[int_pts[kj].shell_idx]); boundary_shells_.push_back(curr); i1 = boundary_shells_.size() - 1; } // Add inner boundary shells for (size_t kh=kj+1; kh<=kr; ++kh) { found = findBoundaryShell(models[int_pts[kh].shell_idx], i3, i4); if (!found) boundary_shells_[i1].push_back(models[int_pts[kh].shell_idx]); } } } } }
//=========================================================================== void Torus::closestBoundaryPoint(const Point& pt, double& clo_u, double& clo_v, Point& clo_pt, double& clo_dist, double epsilon, const RectDomain* rd, double *seed) const //=========================================================================== { // Algorithm: // 1) Find closest point overall // 2) If on boundary, return // 3) Else, snap to boundary // Find closest point overall closestPoint(pt, clo_u, clo_v, clo_pt, clo_dist, epsilon); // Check if on boundary RectDomain dom = parameterDomain(); double umin = dom.umin(); double umax = dom.umax(); double vmin = dom.vmin(); double vmax = dom.vmax(); if (fabs(clo_u - umin) < epsilon || fabs(clo_u - umax) < epsilon || fabs(clo_v - vmin) < epsilon || fabs(clo_v - vmax) < epsilon) { return; } // Overall closest point is in the inner of the patch double clo_u_inner = clo_u; double clo_v_inner = clo_v; // Fist on boundary clo_u = umin; point(clo_pt, umin, clo_v_inner); clo_dist = pt.dist(clo_pt); // Second Point clo_pt_tmp; point(clo_pt_tmp, umax, clo_v_inner); double clo_dist_tmp = pt.dist(clo_pt_tmp); if (clo_dist_tmp < clo_dist) { clo_pt = clo_pt_tmp; clo_u = umax; clo_v = clo_v_inner; clo_dist = clo_dist_tmp; } // Third point(clo_pt_tmp, clo_u_inner, vmin); clo_dist_tmp = pt.dist(clo_pt_tmp); if (clo_dist_tmp < clo_dist) { clo_pt = clo_pt_tmp; clo_u = clo_u_inner; clo_v = vmin; clo_dist = clo_dist_tmp; } // Fourth point(clo_pt_tmp, clo_u_inner, vmax); clo_dist_tmp = pt.dist(clo_pt_tmp); if (clo_dist_tmp < clo_dist) { clo_pt = clo_pt_tmp; clo_u = clo_u_inner; clo_v = vmax; clo_dist = clo_dist_tmp; } return; }
//=========================================================================== int CurveBoundedDomain::positionPointInDomain(int pardir, double parval1, double parval2, double tolerance) const // Fetch all intervals in one parameter direction // going through a specific point lying inside the // bounded domain. // // Return value: -1 : Outside of outer loop // 0 : Inside domain // j>0 : Inside hole number j, i.e. inside loop number j //=========================================================================== { // Get the rectangular domain containing this domain RectDomain parbox = containingDomain(); // Make a constant curve in the parameter domain, in the given // direct slightly larger than the found containing domain. double par1[2], par2[2], vec[2]; double parint; int par_idx = 0; if (pardir == 2) { // Make constant parameter curve in 2. parameter direction. par1[0] = par2[0] = parval1; par1[1] = parbox.vmin(); par2[1] = parbox.vmax(); parint = std::max(par2[1] - par1[1], 0.1); par1[1] -= 0.1*parint; par2[1] += 0.1*parint; par_idx = 1; } else if (pardir == 1) { // Make constant parameter curve in 1. parameter direction. par1[1] = par2[1] = parval2; par1[0] = parbox.umin(); par2[0] = parbox.umax(); parint = std::max(par2[0] - par1[0], 0.1); par1[0] -= 0.1*parint; par2[0] += 0.1*parint; par_idx = 0; } else { // Diagonal parameter curve par1[0] = par2[0] = parval1; par1[1] = par2[1] = parval2; vec[0] = parbox.umax() - parbox.umin(); vec[1] = parbox.vmax() - parbox.vmin(); par1[0] -= vec[0]; par1[1] -= vec[1]; par2[0] += vec[0]; par2[1] += vec[1]; par_idx = 0; // @@@ VSK, 0309. This is not really correct } Point pnt1(par1[0], par1[1]); Point pnt2(par2[0], par2[1]); SplineCurve isopar(pnt1, pnt2); vector<intersection_point> intpt; findPcurveInsideSegments(isopar, tolerance, intpt); int ki; int nmbpoint = (int)intpt.size(); if (nmbpoint == 1) { // Assuming non-recognized tangential intersection return -1; } else if (nmbpoint%2 != 0) { throw std::logic_error("Odd number of intersections."); } double ptol = 1.0e-8; for (ki=1; ki<nmbpoint; ki+=1) { // Check if the initial point lies inside the current interval Point eval1, eval2; isopar.point(eval1, intpt[ki-1].par1); isopar.point(eval2, intpt[ki].par1); if (eval1[0]-ptol < parval1 && eval2[0]+ptol > parval1 && eval1[1]-ptol < parval2 && eval2[1]+ptol > parval2) { // The point lies inside this interval. Check if the interval // corresponds to an inner loop int loop1 = intpt[ki-1].loop_idx; int loop2 = intpt[ki].loop_idx; if (loop1 != loop2) return 0; // In the domain else return loop1; } } return -1; // The point lies outside the domain }
//=========================================================================== void CurveBoundedDomain::getInsideIntervals(int pardir, double parval1, double parval2, double tolerance, vector<pair<double, double> >& insideInts, bool with_bd) const // Fetch all intervals in one parameter direction // going through a specific point lying inside the // bounded domain. //=========================================================================== { // Get the rectangular domain containing this domain RectDomain parbox = containingDomain(); Point mid(0.5*(parbox.umin()+parbox.umax()), 0.5*(parbox.vmin()+parbox.vmax())); Point parpt(parval1, parval2); double len1 = (parbox.umax()-parbox.umin())+(parbox.vmax()-parbox.vmin()); double len2 = mid.dist(parpt); if (len1 == 0.0) { MESSAGE("Degenerate domain!"); return; } double mult_fac = 2.0*(len1+len2)/len1; // The curve with which to intersect // should be much larger than the trimmed domain // Make a constant curve in the parameter domain, in the given // direct slightly larger than the found containing domain. double par1[2], par2[2], vec[2]; double parint; int par_idx = 0; double len; if (pardir == 2) { // Make constant parameter curve in 2. parameter direction. par1[0] = par2[0] = parval1; par1[1] = parbox.vmin(); par2[1] = parbox.vmax(); parint = std::max(par2[1] - par1[1], 0.1); len = mult_fac*parint; par1[1] -= len; par2[1] += len; par_idx = 1; } else if (pardir == 1) { // Make constant parameter curve in 1. parameter direction. par1[1] = par2[1] = parval2; par1[0] = parbox.umin(); par2[0] = parbox.umax(); parint = std::max(par2[0] - par1[0], 0.1); len = mult_fac*parint; par1[0] -= len; par2[0] += len; par_idx = 0; } else { // Diagonal parameter curve par1[0] = par2[0] = parval1; par1[1] = par2[1] = parval2; vec[0] = parbox.umax() - parbox.umin(); vec[1] = parbox.vmax() - parbox.vmin(); len = mult_fac*sqrt(vec[0]*vec[0]+vec[1]*vec[1]); par1[0] -= (mult_fac*vec[0]); par1[1] -= (mult_fac*vec[1]); par2[0] += (mult_fac*vec[0]); par2[1] += (mult_fac*vec[1]); par_idx = 0; // @@@ VSK, 0309. This is not really correct } Point pnt1(par1[0], par1[1]); Point pnt2(par2[0], par2[1]); SplineCurve isopar(pnt1, -len, pnt2, len); vector<intersection_point> intpt; findPcurveInsideSegments(isopar, tolerance, intpt, with_bd); int ki; int nmbpoint = (int)intpt.size(); if (nmbpoint == 1) { // Assuming non-recognized tangential intersection return; } else if (nmbpoint%2 != 0) { throw std::logic_error("Odd number of intersections."); } for (ki=1; ki<nmbpoint; ki+=2) { Point eval1, eval2; isopar.point(eval1, intpt[ki-1].par1); isopar.point(eval2, intpt[ki].par1); insideInts.push_back(std::make_pair(eval1[par_idx], eval2[par_idx])); // std::cout << eval1[2-pardir] <<" , " << eval2[2-pardir] << std::endl; } }
//=========================================================================== double BoundedSurface::area(double tol) const //=========================================================================== { double fac = 10.0; // Get surrounding domain RectDomain domain = containingDomain(); // Get smallest surrounding surface shared_ptr<ParamSurface> base_sf = surface_; while (base_sf->instanceType() == Class_BoundedSurface) base_sf = dynamic_pointer_cast<BoundedSurface, ParamSurface>(base_sf)->underlyingSurface(); vector<shared_ptr<ParamSurface> > sfs = base_sf->subSurfaces(domain.umin(), domain.vmin(), domain.umax(), domain.vmax()); double total_area = 0.0; size_t kr; for (kr=0; kr<sfs.size(); ++kr) { shared_ptr<SplineSurface> spline_sf = dynamic_pointer_cast<SplineSurface, ParamSurface>(sfs[kr]); if (spline_sf.get()) total_area += spline_sf->area(tol); } if (isIsoTrimmed(0.1*tol)) { // We are finished return total_area; } std::ofstream out_file("tmp_mini_surf.g2"); // Otherwise, split the current surface into smaller pieces and compare areas int nmb_split = 5; double u1 = domain.umin(); double v1 = domain.vmin(); double u_del = (domain.umax() - u1)/(double)(nmb_split); double v_del = (domain.vmax() - v1)/(double)(nmb_split); int ki, kj; double curr_area = 0.0; vector<shared_ptr<ParamSurface> > all_sfs; for (kj=0; kj<nmb_split; ++kj, v1+=v_del) for (ki=0, u1=domain.umin(); ki<nmb_split; ++ki, u1+=u_del) { vector<shared_ptr<ParamSurface> > sub_sfs = subSurfaces(u1, v1, u1+u_del, v1+v_del); for (kr=0; kr<sub_sfs.size(); ++kr) { // sub_sfs[ki]->writeStandardHeader(out_file); // sub_sfs[ki]->write(out_file); RectDomain dom2 = sub_sfs[kr]->containingDomain(); vector<shared_ptr<ParamSurface> > tmp_sfs = base_sf->subSurfaces(std::min(u1,dom2.umin()), std::min(v1,dom2.vmin()), std::max(u1+u_del,dom2.umax()), std::max(v1+v_del,dom2.vmax())); curr_area += tmp_sfs[0]->area(tol); } all_sfs.insert(all_sfs.end(), sub_sfs.begin(), sub_sfs.end()); } if (total_area/curr_area < 1.0 + fac*tol) return curr_area; // The area is close enough // Compute recursively curr_area = 0.0; for (kr=0; kr<all_sfs.size(); ++kr) curr_area += all_sfs[kr]->area(tol); return curr_area; }