Skip to content

Commit

Permalink
New trace algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
Vort committed Jan 8, 2017
1 parent d0a134d commit c78eaa9
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 123 deletions.
17 changes: 10 additions & 7 deletions Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ class ConfigData
[DataMember]
public int iterationCount;
[DataMember]
public double sampleWidthScale;
public double scanRadiusScale;
[DataMember]
public double sampleLengthScale;
public double angleRange;
[DataMember]
public double angleStep;
[DataMember]
public double shoreContrast;
[DataMember]
public double maxDifference;
public double advanceRate;

[DataMember]
public bool debug;
Expand All @@ -49,11 +51,12 @@ static Config()
lon1 = 52.2209239,
lat2 = 64.9032122,
lon2 = 52.2213061,
iterationCount = 500,
sampleWidthScale = 1.7,
sampleLengthScale = 0.6,
iterationCount = 300,
scanRadiusScale = 2.0,
angleRange = 90.0,
angleStep = 4.0,
shoreContrast = 10.0,
maxDifference = 14.0,
advanceRate = 0.5,
debug = false
};
if (File.Exists(fileName))
Expand Down
193 changes: 79 additions & 114 deletions Tracer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
Expand All @@ -7,9 +8,9 @@ namespace RiverTrace
{
class Tracer
{
private int sampleWidth;
private int sampleLength;
private double riverWidthM;
private double scanRadius;
private Color waterColor;
private TileMap tileMap;

void WriteOsm(List<Vector> result)
Expand Down Expand Up @@ -53,6 +54,14 @@ void CalcSampleDimensions(Vector startPoint, Vector direction)
for (int i = 0; i < pickCount; i++)
{
Color refColor = tileMap.GetPixel(pickPoint1.X, pickPoint1.Y);

if (i == 0)
waterColor = refColor;
else
waterColor = new Color((byte)((waterColor.R + refColor.R) / 2),
(byte)((waterColor.G + refColor.G) / 2),
(byte)((waterColor.B + refColor.B) / 2));

for (int j = 0; j < 2; j++)
{
Vector pickPoint2 = pickPoint1;
Expand All @@ -71,96 +80,13 @@ void CalcSampleDimensions(Vector startPoint, Vector direction)
riverHalfWidth[0] /= pickCount;
riverHalfWidth[1] /= pickCount;
double riverWidthPx = riverHalfWidth[0] + riverHalfWidth[1] + 1.0;
sampleWidth = Math.Max((int)Math.Ceiling(riverWidthPx * Config.Data.sampleWidthScale), 5);
sampleLength = Math.Max((int)Math.Ceiling(riverWidthPx * Config.Data.sampleLengthScale), 3);
scanRadius = riverWidthPx * Config.Data.scanRadiusScale;

Vector wp1 = startPoint + sideDirs[0] * (riverWidthPx / 2.0);
Vector wp2 = startPoint + sideDirs[1] * (riverWidthPx / 2.0);
riverWidthM = Projection.Distance(wp1, wp2, Config.Data.zoom);
}

SimpleBitmap GetSample(Vector origin, Vector direction)
{
SimpleBitmap sample = new SimpleBitmap(sampleWidth, sampleLength);

Vector dv = direction.Rotated(-90);
for (int i = 0; i < sampleWidth; i++)
for (int j = 0; j < sampleLength; j++)
{
int xs = sampleWidth / 2 - i;
int ys = j;
double x = xs * dv.X - ys * dv.Y + origin.X;
double y = xs * dv.Y + ys * dv.X + origin.Y;
sample.SetPixel(i, j, tileMap.GetPixel(x, y));
}

return sample;
}

double GetSampleDifference(SimpleBitmap s1, SimpleBitmap s2)
{
double totalDelta = 0.0;
for (int i = 0; i < sampleWidth; i++)
for (int j = 0; j < sampleLength; j++)
{
Color c1 = s1.GetPixel(i, j);
Color c2 = s2.GetPixel(i, j);
double pixelDelta = c1.DifferenceTo(c2);
totalDelta += pixelDelta;
}
return totalDelta / (sampleWidth * sampleLength);
}

void GetBestAngle(Vector lastPoint, Vector lastVector, SimpleBitmap avgSample,
double minAngle, double maxAngle, double step, out SimpleBitmap bestSample,
out double bestDiff, out Vector bestVector, out double bestAngle)
{
SimpleBitmap localBestSample = null;
double localBestDiff = double.MaxValue;
Vector localBestVector = null;
double localBestAngle = 0.0;
var lockObj = new object();

int stepCount = (int)Math.Round((maxAngle - minAngle) / step) + 1;
Parallel.For(0, stepCount, i =>
{
double angle = minAngle + i * step;
Vector rv = lastVector.Rotated(angle);
SimpleBitmap candidateSample = GetSample(lastPoint, rv);
double diff = GetSampleDifference(avgSample, candidateSample);
lock (lockObj)
{
localBestDiff = Math.Min(localBestDiff, diff);
if (diff == localBestDiff)
{
localBestSample = candidateSample;
localBestVector = rv;
localBestAngle = angle;
}
}
});
bestVector = localBestVector;
bestSample = localBestSample;
bestDiff = localBestDiff;
bestAngle = localBestAngle;
}

SimpleBitmap GetAvgSample(SimpleBitmap s1, SimpleBitmap s2)
{
SimpleBitmap sample = new SimpleBitmap(sampleWidth, sampleLength);
for (int i = 0; i < sampleWidth; i++)
for (int j = 0; j < sampleLength; j++)
{
Color c1 = s1.GetPixel(i, j);
Color c2 = s2.GetPixel(i, j);
sample.SetPixel(i, j,
(byte)((c1.R + c2.R) / 2),
(byte)((c1.G + c2.G) / 2),
(byte)((c1.B + c2.B) / 2));
}
return sample;
}

public Tracer()
{
Stopwatch sw = new Stopwatch();
Expand All @@ -181,35 +107,76 @@ public Tracer()

CalcSampleDimensions(p1, lastDirection);

int pixelRange = (int)(scanRadius * 2) + 1;

List<SimpleBitmap> samples = new List<SimpleBitmap>();
SimpleBitmap firstSample = GetSample(p1, lastDirection);
SimpleBitmap avgSample = firstSample;
Vector lastPoint = p1 + lastDirection * sampleLength;
way.Add(lastPoint);
samples.Add(firstSample);

double totalDiff = 0.0;
for (int i = 0; i < Config.Data.iterationCount; i++)

Vector lastPoint = p1;
for (int z = 0; z < Config.Data.iterationCount; z++)
{
SimpleBitmap bestSample;
double bestDiff;
Vector bestVector;
double bestAngle;
GetBestAngle(lastPoint, lastDirection, avgSample, -50.0, 50.0, 5.0,
out bestSample, out bestDiff, out bestVector, out bestAngle);
GetBestAngle(lastPoint, lastDirection, avgSample, bestAngle - 4.0, bestAngle + 4.0, 1.0,
out bestSample, out bestDiff, out bestVector, out bestAngle);

if (bestDiff > Config.Data.maxDifference)
break;
SimpleBitmap sb = null;
if (Config.Data.debug)
sb = new SimpleBitmap(pixelRange * 2, pixelRange);
var angles = new Dictionary<double, double>();
for (int i = 0; i < pixelRange; i++)
{
for (int j = 0; j < pixelRange; j++)
{
int x = (int)(lastPoint.X + i - scanRadius);
int y = (int)(lastPoint.Y + j - scanRadius);
Vector pixelVector = new Vector(x, y) - lastPoint;
double pixelVectorLen = pixelVector.Length();

if (pixelVector.Length() < 1.0)
continue;
if (pixelVectorLen > scanRadius)
continue;

double angle = lastDirection.AngleTo(pixelVector);
if (angle < -Config.Data.angleRange)
continue;
if (angle > Config.Data.angleRange)
continue;

Color c = tileMap.GetPixel(x, y);
if (Config.Data.debug)
sb.SetPixel(i, j, c);

double invDiff = Math.Max(1.0 -
waterColor.DifferenceTo(c) / Config.Data.shoreContrast, 0.0);

if (Config.Data.debug)
{
byte diffColor = (byte)Math.Round(invDiff * 255.0);
sb.SetPixel(i + pixelRange, j, new Color(diffColor, diffColor, diffColor));
}

if (invDiff != 0.0)
{
if (!angles.ContainsKey(angle))
angles[angle] = 0.0;
angles[angle] += invDiff;
}
}
}

totalDiff += bestDiff;
samples.Add(sb);

samples.Add(bestSample);
avgSample = GetAvgSample(firstSample, bestSample);
if (angles.Count == 0)
break;

lastDirection = bestVector;
lastPoint = lastPoint + lastDirection * sampleLength;
double[] anglesGrid = new double[(int)Math.Round(
Config.Data.angleRange * 2 / Config.Data.angleStep + 1)];
foreach (var kv in angles)
{
anglesGrid[(int)Math.Round((kv.Key +
Config.Data.angleRange) / Config.Data.angleStep)] += kv.Value;
}

double bestAngle = (anglesGrid.ToList().IndexOf(anglesGrid.Max()) *
Config.Data.angleStep - Config.Data.angleRange);
lastDirection = lastDirection.Rotated(bestAngle);
lastPoint += lastDirection * scanRadius * Config.Data.advanceRate;
way.Add(lastPoint);
}
sw.Stop();
Expand All @@ -220,15 +187,13 @@ public Tracer()
if (Config.Data.debug)
{
SimpleBitmap sampleChain = new SimpleBitmap(
sampleWidth, sampleLength * samples.Count);
samples[0].Width, samples[0].Height * samples.Count);
for (int i = 0; i < samples.Count; i++)
samples[i].CopyTo(sampleChain, i * sampleLength);
samples[i].CopyTo(sampleChain, i * samples[0].Height);
sampleChain.WriteTo("sample_chain.png");

for (int i = 0; i < 50; i++)
Console.WriteLine();
Console.WriteLine("<!--");
Console.WriteLine("Total diff = " + totalDiff);
Console.WriteLine("Elapsed = " + sw.Elapsed.TotalSeconds);
Console.WriteLine("-->");
}
Expand Down
24 changes: 22 additions & 2 deletions Vector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@ public Vector(double x, double y)

public void Normalize()
{
double l = Math.Sqrt(X * X + Y * Y);
double l = Length();
X /= l;
Y /= l;
}

public double Length()
{
return Math.Sqrt(X * X + Y * Y);
}

public Vector Rotated(double degrees)
{
double rad = DegToRad(degrees);
Expand All @@ -48,9 +53,24 @@ public Vector Rotated(double degrees)
X * s + Y * c);
}

public double AngleTo(Vector p2)
{
double angle = RadToDeg(Math.Atan2(p2.Y, p2.X) - Math.Atan2(Y, X));
if (angle < -180.0)
angle += 360.0;
else if (angle > 180.0)
angle -= 360.0;
return angle;
}

public static double DegToRad(double degrees)
{
return Math.PI * degrees / 180.0;
return degrees * Math.PI / 180.0;
}

public static double RadToDeg(double radians)
{
return radians * 180.0 / Math.PI;
}

public double X;
Expand Down

0 comments on commit c78eaa9

Please sign in to comment.