#include <algorithm>
#include <array>
#include <complex>
#include <functional>
#include <iostream>
#include <random>
#include <vector>
#include <fstream>
using namespace std;
using Vec2D = complex<float>;
float dot(Vec2D u, Vec2D v) { return real(conj(u)*v); }
float length( Vec2D u ) { return sqrt( norm(u) ); }
using Segment = array<Vec2D,2>;
Vec2D closestPoint( Vec2D x, Segment s ) {
Vec2D u = s[1]-s[0];
float t = clamp(dot(x-s[0],u)/dot(u,u),0.f,1.f);
return (1-t)*s[0] + t*s[1];
}
float random( float rMin, float rMax ) {
const float rRandMax = 1./(float)RAND_MAX;
float u = rRandMax*(float)rand();
return u*(rMax-rMin) + rMin;
}
float G( float r, float R )
{
float GrR = log(R/r)/(2.*M_PI);
if( isnan(GrR) ) return 0;
return GrR;
}
float solve( Vec2D x0,
vector<Segment> segments,
function<float(Vec2D)> f,
function<float(Vec2D)> g
) {
const float eps = 0.001;
const int nWalks = 32;
const int maxSteps = 16;
float sum = 0.;
for( int i = 0; i < nWalks; i++ ) {
Vec2D x = x0;
float R;
int steps = 0;
do {
R = numeric_limits<float>::max();
for( auto s : segments ) {
Vec2D p = closestPoint( x, s );
R = min( R, length(x-p) );
}
float r = R*sqrt(random(0.,1.));
float alpha = random( 0., 2.*M_PI );
Vec2D y = x + Vec2D( r*cos(alpha), r*sin(alpha) );
sum += (M_PI*R*R)*f(y)*G(r,R);
float theta = random( 0., 2.*M_PI );
x = x + Vec2D( R*cos(theta), R*sin(theta) );
steps++;
}
while( R > eps && steps < maxSteps );
sum += g(x);
}
return sum/nWalks;
}
float uref( Vec2D x )
{
return cos(2.f*M_PI*real(x)) * sin(2.f*M_PI*imag(x));
}
float laplace_uref( Vec2D x )
{
return 8.f*(M_PI*M_PI) * cos(2.f*M_PI*real(x)) * sin(2.f*M_PI*imag(x));
}
vector<Segment> scene = {
{{ Vec2D(0.0, 0.0), Vec2D(1.0, 0.0) }},
{{ Vec2D(1.0, 0.0), Vec2D(1.0, 1.0) }},
{{ Vec2D(1.0, 1.0), Vec2D(0.0, 1.0) }},
{{ Vec2D(0.0, 1.0), Vec2D(0.0, 0.0) }}
};
int main( int argc, char** argv )
{
srand( time(NULL) );
ofstream out( "out.csv" );
int s = 128;
for( int j = 0; j < s; j++ )
{
cerr << "row " << j << " of " << s << endl;
for( int i = 0; i < s; i++ )
{
Vec2D x0( (float)i/(float)s, (float)j/(float)s );
float u = solve( x0, scene, laplace_uref, uref );
out << u;
if( i < s-1 ) out << ",";
}
out << endl;
}
return 0;
}