#define _USE_MATH_DEFINES #include #include #include #include "BLUE_NOISE.h" #include "ScallopedSector.h" static const float kTwoPi = (float) (M_PI*2); static float integralOfDistToCircle(float x, float d, float r, float k) { if (r1) y = 1; float theta = asin(y); return (r*(r*(x + k*theta) + k*cos(theta)*d_sin_x) + d*cos(x)*d_sin_x)*.5f; } ScallopedSector::ScallopedSector(Vec2 &_Pt, float _a1, float _a2, Vec2 &P1, float r1, float sign1, Vec2 &P2, float r2, float sign2) { Vec2 v1 = Vec2(P1.x - _Pt.x, P1.y - _Pt.y); Vec2 v2 = Vec2(P2.x - _Pt.x, P2.y - _Pt.y); P = _Pt; a1 = _a1; a2 = _a2; arcs[0].P = P1; arcs[0].r = r1; arcs[0].sign = sign1; arcs[0].d = sqrt(v1.x*v1.x + v1.y*v1.y); arcs[0].rSqrd = arcs[0].r*arcs[0].r; arcs[0].dSqrd = arcs[0].d*arcs[0].d; arcs[0].theta = atan2(v1.y,v1.x); arcs[0].integralAtStart = integralOfDistToCircle(a1 - arcs[0].theta, arcs[0].d, arcs[0].r, arcs[0].sign); arcs[1].P = P2; arcs[1].r = r2; arcs[1].sign = sign2; arcs[1].d = sqrt(v2.x*v2.x + v2.y*v2.y); arcs[1].rSqrd = arcs[1].r*arcs[1].r; arcs[1].dSqrd = arcs[1].d*arcs[1].d; arcs[1].theta = atan2(v2.y,v2.x); arcs[1].integralAtStart = integralOfDistToCircle(a1 - arcs[1].theta, arcs[1].d, arcs[1].r, arcs[1].sign); area = calcAreaToAngle(a2); } float ScallopedSector::calcAreaToAngle(float angle) { float underInner = integralOfDistToCircle(angle - arcs[0].theta, arcs[0].d, arcs[0].r, arcs[0].sign) - arcs[0].integralAtStart; float underOuter = integralOfDistToCircle(angle - arcs[1].theta, arcs[1].d, arcs[1].r, arcs[1].sign) - arcs[1].integralAtStart; return underOuter-underInner; } float ScallopedSector::calcAngleForArea(float area, RNG &rng) { float lo = a1, hi = a2, cur = lo + (hi-lo)*rng.getFloat(); for (int i=0; i<10; i++) { if (calcAreaToAngle(cur) *regions) { std::vector angles; Vec2 v(C.x - P.x, C.y-P.y); float d = sqrt(v.x*v.x + v.y*v.y); if (rFLT_EPSILON) { float invD = 1.0f/d; float x = (d*d - r*r + R*R)*invD*.5f; float k = R*R - x*x; if (k>0) { float y = sqrt(k); float vx = v.x*invD; float vy = v.y*invD; float vx_x = vx*x, vy_x = vy*x; float vx_y = vx*y, vy_y = vy*y; float angle; angle = canonizeAngle(atan2(C2.y + vy_x + vx_y - P.y, C2.x + vx_x - vy_y - P.x)); if (a1outer) { regions->push_back(ScallopedSector(P, a1, a2, arcs[0].P, arcs[0].r, arcs[0].sign, arcs[1].P, arcs[1].r, arcs[1].sign)); } else { if (innerpush_back(ScallopedSector(P, a1, a2, arcs[0].P, arcs[0].r, arcs[0].sign, C, r, -1)); } if (d2push_back(ScallopedSector(P, a1, a2, C, r, 1, arcs[1].P, arcs[1].r, arcs[1].sign)); } } } } /// ScallopedRegion::ScallopedRegion(Vec2 &P, float r1, float r2, float _minArea) : minArea(_minArea) { regions = new std::vector; regions->push_back(ScallopedSector(P, 0, kTwoPi, P, r1, 1, P, r2, 1)); area = (*regions)[0].area; } ScallopedRegion::~ScallopedRegion() { delete regions; } void ScallopedRegion::subtractDisk(Vec2 C, float r) { std::vector *newRegions = new std::vector; area = 0; for (unsigned int i=0; isize(); i++) { ScallopedSector &ss = (*regions)[i]; std::vector *tmp = new std::vector; ss.subtractDisk(C, r, tmp); for (unsigned int j=0; jsize(); j++) { ScallopedSector &nss = (*tmp)[j]; if (nss.area>minArea) { area += nss.area; if (newRegions->size()) { ScallopedSector &last = (*newRegions)[newRegions->size()-1]; if (last.a2==nss.a1 && (last.arcs[0].P==nss.arcs[0].P && last.arcs[0].r==nss.arcs[0].r && last.arcs[0].sign==nss.arcs[0].sign) && (last.arcs[1].P==nss.arcs[1].P && last.arcs[1].r==nss.arcs[1].r && last.arcs[1].sign==nss.arcs[1].sign)) { last.a2 = nss.a2; last.area = last.calcAreaToAngle(last.a2); continue; } } newRegions->push_back(nss); } } delete tmp; } delete regions; regions = newRegions; } Vec2 ScallopedRegion::sample(RNG &rng) { if (!regions->size()) { printf("Fatal error, sampled from empty region."); exit(1); return Vec2(0,0); } else { float a = area*rng.getFloatL(); ScallopedSector &ss = (*regions)[0]; for (unsigned int i=0; isize(); i++) { ss = (*regions)[i]; if (a