void Mobius::grandmasRecipie(complex<double> ta, complex<double> tb, Matrix &ma, Matrix &mb) { complex<double> tab; complex<double> z0; // first solve the quadratic equation x^2 - ta.tb.x + ta^2 + tb^2 = 0 // using -b +- sqrt(b^2 - 4ac) / 2a a = 1, b = -ta.tb and c = ta^2 + tb^2 // set tab to x tab = solveQuadratic(complex<double>(1,0), complex<double>(-1, 0) * ta * tb, (ta * ta) + (tb * tb)); // z0 is another big calc z0 = ((tab - r_2) * tb) / ((tb * tab) - (r_2 * ta) + (i_2 * tab)); // finally generate the two generator matrices ma.setMatrix(ta / r_2, ((ta*tab) - (r_2 * tb) + i_4) / (((r_2*tab) + r_4) * z0), (((ta*tab) - (r_2 * tb) - i_4) * z0) / ((r_2*tab) - r_4), ta / r_2); mb.setMatrix((tb - i_2)/ r_2, tb / r_2, tb / r_2, (tb + i_2)/ r_2); return; }
complex<double> Mobius::fixedPoint(Matrix m) { // the fixed points are found by solving the quadratic formula // cz^2 + (d - a)z - b return solveQuadratic(m._c, (m._d-m._a), -m._b); }
//(r⃗ ·r⃗)t2 +2r⃗ ·(r⃗o −cen⃗ter)t+(r⃗o −cen⃗ter)·(r⃗o −cen⃗ter)−R2 =0 bool Sphere::intersect(const Ray& r, const float tmin, float &t_max){ float t0, t1; // solutions for t if the ray intersects // analytic solution Vector3D L = r.getOrigin() - center; // std::cout << "L " << L << std::endl; float a = r.getDir().dot(r.getDir()); // std::cout << "a " << a << std::endl; float b = 2 * r.getDir().dot(L); // std::cout << "b " << b << std::endl; float c = L.dot(L) - (radius * radius ) ; // std::cout << "c " << c << std::endl; if (!solveQuadratic(a, b, c, t0, t1)) return false; if (t0 > t1) std::swap(t0, t1); if (t0 < 0) { t0 = t1; // if t0 is negative, let's use t1 instead if (t0 < 0) return false; // both t0 and t1 are negative } t_max = t0; return true; }
// degree == 3 std::vector<double> Polynomial::solveCubic(){ if(coeffs[3] == 0){ return solveQuadratic(); } if(coeffs[1] == 0 && coeffs[2] == 0){ return std::vector<double>(1,cbrt(-coeffs[0]/coeffs[3])); } if(coeffs[0] == 0){ std::vector<double> temp; temp.push_back(coeffs[1]),temp.push_back(coeffs[2]); temp.push_back(coeffs[3]); Polynomial p(temp,2); std::vector<double> retVal = p.solveQuadratic(); retVal.push_back(0); return retVal; } double firstRoot = this->newtonRaphson(1.0); Polynomial quad = this->syntheticDiv(firstRoot); std::vector<double> temp = quad.solveQuadratic(); std::vector<double> retVal; retVal.push_back(temp[0]); retVal.push_back(temp[1]); retVal.push_back(firstRoot); return retVal; }
double distanceMarcher::updatePointOrderOne(int i) { double a,b,c; a=b=c=0; int naddr=0; for (int dim=0; dim<dim_; dim++) { double value = maxDouble; for (int j=-1; j<2; j+=2) // each direction { naddr = _getN(i,dim,j,Mask); if (naddr!=-1 && flag_[naddr]==Frozen)// && (!ignore_mask_ || !ignore_mask_[naddr])) { if (distance_[naddr]<value) { value = distance_[naddr]; } } } if (value<maxDouble) { // printf("yay, %f, %f\n", value, maxDouble); a+=idx2_[dim]; b-=idx2_[dim]*2*value; c+=idx2_[dim]*pow(value,2); } } return solveQuadratic(i,a,b,c); }
bool Sphere::intersect(const Ray& ray, Intersection& inter) { Vector temp = ray.o - center; float a = dot(ray.d, ray.d); float b = 2 * dot(temp, ray.d); float c = dot(temp, temp) - radius * radius; float t1, t2; if (solveQuadratic(a, b, c, &t1, &t2)) { float t = std::min(t1, t2); if (t > EPSILON && t < inter.t) { ray.rayEpsilon = 1e-3f * t; inter.normal = (temp + ray.d * t) / radius; inter.ray = ray; inter.t = t; inter.hitPoint = ray(t); inter.hitObject = true; inter.material = getMaterial(); return true; } } return false; }
std::vector<std::complex<double> > PolyBase::calcRoots(const double epsilon) /** Calculate all the roots of the polynominal. Uses the GSL which uses a Hessian reduction of the characteristic compainion matrix. \f[ A= \left( -a_{m-1}/a_m -a_{m-2}/a_m ... -a_0/a_m \right) \f] where the matrix component below A is the Indenty. However, GSL requires that the input coefficient is a_m == 1, hence the call to this->compress(). @param epsilon :: tolerance factor (-ve to use default) @return roots (not sorted/uniqued) */ { compress(epsilon); std::vector<std::complex<double> > Out(iDegree); // Zero State: if (iDegree==0) return Out; // x+a_0 =0 if (iDegree==1) { Out[0]=std::complex<double>(-afCoeff[0]); return Out; } // x^2+a_1 x+c = 0 if (iDegree==2) { solveQuadratic(Out[0],Out[1]); return Out; } // x^3+a_2 x^2+ a_1 x+c=0 if (iDegree==2) { solveCubic(Out[0],Out[1],Out[2]); return Out; } // THERE IS A QUARTIC / QUINTIC Solution availiable but... // WS contains the the hessian matrix if required (eigenvalues/vectors) // gsl_poly_complex_workspace* WS (gsl_poly_complex_workspace_alloc(iDegree+1)); double* RZ=new double[2*(iDegree+1)]; gsl_poly_complex_solve(&afCoeff.front(),iDegree+1, WS, RZ); for(int i=0;i<iDegree;i++) Out[i]=std::complex<double>(RZ[2*i],RZ[2*i+1]); gsl_poly_complex_workspace_free (WS); delete [] RZ; return Out; }
double travelTimeMarcher::updatePointOrderTwo(int i) { double a,b,c; a=b=c=0; int naddr=0; for (int dim=0; dim<dim_; dim++) { double value1 = maxDouble; double value2 = maxDouble; for (int j=-1; j<2; j+=2) // each direction { naddr = _getN(i,dim,j,Mask); if (naddr!=-1 && flag_[naddr]==Frozen) { if (distance_[naddr]<value1) { value1 = distance_[naddr]; int naddr2 = _getN(i,dim,j*2,Mask); if (naddr2!=-1 && flag_[naddr2]==Frozen && ((distance_[naddr2]<=value1 && value1 >=0) || (distance_[naddr2]>=value1 && value1 <=0))) { value2=distance_[naddr2]; if (phi_[naddr2] * phi_[naddr] < 0) value2 *= -1; } } } } if (value2<maxDouble) { double tp = oneThird*(4*value1-value2); a+=idx2_[dim]*aa; b-=idx2_[dim]*2*aa*tp; c+=idx2_[dim]*aa*pow(tp,2); } else if (value1<maxDouble) { a+=idx2_[dim]; b-=idx2_[dim]*2*value1; c+=idx2_[dim]*pow(value1,2); } } return solveQuadratic(i,a,b,c); }
bool VRSim::solveRaycast(const cavr::gfx::Ray& ray, const cavr::math::vec3f& pos, float radius_sq) { float t0, t1; cavr::math::vec3f L = ray.origin() - pos; float a = ray.direction().dot(ray.direction()); float b = 2 * ray.direction().dot(L); float c = L.dot(L) - radius_sq; if(!solveQuadratic(a, b, c, t0, t1)) return false; if (t0 > t1) std::swap(t0, t1); if (t0 < 0) { t0 = t1; // if t0 is negative, let's use t1 instead if (t0 < 0) return false; // both t0 and t1 are negative } return true; }
bool Sphere::intersectP(const Ray& ray) { Vector temp = ray.o - center; float a = dot(ray.d, ray.d); float b = 2 * dot(temp, ray.d); float c = dot(temp, temp) - radius * radius; float t1, t2; if (solveQuadratic(a, b, c, &t1, &t2)) { float t = std::min(t1, t2); if (t > EPSILON) { return true; } } return false; }
tuple solveQuadraticWrapper( double a, double b, double c ) { double x[2]; int s = solveQuadratic( a, b, c, x ); switch( s ) { case 0 : return tuple(); case 1 : return make_tuple( x[0] ); case 2 : return make_tuple( x[0], x[1] ); default : PyErr_SetString( PyExc_ArithmeticError, "Infinite solutions." ); throw_error_already_set(); return tuple(); // should never get here } }
void computeChromaticTuneLimits(LINE_LIST *beamline) { long i, j, n, p; double c1, c2, c3, tuneValue[5], solution[2]; for (i=0; i<2; i++) { if (beamline->chromDeltaHalfRange<=0) { beamline->tuneChromUpper[i] = beamline->tuneChromLower[i] = beamline->tune[i]; } else { tuneValue[0] = beamline->tune[i]; /* polynomial coefficients */ c1 = beamline->chromaticity[i]; c2 = beamline->chrom2[i]/2.0; c3 = beamline->chrom3[i]/6.0; tuneValue[1] = beamline->tune[i] + beamline->chromDeltaHalfRange*c1 + sqr(beamline->chromDeltaHalfRange)*c2 + ipow(beamline->chromDeltaHalfRange, 3)*c3; tuneValue[2] = beamline->tune[i] - beamline->chromDeltaHalfRange*c1 + sqr(beamline->chromDeltaHalfRange)*c2 - ipow(beamline->chromDeltaHalfRange, 3)*c3; p = 3; /* find extrema */ n = solveQuadratic(3*c3, 2*c2, c1, solution); for (j=0; j<n; j++) { if (fabs(solution[j])>beamline->chromDeltaHalfRange) continue; tuneValue[p] = beamline->tune[i] + solution[j]*c1 + sqr(solution[j])*c2 + ipow(solution[j], 3)*c3; p += 1; } find_min_max(beamline->tuneChromLower+i, beamline->tuneChromUpper+i, tuneValue, p); } } }
int solveCubic( T a, T b, T c, T d, T result[3] ) { if( a == 0 ) return solveQuadratic( b, c, d, result ); T f = ((3 * c / a) - ((b * b) / (a * a))) / 3; T g = ((2 * b * b * b) / (a * a * a) - (9 * b * c) / (a * a) + (27 * d) / (a)) / 27; T h = g * g / 4 + f * f * f / 27; if( f == 0 && g == 0 && h == 0 ) { result[0] = -math<T>::cbrt( d / a ); return 1; } else if( h > 0 ) { // 1 root T r = -( g / 2 ) + math<T>::sqrt( h ); T s = math<T>::cbrt( r ); T t = -(g / 2) - math<T>::sqrt( h ); T u = math<T>::cbrt( t ); result[0] = (s + u) - (b / (3 * a)); return 1; } else { // 3 roots T i = math<T>::sqrt( (g * g / 4) - h ); T j = math<T>::cbrt( i ); T k = math<T>::acos( -(g / (2 * i)) ); T l = -j; T m = math<T>::cos( k / 3 ); T n = math<T>::sqrt(3) * math<T>::sin( k / 3 ); T p = -b / (3 * a); result[0] = 2 * j * math<T>::cos(k / 3) - (b / (3 * a)); result[1] = l * (m + n) + p; result[2] = l * (m - n) + p; return 3; } }
int HitOutline::Raycast(Point2D p, Vector2D v, Scalar maxTime, Hit* hitArr, int hitArrSize, Scalar sense) { //local data: Bart Hit localHitArr[100]; int localHitArrSize=100; int hitCount = 0; // TODO: Currently very slow, brute force! int lineVertexCount = m_Lines.size(); int quadVertexCount = m_Quads.size(); Scalar epsilon = 1e-6; Point2D p1 = p; Point2D p2 = p+v; Point2D orig(0,0); Scalar vDv = v.Dot(v); Vector2D n = v.Orthogonal(); // Line-line intersections. if( lineVertexCount > 0 ) { Point2D* lines = &m_Lines[0]; for( int i=0; i<lineVertexCount && hitCount<localHitArrSize; i += 2 ) { Point2D q1 = lines[i+0]; Point2D q2 = lines[i+1]; Vector2D ortho = (q2-q1).Orthogonal(); if( (dot(ortho, v) * sense < 0) || sense==0) { Scalar time1; Scalar time2; if( IntersectLines(p1, p2, q1, q2, time1, time2) ) { if( time1 >= 0 && time1 < maxTime && time2 >= 0 && time2 <= 1 ) { Hit hit; hit.Time = time1; hit.Point = p + time1 * v; hit.Normal = ortho.Normalized(); localHitArr[hitCount++] = hit; } } } } } // Line-quadratic intersections. if( quadVertexCount > 0 ) { Point2D* quads = &m_Quads[0]; for( int i=0; i<quadVertexCount && hitCount<localHitArrSize; i += 3 ) { Vector2D q0 = quads[i+0] - p; Vector2D q1 = quads[i+1] - p; Vector2D q2 = quads[i+2] - p; // Hit only possible if: // (1) not all points are on same side of ray, // // (2) and some points are in front of ray (currently not checked, handled by abc formula) Scalar dot_n_q0 = dot(n,q0); Scalar dot_n_q1 = dot(n,q1); Scalar dot_n_q2 = dot(n,q2); if( dot_n_q0 <= 0 && dot_n_q1 <= 0 && dot_n_q2 <= 0 ) continue; if( dot_n_q0 >= 0 && dot_n_q1 >= 0 && dot_n_q2 >= 0 ) continue; Scalar ts[2]; Scalar a = 2*dot_n_q1-dot_n_q0-dot_n_q2; Scalar b = 2*dot_n_q0-2*dot_n_q1; Scalar c = -dot_n_q0; int n = solveQuadratic(a,b,c,ts); for( int j=0; j<n && hitCount < localHitArrSize; ++j ) { Scalar t = ts[j]; if( t >= 0 && t <= 1 ) { Vector2D diff = (2*(q2-q1)+2*(q0-q1))*t+2*(q1-q0); Vector2D ortho = diff.Orthogonal(); if( (dot(ortho, v) * sense < 0) || sense==0) { Vector2D h = lerp( lerp(q0,q1,t), lerp(q1,q2,t), t); Scalar time = h.Dot(v) / vDv; //time >= -maxTime if( time >= 0 && time < maxTime ) { Hit hit; hit.Point = p+h; hit.Time = time; hit.Normal = ortho.Normalized(); localHitArr[hitCount++] = hit; } } } } } } std::sort(localHitArr, localHitArr+hitCount, sortHitOnTime); //Bart for( int i=0; i<hitCount && i < hitArrSize; ++i ) { hitArr[i]=localHitArr[i]; } return hitCount; }
static void renderDiskExact(IntegratorT& integrator, V3f p, V3f n, float r) { int faceRes = integrator.res(); float plen2 = p.length2(); if(plen2 == 0) // Sanity check return; // Angle from face normal to edge is acos(1/sqrt(3)). static float cosFaceAngle = 1.0f/sqrtf(3); static float sinFaceAngle = sqrtf(2.0f/3.0f); for(int iface = 0; iface < 6; ++iface) { // Avoid rendering to the current face if the disk definitely doesn't // touch it. First check the cone angle if(sphereOutsideCone(p, plen2, r, MicroBuf::faceNormal(iface), cosFaceAngle, sinFaceAngle)) continue; float dot_pFaceN = MicroBuf::dotFaceNormal(iface, p); float dot_nFaceN = MicroBuf::dotFaceNormal(iface, n); // If the disk is behind the camera and the disk normal is relatively // aligned with the face normal (to within the face cone angle), the // disk can't contribute to the face and may be culled. if(dot_pFaceN < 0 && fabs(dot_nFaceN) > cosFaceAngle) continue; // Check whether disk spans the perspective divide for the current // face. Note: sin^2(angle(n, faceN)) = (1 - dot_nFaceN*dot_nFaceN) if((1 - dot_nFaceN*dot_nFaceN)*r*r >= dot_pFaceN*dot_pFaceN) { // When the disk spans the perspective divide, the shape of the // disk projected onto the face is a hyperbola. Bounding a // hyperbola is a pain, so the easiest thing to do is trace a ray // for every pixel on the face and check whether it hits the disk. // // Note that all of the tricky rasterization rubbish further down // could probably be replaced by the following ray tracing code if // I knew a way to compute the tight raster bound. integrator.setFace(iface); for(int iv = 0; iv < faceRes; ++iv) for(int iu = 0; iu < faceRes; ++iu) { // V = ray through the pixel V3f V = integrator.rayDirection(iface, iu, iv); // Signed distance to plane containing disk float t = dot(p, n)/dot(V, n); if(t > 0 && (t*V - p).length2() < r*r) { // The ray hit the disk, record the hit integrator.addSample(iu, iv, t, 1.0f); } } continue; } // If the disk didn't span the perspective divide and is behind the // camera, it may be culled. if(dot_pFaceN < 0) continue; // Having gone through all the checks above, we know that the disk // doesn't span the perspective divide, and that it is in front of the // camera. Therefore, the disk projected onto the current face is an // ellipse, and we may compute a quadratic function // // q(u,v) = a0*u*u + b0*u*v + c0*v*v + d0*u + e0*v + f0 // // such that the disk lies in the region satisfying q(u,v) < 0. To do // this, start with the implicit definition of the disk on the plane, // // norm(dot(p,n)/dot(V,n) * V - p)^2 - r^2 < 0 // // and compute coefficients A,B,C such that // // A*dot(V,V) + B*dot(V,n)*dot(p,V) + C < 0 float dot_pn = dot(p,n); float A = dot_pn*dot_pn; float B = -2*dot_pn; float C = plen2 - r*r; // Project onto the current face to compute the coefficients a0 through // to f0 for q(u,v) V3f pp = MicroBuf::canonicalFaceCoords(iface, p); V3f nn = MicroBuf::canonicalFaceCoords(iface, n); float a0 = A + B*nn.x*pp.x + C*nn.x*nn.x; float b0 = B*(nn.x*pp.y + nn.y*pp.x) + 2*C*nn.x*nn.y; float c0 = A + B*nn.y*pp.y + C*nn.y*nn.y; float d0 = (B*(nn.x*pp.z + nn.z*pp.x) + 2*C*nn.x*nn.z); float e0 = (B*(nn.y*pp.z + nn.z*pp.y) + 2*C*nn.y*nn.z); float f0 = (A + B*nn.z*pp.z + C*nn.z*nn.z); // Finally, transform the coefficients so that they define the // quadratic function in *raster* face coordinates, (iu, iv) float scale = 2.0f/faceRes; float scale2 = scale*scale; float off = 0.5f*scale - 1.0f; float a = scale2*a0; float b = scale2*b0; float c = scale2*c0; float d = ((2*a0 + b0)*off + d0)*scale; float e = ((2*c0 + b0)*off + e0)*scale; float f = (a0 + b0 + c0)*off*off + (d0 + e0)*off + f0; // Construct a tight bound for the ellipse in raster coordinates. int ubegin = 0, uend = faceRes; int vbegin = 0, vend = faceRes; float det = 4*a*c - b*b; // Sanity check; a valid ellipse must have det > 0 if(det <= 0) { // If we get here, the disk is probably edge on (det == 0) or we // have some hopefully small floating point errors (det < 0: the // hyperbolic case we've already ruled out). Cull in either case. continue; } float ub = 0, ue = 0; solveQuadratic(det, 4*d*c - 2*b*e, 4*c*f - e*e, ub, ue); ubegin = std::max(0, Imath::ceil(ub)); uend = std::min(faceRes, Imath::ceil(ue)); float vb = 0, ve = 0; solveQuadratic(det, 4*a*e - 2*b*d, 4*a*f - d*d, vb, ve); vbegin = std::max(0, Imath::ceil(vb)); vend = std::min(faceRes, Imath::ceil(ve)); // By the time we get here, we've expended perhaps 120 FLOPS + 2 sqrts // to set up the coefficients of q(iu,iv). The setup is expensive, but // the bound is optimal so it will be worthwhile vs raytracing, unless // the raster faces are very small. integrator.setFace(iface); for(int iv = vbegin; iv < vend; ++iv) for(int iu = ubegin; iu < uend; ++iu) { float q = a*(iu*iu) + b*(iu*iv) + c*(iv*iv) + d*iu + e*iv + f; if(q < 0) { V3f V = integrator.rayDirection(iface, iu, iv); // compute distance to hit point float z = dot_pn/dot(V, n); integrator.addSample(iu, iv, z, 1.0f); } } } }