void Curve2D::_bake_segment2d( std::map<float, Vector2>& r_bake, float p_begin, float p_end, const Vector2& p_a, const Vector2& p_out, const Vector2& p_b, const Vector2& p_in, int p_depth, int p_max_depth, float p_tol ) const { float mp = p_begin + (p_end - p_begin) * 0.5; Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 na =(mid - beg).normalized(); Vector2 nb =(end - mid).normalized(); float dp = na.dot(nb); if(dp < cos(deg2rad(p_tol))) { r_bake[mp]=mid; } if(p_depth<p_max_depth) { _bake_segment2d(r_bake, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_tol); _bake_segment2d(r_bake, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_max_depth, p_tol); } }
void Curve3D::_bake_segment3d(Map<float,Vector3>& r_bake, float p_begin, float p_end,const Vector3& p_a,const Vector3& p_out,const Vector3& p_b, const Vector3& p_in,int p_depth,int p_max_depth,float p_tol) const { float mp = p_begin+(p_end-p_begin)*0.5; Vector3 beg = _bezier_interp(p_begin,p_a,p_a+p_out,p_b+p_in,p_b); Vector3 mid = _bezier_interp(mp,p_a,p_a+p_out,p_b+p_in,p_b); Vector3 end = _bezier_interp(p_end,p_a,p_a+p_out,p_b+p_in,p_b); Vector3 na = (mid-beg).normalized(); Vector3 nb = (end-mid).normalized(); float dp = na.dot(nb); if (dp<Math::cos(Math::deg2rad(p_tol))) { r_bake[mp]=mid; } if (p_depth<p_max_depth) { _bake_segment3d(r_bake,p_begin,mp,p_a,p_out,p_b,p_in,p_depth+1,p_max_depth,p_tol); _bake_segment3d(r_bake,mp,p_end,p_a,p_out,p_b,p_in,p_depth+1,p_max_depth,p_tol); } }
void GraphEdit::_bake_segment2d(CanvasItem *p_where, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const { float mp = p_begin + (p_end - p_begin) * 0.5; Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 na = (mid - beg).normalized(); Vector2 nb = (end - mid).normalized(); float dp = Math::rad2deg(Math::acos(na.dot(nb))); if (p_depth >= p_min_depth && (dp < p_tol || p_depth >= p_max_depth)) { p_where->draw_line(beg, end, p_color.linear_interpolate(p_to_color, mp), 2, true); lines++; } else { _bake_segment2d(p_where, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); _bake_segment2d(p_where, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); } }
void GraphEdit::_bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const { float mp = p_begin + (p_end - p_begin) * 0.5; Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b); Vector2 na = (mid - beg).normalized(); Vector2 nb = (end - mid).normalized(); float dp = Math::rad2deg(Math::acos(na.dot(nb))); if (p_depth >= p_min_depth && (dp < p_tol || p_depth >= p_max_depth)) { points.push_back((beg + end) * 0.5); colors.push_back(p_color.linear_interpolate(p_to_color, mp)); lines++; } else { _bake_segment2d(points, colors, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); _bake_segment2d(points, colors, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines); } }
Vector3 Curve3D::interpolate(int p_index, float p_offset) const { int pc = points.size(); ERR_FAIL_COND_V(pc==0,Vector3()); if (p_index >= pc-1) return points[pc-1].pos; else if (p_index<0) return points[0].pos; Vector3 p0 = points[p_index].pos; Vector3 p1 = p0+points[p_index].out; Vector3 p3 = points[p_index+1].pos; Vector3 p2 = p3+points[p_index+1].in; return _bezier_interp(p_offset,p0,p1,p2,p3); }
Vector2 Curve2D::interpolate(int p_index, float p_offset) const { int pc = points.size(); if(pc == 0) return Vector2(); if(p_index >= pc-1) return points[pc-1].pos; else if(p_index<0) return points[0].pos; Vector2 p0 = points[p_index].pos; Vector2 p1 = p0 + points[p_index].out; Vector2 p3 = points[p_index+1].pos; Vector2 p2 = p3 + points[p_index+1].in; return _bezier_interp(p_offset, p0, p1, p2, p3); }
DVector<Point2> Curve2D::bake(int p_subdivs) const { int pc = points.size(); DVector<Point2> ret; if (pc<2) return ret; ret.resize((pc-1)*p_subdivs+1); DVector<Point2>::Write w = ret.write(); const Point *r = points.ptr(); for(int i=0;i<pc;i++) { int ofs = pc*p_subdivs; int limit=(i==pc-1)?p_subdivs+1:p_subdivs; for(int j=0;j<limit;j++) { Vector2 p0 = r[i].pos; Vector2 p1 = p0+r[i].out; Vector2 p3 = r[i].pos; Vector2 p2 = p3+r[i].in; real_t t = j/(real_t)p_subdivs; w[ofs+j]=_bezier_interp(t,p0,p1,p2,p3); } } w = DVector<Point2>::Write(); return ret; }
void Curve2D::_bake() const { if(!baked_cache_dirty) return; baked_max_ofs = 0; baked_cache_dirty = false; if(points.size() == 0) { baked_point_cache.resize(0); return; } if(points.size()==1) { baked_point_cache.resize(1); baked_point_cache[0] = points[0].pos; return; } Vector2 pos=points[0].pos; std::list<Vector2> pointlist; pointlist.push_back(pos); //start always from origin for(int i=0;i<points.size()-1;i++) { float step = 0.1; // at least 10 substeps ought to be enough? float p = 0; while(p<1.0) { float np=p+step; if(np>1.0) np=1.0; Vector2 npp = _bezier_interp(np, points[i].pos,points[i].pos+points[i].out,points[i+1].pos+points[i+1].in,points[i+1].pos); float d = pos.distance_to(npp); if(d>bake_interval) { // OK! between P and NP there _has_ to be Something, let's go searching! int iterations = 10; //lots of detail! float low = p; float hi = np; float mid = low+(hi-low)*0.5; for(int j=0;j<iterations;j++) { npp = _bezier_interp(mid, points[i].pos,points[i].pos+points[i].out,points[i+1].pos+points[i+1].in,points[i+1].pos); d = pos.distance_to(npp); if(bake_interval < d) hi=mid; else low=mid; mid = low+(hi-low)*0.5; } pos=npp; p=mid; pointlist.push_back(pos); } else { p=np; } } } Vector2 lastpos = points[points.size()-1].pos; float rem = pos.distance_to(lastpos); baked_max_ofs=(pointlist.size()-1)*bake_interval+rem; pointlist.push_back(lastpos); baked_point_cache.resize(pointlist.size()); int idx=0; for(std::list<Vector2>::const_iterator itr = pointlist.begin(); itr != pointlist.end(); ++itr) { baked_point_cache[idx] = *itr; idx++; } }
void Curve3D::_bake() const { if (!baked_cache_dirty) return; baked_max_ofs=0; baked_cache_dirty=false; if (points.size()==0) { baked_point_cache.resize(0); baked_tilt_cache.resize(0); return; } if (points.size()==1) { baked_point_cache.resize(1); baked_point_cache.set(0,points[0].pos); baked_tilt_cache.resize(1); baked_tilt_cache.set(0,points[0].tilt); return; } Vector3 pos=points[0].pos; List<Plane> pointlist; pointlist.push_back(Plane(pos,points[0].tilt)); for(int i=0;i<points.size()-1;i++) { float step = 0.1; // at least 10 substeps ought to be enough? float p = 0; while(p<1.0) { float np=p+step; if (np>1.0) np=1.0; Vector3 npp = _bezier_interp(np, points[i].pos,points[i].pos+points[i].out,points[i+1].pos+points[i+1].in,points[i+1].pos); float d = pos.distance_to(npp); if (d>bake_interval) { // OK! between P and NP there _has_ to be Something, let's go searching! int iterations = 10; //lots of detail! float low = p; float hi = np; float mid = low+(hi-low)*0.5; for(int j=0;j<iterations;j++) { npp = _bezier_interp(mid, points[i].pos,points[i].pos+points[i].out,points[i+1].pos+points[i+1].in,points[i+1].pos); d = pos.distance_to(npp); if (bake_interval < d) hi=mid; else low=mid; mid = low+(hi-low)*0.5; } pos=npp; p=mid; Plane post; post.normal=pos; post.d=Math::lerp(points[i].tilt,points[i+1].tilt,mid); pointlist.push_back(post); } else { p=np; } } } Vector3 lastpos = points[points.size()-1].pos; float lastilt = points[points.size()-1].tilt; float rem = pos.distance_to(lastpos); baked_max_ofs=(pointlist.size()-1)*bake_interval+rem; pointlist.push_back(Plane(lastpos,lastilt)); baked_point_cache.resize(pointlist.size()); Vector3Array::Write w = baked_point_cache.write(); int idx=0; baked_tilt_cache.resize(pointlist.size()); RealArray::Write wt = baked_tilt_cache.write(); for(List<Plane>::Element *E=pointlist.front();E;E=E->next()) { w[idx]=E->get().normal; wt[idx]=E->get().d; idx++; } }