double Bernsteins::secant(Bezier bz) { double s = 0, t = 1; double e = 1e-14; int side = 0; double r, fr, fs = bz.at0(), ft = bz.at1(); for (size_t n = 0; n < 100; ++n) { r = (fs*t - ft*s) / (fs - ft); if (fabs(t-s) < e * fabs(t+s)) { debug(std::cout << "error small " << fabs(t-s) << ", accepting solution " << r << "after " << n << "iterations\n"); return r; } fr = horner(bz, r); if (fr * ft > 0) { t = r; ft = fr; if (side == -1) fs /= 2; side = -1; } else if (fs * fr > 0) { s = r; fs = fr; if (side == +1) ft /= 2; side = +1; } else break; } return r; }
void draw_surface(float width, float height) { /* pseudo 1. calculate p3-p2 2. set new bezier p0 = old bezier p3 3. new beier p1 = p0 + old(p3-p2)*/ Bezier tl = Bezier(width, height, angle); Vector4 d1 = tl.p3 - tl.p2; Vector4 d2 = tl.p7 - tl.p6; Vector4 d3 = tl.p11 - tl.p10; Vector4 d4 = tl.p15 - tl.p14; Vector4 g1 = tl.p3 + d1; Vector4 g2 = tl.p7 + d2; Vector4 g3 = tl.p11 + d3; Vector4 g4 = tl.p15 + d4; cout << "tlp7: " << tl.p7.y << endl; Bezier tr = Bezier(tl.p3, g1, tl.p7, g2, tl.p11, g3, tl.p15, g4, angle); //cout << "p0: " << tr.p0.y << " p3: " << tr.p3.y << " p12: " << tr.p12.y << " p15: " << tr.p15.y << endl; cout << "p4: " << tr.p4.y << " p8: " << tr.p8.y << " p7: " << tr.p7.y << " p11: " << tr.p11.y << endl; cout << "p5: " << tr.p5.y << endl; for (float t1 = -0.5; t1 < 0.49; t1 += 0.01) { for (float t2 = -0.5; t2 < 0.49; t2 += 0.01) { glColor3f(1, 0, 0); tl.tessellate(t1, t2, .1); glColor3f(0, 0, 1); tr.tessellate(t1, t2, .1); } } }
void ShapeMaker::cubicTo (const Bezier &cubic) { const double sqrt3 = 1.7320508075688772935274463415059; const double precision = 600 * 18 / (60 * factorx * sqrt3); // distance between control points of quadratic approximations of either end double D01 = (cubic.p1 - (cubic.c1 - cubic.c0) * 3 - cubic.p0).magnitude () / 2; double tMax3 = precision / D01; if (tMax3 >= 1) { curveTo (cubic.quadraticCtrl(), cubic.p1); return; } Bezier end(cubic); if (tMax3 >= 0.5 * 0.5 * 0.5) { Bezier start (end.split (0.5)); curveTo (start.quadraticCtrl (), start.p1); } else { double tMax = pow (tMax3, 1.0/3.0); Bezier start (end.split (tMax)); Bezier middle (end.split (1 - tMax / (1 - tMax))); curveTo (start.quadraticCtrl (), start.p1); cubicTo (middle); } curveTo (end.quadraticCtrl (), end.p1); }
CubicSpline::CubicSpline(vector<Vector3> controlPoints, float tightness, int subDivisions) : m_length(0.f) { Vector3 endTangent; for (int i = 0; i < controlPoints.size()-1; i++) { vector<Vector3> path; Vector3 start = controlPoints[i]; Vector3 end = controlPoints[i+1]; path.push_back(start); if (endTangent != Vector3::Zero) { // start tangent becomes the negative of the previous end tangent path.push_back(-endTangent + start); } if (i < controlPoints.size() - 2) { Vector3 next = controlPoints[i + 2]; Vector3 line1 = start - end; Vector3 line2 = end - next; line1.Normalize(); line2.Normalize(); // average the two vectors to get the normal of reflection endTangent = Vector3((line1.x + line2.x) / 2.f, (line1.y + line2.y) / 2.f, (line1.z + line2.z) / 2.f); //endTangent.Normalize(); endTangent *= tightness; path.push_back(endTangent + end); } path.push_back(end); Bezier bezier = Bezier(path); float length = bezier.Length(subDivisions); m_length += length; m_bezierSections.push_back(std::make_pair(Bezier(bezier), length)); } }
CtrlSliderBg::CtrlSliderBg( intf_thread_t *pIntf, const Bezier &rCurve, VarPercent &rVariable, int thickness, GenericBitmap *pBackground, int nbHoriz, int nbVert, int padHoriz, int padVert, VarBool *pVisible, const UString &rHelp ): CtrlGeneric( pIntf, rHelp, pVisible ), m_pCursor( NULL ), m_rVariable( rVariable ), m_thickness( thickness ), m_rCurve( rCurve ), m_width( rCurve.getWidth() ), m_height( rCurve.getHeight() ), m_pImgSeq( pBackground ), m_nbHoriz( nbHoriz ), m_nbVert( nbVert ), m_padHoriz( padHoriz ), m_padVert( padVert ), m_bgWidth( 0 ), m_bgHeight( 0 ), m_position( 0 ) { if( pBackground ) { // Build the background image sequence // Note: we suppose that the last padding is not included in the // given image // TODO: we should probably change this assumption, as it would make // the code a bit simpler and it would be more natural for the skins // designers m_bgWidth = (pBackground->getWidth() + m_padHoriz) / nbHoriz; m_bgHeight = (pBackground->getHeight() + m_padVert) / nbVert; // Observe the position variable m_rVariable.addObserver( this ); // Initial position m_position = (int)( m_rVariable.get() * (m_nbHoriz * m_nbVert - 1) ); } }
void Bezier::attach(Bezier& other, bool reverse) { nextPatch = &other; // Calculate road radius as the connection of this and the next patch MathVector<float, 3> a = surfCoord(0.5, 0.0), b = surfCoord(0.5, 1.0), c = other.surfCoord(0.5, 1.0); if (reverse) { a = surfCoord(0.5, 1.0); b = surfCoord(0.5, 0.0); c = other.surfCoord(0.5, 0.0); } MathVector<float, 3> d1 = a - b, d2 = c - b; float diff = d2.magnitude() - d1.magnitude(); float dd = ((d1.magnitude() < 0.0001) || (d2.magnitude() < 0.0001)) ? 0.f : d1.normalized().dot(d2.normalized()); float angle = acosf((dd >= 1.f) ? 1.f :(dd <= -1.f) ? -1.f : dd); float d1d2mag = d1.magnitude() + d2.magnitude(); float alpha = (d1d2mag < 0.0001) ? 0.f : (float) (M_PI * diff + 2.f * d1.magnitude() * angle) / d1d2mag / 2.f; if (fabs(alpha - M_PI/2.0) < 0.001) roadRadius = 10000.0; else roadRadius = d1.magnitude() / 2.f / cosf(alpha); if (d1.magnitude() < 0.0001) roadCurvature = 0.0; else roadCurvature = 2.f * cosf(alpha) / d1.magnitude(); // Determine it's a left or right turn at the connection MathVector<float, 3> d = d1.cross(d2); if (fabs(d[0]) < 0.1 && fabs(d[1]) < 0.1 && fabs(d[2]) < 0.1) turn = 0; // Straight road ahead else if (d[1] > 0.0) turn = -1; // Left turn ahead else turn = 1; // Right turn ahead // Calculate distance from start of the road length = d1.magnitude(); }
float AiCarStandard::GetHorizontalDistanceAlongPatch(const Bezier & patch, Vec3 carposition) { Vec3 leftside = (patch.GetPoint(0,0) + patch.GetPoint(3,0))*0.5; Vec3 rightside = (patch.GetPoint(0,3) + patch.GetPoint(3,3))*0.5; Vec3 patchwidthvector = rightside - leftside; return patchwidthvector.Normalize().dot(carposition-leftside); }
void drawPath() { for (float g = 0; g < 1; g += .005) { glColor3f(0, 0, 1); Vector4 test = x1.lip(g, .1); drawDots(test); } for (float g = 0; g < 1; g += .005) { glColor3f(1, 1, 0); Vector4 test = x2.lip(g, .1); drawDots(test); } for (float g = 0; g < 1; g += .005) { glColor3f(1, 0, 0); Vector4 test = x3.lip(g, .1); drawDots(test); } for (float g = 0; g < 1; g += .005) { glColor3f(1, 1, 1); Vector4 test = x4.lip(g, .1); drawDots(test); } }
void convex_hull_marching(Bezier src_bz, Bezier bz, std::vector<double> &solutions, double left_t, double right_t) { while(bz.order() > 0 and bz[0] == 0) { std::cout << "deflate\n"; bz = bz.deflate(); solutions.push_back(left_t); } if (bz.order() > 0) { int old_sign = SGN(bz[0]); int sign; double left_bound = 0; double dt = 0; for (size_t i = 1; i < bz.size(); i++) { sign = SGN(bz[i]); if (sign != old_sign) { dt = double(i) / bz.order(); left_bound = dt * bz[0] / (bz[0] - bz[i]); break; } old_sign = sign; } if (dt == 0) return; std::cout << bz << std::endl; std::cout << "dt = " << dt << std::endl; std::cout << "left_t = " << left_t << std::endl; std::cout << "right_t = " << right_t << std::endl; std::cout << "left bound = " << left_bound << " = " << bz(left_bound) << std::endl; double new_left_t = left_bound * (right_t - left_t) + left_t; std::cout << "new_left_t = " << new_left_t << std::endl; Bezier bzr = subRight(src_bz, new_left_t); while(bzr.order() > 0 and bzr[0] == 0) { std::cout << "deflate\n"; bzr = bzr.deflate(); solutions.push_back(new_left_t); } if (left_t < new_left_t) { convex_hull_marching(src_bz, bzr, solutions, new_left_t, right_t); } else { std::cout << "epsilon reached\n"; while(bzr.order() > 0 and fabs(bzr[0]) <= 1e-10) { std::cout << "deflate\n"; bzr = bzr.deflate(); std::cout << bzr << std::endl; solutions.push_back(new_left_t); } } } }
bool Bezier::operator!=(const Bezier & other) const { if (m_isEmpty != other.isEmpty()) return true; if (m_cp0 != other.cp0()) return true; if (m_cp1 != other.cp1()) return true; return false; }
CtrlSliderBg::CtrlSliderBg( intf_thread_t *pIntf, CtrlSliderCursor &rCursor, const Bezier &rCurve, VarPercent &rVariable, int thickness, VarBool *pVisible, const UString &rHelp ): CtrlGeneric( pIntf, rHelp, pVisible ), m_rCursor( rCursor ), m_rVariable( rVariable ), m_thickness( thickness ), m_rCurve( rCurve ), m_width( rCurve.getWidth() ), m_height( rCurve.getHeight() ) { }
CtrlSliderCursor::CtrlSliderCursor( intf_thread_t *pIntf, const GenericBitmap &rBmpUp, const GenericBitmap &rBmpOver, const GenericBitmap &rBmpDown, const Bezier &rCurve, VarPercent &rVariable, VarBool *pVisible, const UString &rTooltip, const UString &rHelp ): CtrlGeneric( pIntf, rHelp, pVisible ), m_fsm( pIntf ), m_rVariable( rVariable ), m_tooltip( rTooltip ), m_width( rCurve.getWidth() ), m_height( rCurve.getHeight() ), m_cmdOverDown( this, &transOverDown ), m_cmdDownOver( this, &transDownOver ), m_cmdOverUp( this, &transOverUp ), m_cmdUpOver( this, &transUpOver ), m_cmdMove( this, &transMove ), m_cmdScroll( this, &transScroll ), m_lastPercentage( 0 ), m_xOffset( 0 ), m_yOffset( 0 ), m_pEvt( NULL ), m_rCurve( rCurve ) { // Build the images of the cursor OSFactory *pOsFactory = OSFactory::instance( getIntf() ); m_pImgUp = pOsFactory->createOSGraphics( rBmpUp.getWidth(), rBmpUp.getHeight() ); m_pImgUp->drawBitmap( rBmpUp, 0, 0 ); m_pImgDown = pOsFactory->createOSGraphics( rBmpDown.getWidth(), rBmpDown.getHeight() ); m_pImgDown->drawBitmap( rBmpDown, 0, 0 ); m_pImgOver = pOsFactory->createOSGraphics( rBmpOver.getWidth(), rBmpOver.getHeight() ); m_pImgOver->drawBitmap( rBmpOver, 0, 0 ); // States m_fsm.addState( "up" ); m_fsm.addState( "over" ); m_fsm.addState( "down" ); // Transitions m_fsm.addTransition( "over", "mouse:left:down", "down", &m_cmdOverDown ); m_fsm.addTransition( "down", "mouse:left:up", "over", &m_cmdDownOver ); m_fsm.addTransition( "over", "leave", "up", &m_cmdOverUp ); m_fsm.addTransition( "up", "enter", "over", &m_cmdUpOver ); m_fsm.addTransition( "down", "motion", "down", &m_cmdMove ); m_fsm.addTransition( "over", "scroll", "over", &m_cmdScroll ); // Initial state m_fsm.setState( "up" ); m_pImg = m_pImgUp; // Observe the position variable m_rVariable.addObserver( this ); // Initial position of the cursor m_lastPercentage = m_rVariable.get(); }
bool are_equal(Bezier A, Bezier B) { int maxSize = max(A.size(), B.size()); double t = 0., dt = 1./maxSize; for(int i = 0; i <= maxSize; i++) { EXPECT_FLOAT_EQ(A.valueAt(t), B.valueAt(t));// return false; t += dt; } return true; }
/** Changes the basis of p to be bernstein. \param p the Symmetric basis polynomial \returns the Bernstein basis polynomial if the degree is even q is the order in the symmetrical power basis, if the degree is odd q is the order + 1 n is always the polynomial degree, i. e. the Bezier order sz is the number of bezier handles. */ void sbasis_to_bezier (Bezier & bz, SBasis const& sb, size_t sz) { if (sb.size() == 0) { THROW_RANGEERROR("size of sb is too small"); } size_t q, n; bool even; if (sz == 0) { q = sb.size(); if (sb[q-1][0] == sb[q-1][1]) { even = true; --q; n = 2*q; } else { even = false; n = 2*q-1; } } else { q = (sz > 2*sb.size()-1) ? sb.size() : (sz+1)/2; n = sz-1; even = false; } bz.clear(); bz.resize(n+1); double Tjk; for (size_t k = 0; k < q; ++k) { for (size_t j = k; j < n-k; ++j) // j <= n-k-1 { Tjk = binomial(n-2*k-1, j-k); bz[j] += (Tjk * sb[k][0]); bz[n-j] += (Tjk * sb[k][1]); // n-k <-> [k][1] } } if (even) { bz[q] += sb[q][0]; } // the resulting coefficients are with respect to the scaled Bernstein // basis so we need to divide them by (n, j) binomial coefficient for (size_t j = 1; j < n; ++j) { bz[j] /= binomial(n, j); } bz[0] = sb[0][0]; bz[n] = sb[0][1]; }
// suggested by Sederberg. double Bernsteins::horner(Bezier bz, double t) { double u, tn, tmp; u = 1.0 - t; tn = 1.0; tmp = bz.at0() * u; for(size_t i = 1; i < bz.degree(); ++i) { tn *= t; tmp = (tmp + tn*choose<double>(bz.order(), (unsigned)i)*bz[i]) * u; } return (tmp + tn*t*bz.at1()); }
/** Find all t s.t s(t) = 0 \param a sbasis function \returns vector of zeros (roots) */ std::vector<double> roots(SBasis const & s) { switch(s.size()) { case 0: return std::vector<double>(); case 1: return roots1(s); default: { Bezier bz; sbasis_to_bezier(bz, s); return bz.roots(); } } }
Bezier Bezier::join(const Bezier * other) const { Bezier bezier; bool otherIsEmpty = (other == NULL || other->isEmpty()); if (isEmpty() && otherIsEmpty) { return bezier; } else { if (isEmpty()) { bezier.set_cp0(m_endpoint0); bezier.set_cp1(other->cp1()); } else if (other->isEmpty()) { bezier.set_cp1(other->m_endpoint1); bezier.set_cp0(cp0()); } else { bezier.set_cp0(cp0()); bezier.set_cp1(other->cp1()); } } return bezier; }
Bezier Bezier::fromElement(QDomElement & element) { Bezier bezier; if (element.tagName().compare("bezier") != 0) return bezier; QDomElement point = element.firstChildElement("cp0"); if (point.isNull()) return bezier; double x = point.attribute("x").toDouble(); double y = point.attribute("y").toDouble(); bezier.set_cp0(QPointF(x, y)); point = element.firstChildElement("cp1"); x = point.attribute("x").toDouble(); y = point.attribute("y").toDouble(); bezier.set_cp1(QPointF(x, y)); return bezier; }
ActionRetCodeEnum RotoShapeRenderNode::isIdentity(TimeValue time, const RenderScale & scale, const RectI & roi, ViewIdx view, const ImagePlaneDesc& /*plane*/, TimeValue* inputTime, ViewIdx* inputView, int* inputNb, ImagePlaneDesc* /*inputPlane*/) { *inputView = view; NodePtr node = getNode(); *inputNb = -1; RotoDrawableItemPtr rotoItem = getAttachedRotoItem(); if (!rotoItem) { return eActionStatusFailed; } Bezier* isBezier = dynamic_cast<Bezier*>(rotoItem.get()); if (!rotoItem || !rotoItem->isActivated(time, view) || (isBezier && ((!isBezier->isCurveFinished(view) && !isBezier->isOpenBezier()) || isBezier->getControlPointsCount(view) <= 1))) { *inputTime = time; *inputNb = 0; return eActionStatusOK; } bool isPainting = isDuringPaintStrokeCreation(); RectD maskRod; getRoDFromItem(rotoItem, time, view, isPainting, &maskRod); RectI maskPixelRod; maskRod.toPixelEnclosing(scale, getAspectRatio(-1), &maskPixelRod); if ( !maskPixelRod.intersects(roi) ) { *inputTime = time; *inputNb = 0; } return eActionStatusOK; } // isIdentity
double AiCarStandard::GetPatchRadius(const Bezier & patch) { if (patch.GetNextPatch() && patch.GetNextPatch()->GetNextPatch()) { double track_radius = 0; /*Vec3 d1 = -GetPatchDirection(patch); Vec3 d2 = GetPatchDirection(*patch.GetNextPatch());*/ Vec3 d1 = -(patch.GetNextPatch()->GetRacingLine() - patch.GetRacingLine()); Vec3 d2 = patch.GetNextPatch()->GetNextPatch()->GetRacingLine() - patch.GetNextPatch()->GetRacingLine(); d1[2] = 0; d2[2] = 0; float d1mag = d1.Magnitude(); float d2mag = d2.Magnitude(); float diff = d2mag - d1mag; double dd = ((d1mag < 0.0001) || (d2mag < 0.0001)) ? 0.0 : d1.Normalize().dot(d2.Normalize()); float angle = acos((dd>=1.0L)?1.0L:(dd<=-1.0L)?-1.0L:dd); float d1d2mag = d1mag + d2mag; float alpha = (d1d2mag < 0.0001) ? 0.0f : (M_PI * diff + 2.0 * d1mag * angle) / d1d2mag / 2.0; if (fabs(alpha - M_PI/2.0) < 0.001) track_radius = 10000.0; else track_radius = d1mag / 2.0 / cos(alpha); return track_radius; } else //fall back return 0; }
void Draw_Bezier(float width, float height) { float x = width / 2; float y = height / 2; Matrix4 t; t.makeTranslate(-x, -y, 0); Matrix4 c = objCamera.c; c = t*c; c.transpose(); glLoadMatrixd(c.getPointer()); glColor3f(0, 0, 1); my = Bezier(width, height, angle); for (float t1 = -0.5; t1 < 0.49; t1 += 0.01) { for (float t2 = -0.5; t2 < 0.49; t2 += 0.01) { my.tessellate(t1, t2, .1); } } t.makeTranslate(x, -y, 0); c = objCamera.c; c = t*c; c.transpose(); glLoadMatrixd(c.getPointer()); glColor3f(1, 0, 0); my2 = Bezier(width, height, angle); for (float t1 = -0.5; t1 < 0.49; t1 += 0.01) { for (float t2 = -0.5; t2 < 0.49; t2 += 0.01) { my.tessellate(t1, t2, .1); } } }
TEST(Bezier, BezierFunctions) { MathVector<float, 3> p[4], l[4], r[4]; p[0].set(-1,0,0); p[1].set(-1,1,0); p[2].set(1,1,0); p[3].set(1,0,0); Bezier b; b.deCasteljauHalveCurve(p, l, r); EXPECT_EQ(l[0],(MathVector<float, 3>(-1, 0, 0))); EXPECT_EQ(l[1],(MathVector<float, 3>(-1, 0.5, 0))); EXPECT_EQ(l[2],(MathVector<float, 3>(-0.5, 0.75, 0))); EXPECT_EQ(l[3],(MathVector<float, 3>(0, 0.75, 0))); EXPECT_EQ(r[3],(MathVector<float, 3>(1, 0, 0))); EXPECT_EQ(r[2],(MathVector<float, 3>(1, 0.5, 0))); EXPECT_EQ(r[1],(MathVector<float, 3>(0.5, 0.75, 0))); EXPECT_EQ(r[0],(MathVector<float, 3>(0, 0.75, 0))); //TODO Commented due to "stack smashing" error // b.setFromCorners(MathVector<float, 3>(1, 0, 1), // MathVector<float, 3>(-1, 0, 1), // MathVector<float, 3>(1, 0, -1), // MathVector<float, 3>(-1,0,-1)); // EXPECT_FALSE(b.checkForProblems()); }
void draw() { glColor3f(0, 1, 0); if (i < 1) { glColor3f(0, 1, 0); Vector4 test = x1.lip(i, .1); drawSphere(test); i += .005; } else if (i >= 1 && i2 < 1) { Vector4 test = x2.lip(i2, .1); drawSphere(test); i2 += .005; } else if (i2 >= 1 && i3 < 1) { Vector4 test = x3.lip(i3, .1); drawSphere(test); i3 += .005; } else { Vector4 test = x4.lip(i4, .1); drawSphere(test); i4 += .005; if (i4 > .99) { i = 0; i2 = 0; i3 = 0; i4 = 0; } } }
void Bezier::find_bezier_roots(std::vector<double> &solutions, double left_t, double right_t) const { Bezier bz = *this; //convex_hull_marching(bz, bz, solutions, left_t, right_t); //return; // a constant bezier, even if identically zero, has no roots if (bz.isConstant()) { return; } while(bz[0] == 0) { debug(std::cout << "deflate\n"); bz = bz.deflate(); solutions.push_back(0); } if (bz.degree() == 1) { debug(std::cout << "linear\n"); if (SGN(bz[0]) != SGN(bz[1])) { double d = bz[0] - bz[1]; if(d != 0) { double r = bz[0] / d; if(0 <= r && r <= 1) solutions.push_back(r); } } return; } //std::cout << "initial = " << bz << std::endl; Bernsteins B(solutions); B.find_bernstein_roots(bz, 0, left_t, right_t); //std::cout << solutions << std::endl; }
void ShapeMaker::cubicTo(double x1, double y1, double x2, double y2, double ax, double ay) { Point a(lastx,lasty); Point b(x1,y1); Point c(x2,y2); Point d(ax,ay); Bezier cubic (a, b, c, d); double t0, t1; int cInflections = cubic.computeInflections (t0, t1); if (cInflections == 0) { cubicTo(cubic); } else if (cInflections == 1) { Bezier cubic0 = cubic.split (t0); cubicTo (cubic0); cubicTo (cubic); } else { Bezier cubic0 = cubic.split (t0); cubicTo (cubic0); Bezier cubic1 = cubic.split (1 - (1 - t1) / (1 - t0)); cubicTo (cubic1); cubicTo (cubic); } lastx = ax; lasty = ay; smoothx = ax - x2; smoothy = ay - y2; }
///trim the patch's width in-place void AiCarStandard::TrimPatch(Bezier & patch, float trimleft_front, float trimright_front, float trimleft_back, float trimright_back) { Vec3 frontvector = (patch.GetPoint(0,3) - patch.GetPoint(0,0)); Vec3 backvector = (patch.GetPoint(3,3) - patch.GetPoint(3,0)); float frontwidth = frontvector.Magnitude(); float backwidth = backvector.Magnitude(); if (trimleft_front + trimright_front > frontwidth) { float scale = frontwidth/(trimleft_front + trimright_front); trimleft_front *= scale; trimright_front *= scale; } if (trimleft_back + trimright_back > backwidth) { float scale = backwidth/(trimleft_back + trimright_back); trimleft_back *= scale; trimright_back *= scale; } Vec3 newfl = patch.GetPoint(0,0); Vec3 newfr = patch.GetPoint(0,3); Vec3 newbl = patch.GetPoint(3,0); Vec3 newbr = patch.GetPoint(3,3); if (frontvector.Magnitude() > 0.001) { Vec3 trimdirection_front = frontvector.Normalize(); newfl = patch.GetPoint(0,0) + trimdirection_front*trimleft_front; newfr = patch.GetPoint(0,3) - trimdirection_front*trimright_front; } if (backvector.Magnitude() > 0.001) { Vec3 trimdirection_back = backvector.Normalize(); newbl = patch.GetPoint(3,0) + trimdirection_back*trimleft_back; newbr = patch.GetPoint(3,3) - trimdirection_back*trimright_back; } patch.SetFromCorners(newfl, newfr, newbl, newbr); }
TEST_F(ChainTest, DegreeElevation) { EXPECT_TRUE(are_equal(wiggle, wiggle)); Bezier Q = wiggle; Bezier P = Q.elevate_degree(); EXPECT_EQ(P.size(), Q.size()+1); //EXPECT_EQ(0, P.forward_difference(1)[0]); EXPECT_TRUE(are_equal(Q, P)); Q = wiggle; P = Q.elevate_to_degree(10); EXPECT_EQ(10, P.order()); EXPECT_TRUE(are_equal(Q, P)); //EXPECT_EQ(0, P.forward_difference(10)[0]); /*Q = wiggle.elevate_degree(); P = Q.reduce_degree(); EXPECT_EQ(P.size()+1, Q.size()); EXPECT_TRUE(are_equal(Q, P));*/ }
Bezier subRight(Bezier bz, double t) { unsigned order = bz.order(); unsigned N = order+1; std::valarray<Coord> row(N); for (unsigned i = 0; i < N; i++) row[i] = bz[i]; // Triangle computation const double omt = (1-t); Bezier Right = bz; Right[order] = row[order]; for (unsigned i = 1; i < N; i++) { for (unsigned j = 0; j < N - i; j++) { row[j] = omt*row[j] + t*row[j+1]; } Right[order-i] = row[order-i]; } return Right; }
/** Changes the basis of p to be sbasis. \param p the Bernstein basis polynomial \returns the Symmetric basis polynomial if the degree is even q is the order in the symmetrical power basis, if the degree is odd q is the order + 1 n is always the polynomial degree, i. e. the Bezier order */ void bezier_to_sbasis (SBasis & sb, Bezier const& bz) { size_t n = bz.order(); size_t q = (n+1) / 2; size_t even = (n & 1u) ? 0 : 1; sb.clear(); sb.resize(q + even, Linear(0, 0)); double Tjk; for (size_t k = 0; k < q; ++k) { for (size_t j = k; j < q; ++j) { Tjk = sgn(j, k) * binomial(n-j-k, j-k) * binomial(n, k); sb[j][0] += (Tjk * bz[k]); sb[j][1] += (Tjk * bz[n-k]); // n-j <-> [j][1] } for (size_t j = k+1; j < q; ++j) { Tjk = sgn(j, k) * binomial(n-j-k-1, j-k-1) * binomial(n, k); sb[j][0] += (Tjk * bz[n-k]); sb[j][1] += (Tjk * bz[k]); // n-j <-> [j][1] } } if (even) { for (size_t k = 0; k < q; ++k) { Tjk = sgn(q,k) * binomial(n, k); sb[q][0] += (Tjk * (bz[k] + bz[n-k])); } sb[q][0] += (binomial(n, q) * bz[q]); sb[q][1] = sb[q][0]; } sb[0][0] = bz[0]; sb[0][1] = bz[n]; }
void Bezier::Attach(Bezier & other, bool reverse) { /*if (!reverse) { //move the other patch to the location of this patch and force its // intermediate points into a nice grid layout other.SetFromCorners(other.points[0][0], other.points[0][3], points[0][0], points[0][3]); for (int x = 0; x < 4; x++) { //slope points in the forward direction Vec3 slope = other.points[0][x] - points[3][x]; if (slope.Magnitude() > 0.0001) slope = slope.Normalize(); float otherlen = (other.points[0][x] - other.points[3][x]).Magnitude(); float mylen = (points[0][x] - points[3][x]).Magnitude(); float meanlen = (otherlen + mylen)/2.0; float leglen = meanlen / 3.0; if (slope.Magnitude() > 0.0001) { other.points[2][x] = other.points[3][x] + slope*leglen; points[1][x] = points[0][x] + slope*(-leglen); } else { other.points[2][x] = other.points[3][x]; points[1][x] = points[0][x]; } } }*/ //CheckForProblems(); //store the pointer to next patch next_patch = &other; //calculate the track radius at the connection of this patch and next patch Vec3 a = SurfCoord(0.5,0.0); Vec3 b = SurfCoord(0.5,1.0); Vec3 c = other.SurfCoord(0.5,1.0); if (reverse) { a = SurfCoord(0.5,1.0); b = SurfCoord(0.5,0.0); c = other.SurfCoord(0.5,0.0); //Reverse(); } //racing_line = a; Vec3 d1 = a - b; Vec3 d2 = c - b; float diff = d2.Magnitude() - d1.Magnitude(); double dd = ((d1.Magnitude() < 0.0001) || (d2.Magnitude() < 0.0001)) ? 0.0 : d1.Normalize().dot(d2.Normalize()); float angle = acos((dd>=1.0L)?1.0L:(dd<=-1.0L)?-1.0L:dd); float d1d2mag = d1.Magnitude() + d2.Magnitude(); float alpha = (d1d2mag < 0.0001) ? 0.0f : (M_PI * diff + 2.0 * d1.Magnitude() * angle) / d1d2mag / 2.0; if (fabs(alpha - M_PI/2.0) < 0.001) track_radius = 10000.0; else track_radius = d1.Magnitude() / 2.0 / cos(alpha); if (d1.Magnitude() < 0.0001) track_curvature = 0.0; else track_curvature = 2.0 * cos(alpha) / d1.Magnitude(); //determine it's a left or right turn at the connection Vec3 d = d1.cross(d2); if (fabs(d[0]) < 0.1 && fabs(d[1]) < 0.1 && fabs(d[2]) < 0.1) { turn = 0; //straight ahead } else if (d[1] > 0.0) turn = -1; //left turn ahead else turn = 1; //right turn ahead //calculate distance from start of the road if (other.next_patch == NULL || reverse) other.dist_from_start = dist_from_start + d1.Magnitude(); length = d1.Magnitude(); }