(61d00a474) v0.9.7.1
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
//By Adrian Biagioli (Flafla2)
|
||||
//under a Creative Commons Attribution 4.0 International License.
|
||||
|
||||
public static class PerlinNoise
|
||||
{
|
||||
public static double OctavePerlin(double x, double y, double z, double frequency, int octaves, double persistence)
|
||||
{
|
||||
double total = 0;
|
||||
double amplitude = 3;
|
||||
for (int i = 0; i < octaves; i++)
|
||||
{
|
||||
total += CalculatePerlin(x * frequency, y * frequency, z * frequency) * amplitude;
|
||||
|
||||
amplitude *= persistence;
|
||||
frequency *= 2;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
// Hash lookup table as defined by Ken Perlin. This is a randomly
|
||||
// arranged array of all numbers from 0-255 inclusive.
|
||||
private static readonly int[] permutation =
|
||||
{
|
||||
151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
|
||||
};
|
||||
|
||||
private static readonly int[] p; // Doubled permutation to avoid overflow
|
||||
|
||||
private static readonly float[] cachedNoise;
|
||||
|
||||
private const int CacheResolution = 256;
|
||||
|
||||
static PerlinNoise()
|
||||
{
|
||||
p = new int[512];
|
||||
for (int x = 0; x < 512; x++)
|
||||
{
|
||||
p[x] = permutation[x % 256];
|
||||
}
|
||||
|
||||
float minValue = float.MaxValue;
|
||||
float maxValue = float.MinValue;
|
||||
cachedNoise = new float[CacheResolution * CacheResolution];
|
||||
for (int x = 0; x < CacheResolution; x++)
|
||||
{
|
||||
for (int y = 0; y < CacheResolution; y++)
|
||||
{
|
||||
cachedNoise[x + CacheResolution * y] = (float)OctavePerlin(x / (double)CacheResolution, y / (double)CacheResolution, 0.5, 10, 4, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < CacheResolution * CacheResolution; i++)
|
||||
{
|
||||
minValue = Math.Min(cachedNoise[i], minValue);
|
||||
maxValue = Math.Max(cachedNoise[i], maxValue);
|
||||
}
|
||||
|
||||
//normalize to 0-1 range
|
||||
for (int i = 0; i < CacheResolution * CacheResolution; i++)
|
||||
{
|
||||
cachedNoise[i] = (cachedNoise[i] - minValue) / (maxValue - minValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sample a pre-generated perlin noise map. Faster than calculating the noise on the fly.
|
||||
/// </summary>
|
||||
/// <param name="x">Normalized x position. The noise map starts repeating after x > 1</param>
|
||||
/// <param name="y">Normalized y position. The noise map starts repeating after y > 1</param>
|
||||
/// <returns>A noise value between 0.0f and 1.0f</returns>
|
||||
public static float GetPerlin(float x, float y)
|
||||
{
|
||||
x = Math.Abs(x) % 1.0f;
|
||||
y = Math.Abs(y) % 1.0f;
|
||||
|
||||
float xIndex = x < 0.5f ? (x * 2.0f * CacheResolution) : CacheResolution - ((x - 0.5f) * 2.0f * CacheResolution);
|
||||
xIndex = Math.Min(xIndex, CacheResolution - 1);
|
||||
|
||||
float yIndex = y < 0.5f ? (y * 2.0f * CacheResolution) : CacheResolution - ((y - 0.5f) * 2.0f * CacheResolution);
|
||||
yIndex = Math.Min(yIndex, CacheResolution - 1);
|
||||
|
||||
int minX = (int)xIndex, maxX = (int)Math.Ceiling(xIndex);
|
||||
int minY = (int)yIndex, maxY = (int)Math.Ceiling(yIndex);
|
||||
|
||||
return MathHelper.Lerp(
|
||||
MathHelper.Lerp(cachedNoise[minX + minY * CacheResolution], cachedNoise[maxX + minY * CacheResolution], xIndex % 1.0f),
|
||||
MathHelper.Lerp(cachedNoise[minX + maxY * CacheResolution], cachedNoise[maxX + maxY * CacheResolution], xIndex % 1.0f),
|
||||
yIndex % 1.0f);
|
||||
}
|
||||
|
||||
public static double CalculatePerlin(double x, double y, double z)
|
||||
{
|
||||
int xi = (int)x & 255; // Calculate the "unit cube" that the point asked will be located in
|
||||
int yi = (int)y & 255; // The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that
|
||||
int zi = (int)z & 255; // plus 1. Next we calculate the location (from 0.0 to 1.0) in that cube.
|
||||
double xf = x - (int)x; // We also fade the location to smooth the result.
|
||||
double yf = y - (int)y;
|
||||
double zf = z - (int)z;
|
||||
double u = Fade(xf);
|
||||
double v = Fade(yf);
|
||||
double w = Fade(zf);
|
||||
|
||||
int a = p[xi] + yi; // This here is Perlin's hash function. We take our x value (remember,
|
||||
int aa = p[a] + zi; // between 0 and 255) and get a random value (from our p[] array above) between
|
||||
int ab = p[a + 1] + zi; // 0 and 255. We then add y to it and plug that into p[], and add z to that.
|
||||
int b = p[xi + 1] + yi; // Then, we get another random value by adding 1 to that and putting it into p[]
|
||||
int ba = p[b] + zi; // and add z to it. We do the whole thing over again starting with x+1. Later
|
||||
int bb = p[b + 1] + zi; // we plug aa, ab, ba, and bb back into p[] along with their +1's to get another set.
|
||||
// in the end we have 8 values between 0 and 255 - one for each vertex on the unit cube.
|
||||
// These are all interpolated together using u, v, and w below.
|
||||
|
||||
double x1, x2, y1, y2;
|
||||
x1 = Lerp(Grad(p[aa], xf, yf, zf), // This is where the "magic" happens. We calculate a new set of p[] values and use that to get
|
||||
Grad(p[ba], xf - 1, yf, zf), // our final gradient values. Then, we interpolate between those gradients with the u value to get
|
||||
u); // 4 x-values. Next, we interpolate between the 4 x-values with v to get 2 y-values. Finally,
|
||||
x2 = Lerp(Grad(p[ab], xf, yf - 1, zf), // we interpolate between the y-values to get a z-value.
|
||||
Grad(p[bb], xf - 1, yf - 1, zf),
|
||||
u); // When calculating the p[] values, remember that above, p[a+1] expands to p[xi]+yi+1 -- so you are
|
||||
y1 = Lerp(x1, x2, v); // essentially adding 1 to yi. Likewise, p[ab+1] expands to p[p[xi]+yi+1]+zi+1] -- so you are adding
|
||||
// to zi. The other 3 parameters are your possible return values (see grad()), which are actually
|
||||
x1 = Lerp(Grad(p[aa + 1], xf, yf, zf - 1), // the vectors from the edges of the unit cube to the point in the unit cube itself.
|
||||
Grad(p[ba + 1], xf - 1, yf, zf - 1),
|
||||
u);
|
||||
x2 = Lerp(Grad(p[ab + 1], xf, yf - 1, zf - 1),
|
||||
Grad(p[bb + 1], xf - 1, yf - 1, zf - 1),
|
||||
u);
|
||||
y2 = Lerp(x1, x2, v);
|
||||
|
||||
return (Lerp(y1, y2, w) + 1) / 2; // For convenience we bound it to 0 - 1 (theoretical min/max before is -1 - 1)
|
||||
}
|
||||
|
||||
public static double Grad(int hash, double x, double y, double z)
|
||||
{
|
||||
int h = hash & 15; // Take the hashed value and take the first 4 bits of it (15 == 0b1111)
|
||||
double u = h < 8 /* 0b1000 */ ? x : y; // If the most signifigant bit (MSB) of the hash is 0 then set u = x. Otherwise y.
|
||||
|
||||
double v; // In Ken Perlin's original implementation this was another conditional operator (?:). I
|
||||
// expanded it for readability.
|
||||
|
||||
if (h < 4 /* 0b0100 */) // If the first and second signifigant bits are 0 set v = y
|
||||
v = y;
|
||||
else if (h == 12 /* 0b1100 */ || h == 14 /* 0b1110*/)// If the first and second signifigant bits are 1 set v = x
|
||||
v = x;
|
||||
else // If the first and second signifigant bits are not equal (0/1, 1/0) set v = z
|
||||
v = z;
|
||||
|
||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); // Use the last 2 bits to decide if u and v are positive or negative. Then return their addition.
|
||||
}
|
||||
|
||||
public static double Fade(double t)
|
||||
{
|
||||
// Fade function as defined by Ken Perlin. This eases coordinate values
|
||||
// so that they will "ease" towards integral values. This ends up smoothing
|
||||
// the final output.
|
||||
return t * t * t * (t * (t * 6 - 15) + 10); // 6t^5 - 15t^4 + 10t^3
|
||||
}
|
||||
|
||||
public static double Lerp(double a, double b, double x)
|
||||
{
|
||||
return a + x * (b - a);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,991 @@
|
||||
/*
|
||||
* Created by SharpDevelop.
|
||||
* User: Burhan
|
||||
* Date: 17/06/2014
|
||||
* Time: 11:30 م
|
||||
*
|
||||
* To change this template use Tools | Options | Coding | Edit Standard Headers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The author of this software is Steven Fortune. Copyright (c) 1994 by AT&T
|
||||
* Bell Laboratories.
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code was originally written by Stephan Fortune in C code. I, Shane O'Sullivan,
|
||||
* have since modified it, encapsulating it in a C++ class and, fixing memory leaks and
|
||||
* adding accessors to the Voronoi Edges.
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Java Version by Zhenyu Pan
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* C# Version by Burhan Joukhadar
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Voronoi2
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of Voronoi.
|
||||
/// </summary>
|
||||
public class Voronoi
|
||||
{
|
||||
// ************* Private members ******************
|
||||
double borderMinX, borderMaxX, borderMinY, borderMaxY;
|
||||
int siteidx;
|
||||
double xmin, xmax, ymin, ymax, deltax, deltay;
|
||||
int nvertices;
|
||||
int nedges;
|
||||
int nsites;
|
||||
Site[] sites;
|
||||
Site bottomsite;
|
||||
int sqrt_nsites;
|
||||
double minDistanceBetweenSites;
|
||||
int PQcount;
|
||||
int PQmin;
|
||||
int PQhashsize;
|
||||
Halfedge[] PQhash;
|
||||
|
||||
const int LE = 0;
|
||||
const int RE = 1;
|
||||
|
||||
int ELhashsize;
|
||||
Halfedge[] ELhash;
|
||||
Halfedge ELleftend, ELrightend;
|
||||
List<GraphEdge> allEdges;
|
||||
|
||||
|
||||
// ************* Public methods ******************
|
||||
// ******************************************
|
||||
|
||||
// constructor
|
||||
public Voronoi ( double minDistanceBetweenSites )
|
||||
{
|
||||
siteidx = 0;
|
||||
sites = null;
|
||||
|
||||
allEdges = null;
|
||||
this.minDistanceBetweenSites = minDistanceBetweenSites;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param xValuesIn Array of X values for each site.
|
||||
* @param yValuesIn Array of Y values for each site. Must be identical length to yValuesIn
|
||||
* @param minX The minimum X of the bounding box around the voronoi
|
||||
* @param maxX The maximum X of the bounding box around the voronoi
|
||||
* @param minY The minimum Y of the bounding box around the voronoi
|
||||
* @param maxY The maximum Y of the bounding box around the voronoi
|
||||
* @return
|
||||
*/
|
||||
// تستدعى هذه العملية لإنشاء مخطط فورونوي
|
||||
public List<GraphEdge> generateVoronoi ( double[] xValuesIn, double[] yValuesIn, double minX, double maxX, double minY, double maxY )
|
||||
{
|
||||
sort(xValuesIn, yValuesIn, xValuesIn.Length);
|
||||
|
||||
// Check bounding box inputs - if mins are bigger than maxes, swap them
|
||||
double temp = 0;
|
||||
if ( minX > maxX )
|
||||
{
|
||||
temp = minX;
|
||||
minX = maxX;
|
||||
maxX = temp;
|
||||
}
|
||||
if ( minY > maxY )
|
||||
{
|
||||
temp = minY;
|
||||
minY = maxY;
|
||||
maxY = temp;
|
||||
}
|
||||
|
||||
borderMinX = minX;
|
||||
borderMinY = minY;
|
||||
borderMaxX = maxX;
|
||||
borderMaxY = maxY;
|
||||
|
||||
siteidx = 0;
|
||||
voronoi_bd ();
|
||||
return allEdges;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Private methods - implementation details
|
||||
********************************************************/
|
||||
|
||||
private void sort ( double[] xValuesIn, double[] yValuesIn, int count )
|
||||
{
|
||||
sites = null;
|
||||
allEdges = new List<GraphEdge>();
|
||||
|
||||
nsites = count;
|
||||
nvertices = 0;
|
||||
nedges = 0;
|
||||
|
||||
double sn = (double)nsites + 4;
|
||||
sqrt_nsites = (int) Math.Sqrt ( sn );
|
||||
|
||||
// Copy the inputs so we don't modify the originals
|
||||
double[] xValues = new double[count];
|
||||
double[] yValues = new double[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
xValues[i] = xValuesIn[i];
|
||||
yValues[i] = yValuesIn[i];
|
||||
}
|
||||
sortNode ( xValues, yValues, count );
|
||||
}
|
||||
|
||||
private void qsort ( Site[] sites )
|
||||
{
|
||||
List<Site> listSites = new List<Site>( sites.Length );
|
||||
for ( int i = 0; i < sites.Length; i++ )
|
||||
{
|
||||
listSites.Add ( sites[i] );
|
||||
}
|
||||
|
||||
listSites.Sort ( new SiteSorterYX () );
|
||||
|
||||
// Copy back into the array
|
||||
for (int i=0; i < sites.Length; i++)
|
||||
{
|
||||
sites[i] = listSites[i];
|
||||
}
|
||||
}
|
||||
|
||||
private void sortNode ( double[] xValues, double[] yValues, int numPoints )
|
||||
{
|
||||
nsites = numPoints;
|
||||
sites = new Site[nsites];
|
||||
xmin = xValues[0];
|
||||
ymin = yValues[0];
|
||||
xmax = xValues[0];
|
||||
ymax = yValues[0];
|
||||
|
||||
for ( int i = 0; i < nsites; i++ )
|
||||
{
|
||||
sites[i] = new Site();
|
||||
sites[i].Coord.SetPoint ( xValues[i], yValues[i] );
|
||||
sites[i].SiteNbr = i;
|
||||
|
||||
if ( xValues[i] < xmin )
|
||||
xmin = xValues[i];
|
||||
else if ( xValues[i] > xmax )
|
||||
xmax = xValues[i];
|
||||
|
||||
if ( yValues[i] < ymin )
|
||||
ymin = yValues[i];
|
||||
else if ( yValues[i] > ymax )
|
||||
ymax = yValues[i];
|
||||
}
|
||||
|
||||
qsort ( sites );
|
||||
deltax = xmax - xmin;
|
||||
deltay = ymax - ymin;
|
||||
}
|
||||
|
||||
private Site nextone ()
|
||||
{
|
||||
Site s;
|
||||
if ( siteidx < nsites )
|
||||
{
|
||||
s = sites[siteidx];
|
||||
siteidx++;
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Edge bisect ( Site s1, Site s2 )
|
||||
{
|
||||
double dx, dy, adx, ady;
|
||||
Edge newedge;
|
||||
|
||||
newedge = new Edge();
|
||||
|
||||
newedge.reg[0] = s1;
|
||||
newedge.reg[1] = s2;
|
||||
|
||||
newedge.ep [0] = null;
|
||||
newedge.ep[1] = null;
|
||||
|
||||
dx = s2.Coord.X - s1.Coord.X;
|
||||
dy = s2.Coord.Y - s1.Coord.Y;
|
||||
|
||||
adx = dx > 0 ? dx : -dx;
|
||||
ady = dy > 0 ? dy : -dy;
|
||||
newedge.c = (double)(s1.Coord.X * dx + s1.Coord.Y * dy + (dx * dx + dy* dy) * 0.5);
|
||||
|
||||
if ( adx > ady )
|
||||
{
|
||||
newedge.a = 1.0;
|
||||
newedge.b = dy / dx;
|
||||
newedge.c /= dx;
|
||||
}
|
||||
else
|
||||
{
|
||||
newedge.a = dx / dy;
|
||||
newedge.b = 1.0;
|
||||
newedge.c /= dy;
|
||||
}
|
||||
|
||||
newedge.edgenbr = nedges;
|
||||
nedges++;
|
||||
|
||||
return newedge;
|
||||
}
|
||||
|
||||
private void makevertex ( Site v )
|
||||
{
|
||||
v.SiteNbr = nvertices;
|
||||
nvertices++;
|
||||
}
|
||||
|
||||
private bool PQinitialize ()
|
||||
{
|
||||
PQcount = 0;
|
||||
PQmin = 0;
|
||||
PQhashsize = 4 * sqrt_nsites;
|
||||
PQhash = new Halfedge[ PQhashsize ];
|
||||
|
||||
for ( int i = 0; i < PQhashsize; i++ )
|
||||
{
|
||||
PQhash [i] = new Halfedge();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int PQbucket ( Halfedge he )
|
||||
{
|
||||
int bucket;
|
||||
|
||||
bucket = (int) ((he.ystar - ymin) / deltay * PQhashsize);
|
||||
if ( bucket < 0 )
|
||||
bucket = 0;
|
||||
if ( bucket >= PQhashsize )
|
||||
bucket = PQhashsize - 1;
|
||||
if ( bucket < PQmin )
|
||||
PQmin = bucket;
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
// push the HalfEdge into the ordered linked list of vertices
|
||||
private void PQinsert ( Halfedge he, Site v, double offset )
|
||||
{
|
||||
Halfedge last, next;
|
||||
|
||||
he.vertex = v;
|
||||
he.ystar = (double)(v.Coord.Y + offset);
|
||||
last = PQhash [ PQbucket (he) ];
|
||||
|
||||
while
|
||||
(
|
||||
(next = last.PQnext) != null
|
||||
&&
|
||||
(he.ystar > next.ystar || (he.ystar == next.ystar && v.Coord.X > next.vertex.Coord.X))
|
||||
)
|
||||
{
|
||||
last = next;
|
||||
}
|
||||
|
||||
he.PQnext = last.PQnext;
|
||||
last.PQnext = he;
|
||||
PQcount++;
|
||||
}
|
||||
|
||||
// remove the HalfEdge from the list of vertices
|
||||
private void PQdelete ( Halfedge he )
|
||||
{
|
||||
Halfedge last;
|
||||
|
||||
if (he.vertex != null)
|
||||
{
|
||||
last = PQhash [ PQbucket (he) ];
|
||||
while ( last.PQnext != he )
|
||||
{
|
||||
last = last.PQnext;
|
||||
}
|
||||
|
||||
last.PQnext = he.PQnext;
|
||||
PQcount--;
|
||||
he.vertex = null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool PQempty ()
|
||||
{
|
||||
return ( PQcount == 0 );
|
||||
}
|
||||
|
||||
private DoubleVector2 PQ_min ()
|
||||
{
|
||||
DoubleVector2 answer = new DoubleVector2 ();
|
||||
|
||||
while ( PQhash[PQmin].PQnext == null )
|
||||
{
|
||||
PQmin++;
|
||||
}
|
||||
|
||||
answer.X = PQhash[PQmin].PQnext.vertex.Coord.X;
|
||||
answer.Y = PQhash[PQmin].PQnext.ystar;
|
||||
return answer;
|
||||
}
|
||||
|
||||
private Halfedge PQextractmin ()
|
||||
{
|
||||
Halfedge curr;
|
||||
|
||||
curr = PQhash[PQmin].PQnext;
|
||||
PQhash[PQmin].PQnext = curr.PQnext;
|
||||
PQcount--;
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
private Halfedge HEcreate(Edge e, int pm)
|
||||
{
|
||||
Halfedge answer = new Halfedge();
|
||||
answer.ELedge = e;
|
||||
answer.ELpm = pm;
|
||||
answer.PQnext = null;
|
||||
answer.vertex = null;
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
private bool ELinitialize()
|
||||
{
|
||||
ELhashsize = 2 * sqrt_nsites;
|
||||
ELhash = new Halfedge[ELhashsize];
|
||||
|
||||
for (int i = 0; i < ELhashsize; i++)
|
||||
{
|
||||
ELhash[i] = null;
|
||||
}
|
||||
|
||||
ELleftend = HEcreate ( null, 0 );
|
||||
ELrightend = HEcreate ( null, 0 );
|
||||
ELleftend.ELleft = null;
|
||||
ELleftend.ELright = ELrightend;
|
||||
ELrightend.ELleft = ELleftend;
|
||||
ELrightend.ELright = null;
|
||||
ELhash[0] = ELleftend;
|
||||
ELhash[ELhashsize - 1] = ELrightend;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Halfedge ELright( Halfedge he )
|
||||
{
|
||||
return he.ELright;
|
||||
}
|
||||
|
||||
private Halfedge ELleft( Halfedge he )
|
||||
{
|
||||
return he.ELleft;
|
||||
}
|
||||
|
||||
private Site leftreg( Halfedge he )
|
||||
{
|
||||
if (he.ELedge == null)
|
||||
{
|
||||
return bottomsite;
|
||||
}
|
||||
return (he.ELpm == LE ? he.ELedge.reg[LE] : he.ELedge.reg[RE]);
|
||||
}
|
||||
|
||||
private void ELinsert( Halfedge lb, Halfedge newHe )
|
||||
{
|
||||
newHe.ELleft = lb;
|
||||
newHe.ELright = lb.ELright;
|
||||
(lb.ELright).ELleft = newHe;
|
||||
lb.ELright = newHe;
|
||||
}
|
||||
|
||||
/*
|
||||
* This delete routine can't reclaim node, since pointers from hash table
|
||||
* may be present.
|
||||
*/
|
||||
private void ELdelete( Halfedge he )
|
||||
{
|
||||
(he.ELleft).ELright = he.ELright;
|
||||
(he.ELright).ELleft = he.ELleft;
|
||||
he.deleted = true;
|
||||
}
|
||||
|
||||
/* Get entry from hash table, pruning any deleted nodes */
|
||||
private Halfedge ELgethash( int b )
|
||||
{
|
||||
Halfedge he;
|
||||
if (b < 0 || b >= ELhashsize)
|
||||
return null;
|
||||
|
||||
he = ELhash[b];
|
||||
if (he == null || !he.deleted )
|
||||
return he;
|
||||
|
||||
/* Hash table points to deleted half edge. Patch as necessary. */
|
||||
ELhash[b] = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
private Halfedge ELleftbnd( DoubleVector2 p )
|
||||
{
|
||||
int bucket;
|
||||
Halfedge he;
|
||||
|
||||
/* Use hash table to get close to desired halfedge */
|
||||
// use the hash function to find the place in the hash map that this
|
||||
// HalfEdge should be
|
||||
bucket = (int) ((p.X - xmin) / deltax * ELhashsize);
|
||||
|
||||
// make sure that the bucket position is within the range of the hash
|
||||
// array
|
||||
if ( bucket < 0 ) bucket = 0;
|
||||
if ( bucket >= ELhashsize ) bucket = ELhashsize - 1;
|
||||
|
||||
he = ELgethash ( bucket );
|
||||
|
||||
// if the HE isn't found, search backwards and forwards in the hash map
|
||||
// for the first non-null entry
|
||||
if ( he == null )
|
||||
{
|
||||
for ( int i = 1; i < ELhashsize; i++ )
|
||||
{
|
||||
if ( (he = ELgethash ( bucket - i ) ) != null )
|
||||
break;
|
||||
if ( (he = ELgethash ( bucket + i ) ) != null )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now search linear list of halfedges for the correct one */
|
||||
if ( he == ELleftend || ( he != ELrightend && right_of (he, p) ) )
|
||||
{
|
||||
// keep going right on the list until either the end is reached, or
|
||||
// you find the 1st edge which the point isn't to the right of
|
||||
do
|
||||
{
|
||||
he = he.ELright;
|
||||
}
|
||||
while ( he != ELrightend && right_of(he, p) );
|
||||
he = he.ELleft;
|
||||
}
|
||||
else
|
||||
// if the point is to the left of the HalfEdge, then search left for
|
||||
// the HE just to the left of the point
|
||||
{
|
||||
do
|
||||
{
|
||||
he = he.ELleft;
|
||||
}
|
||||
while ( he != ELleftend && !right_of(he, p) );
|
||||
}
|
||||
|
||||
/* Update hash table and reference counts */
|
||||
if ( bucket > 0 && bucket < ELhashsize - 1)
|
||||
{
|
||||
ELhash[bucket] = he;
|
||||
}
|
||||
|
||||
return he;
|
||||
}
|
||||
|
||||
private void pushGraphEdge( Site leftSite, Site rightSite, Vector2 point1, Vector2 point2 )
|
||||
{
|
||||
GraphEdge newEdge = new GraphEdge(point1, point2);
|
||||
allEdges.Add ( newEdge );
|
||||
|
||||
newEdge.Site1 = leftSite;
|
||||
newEdge.Site2 = rightSite;
|
||||
}
|
||||
|
||||
private void clip_line( Edge e )
|
||||
{
|
||||
double pxmin, pxmax, pymin, pymax;
|
||||
Site s1, s2;
|
||||
|
||||
double x1 = e.reg[0].Coord.X;
|
||||
double y1 = e.reg[0].Coord.Y;
|
||||
double x2 = e.reg[1].Coord.X;
|
||||
double y2 = e.reg[1].Coord.Y;
|
||||
double x = x2- x1;
|
||||
double y = y2 - y1;
|
||||
|
||||
// if the distance between the two points this line was created from is
|
||||
// less than the square root of 2 عن جد؟, then ignore it
|
||||
if ( Math.Sqrt ( (x*x) + (y*y) ) < minDistanceBetweenSites )
|
||||
{
|
||||
return;
|
||||
}
|
||||
pxmin = borderMinX;
|
||||
pymin = borderMinY;
|
||||
pxmax = borderMaxX;
|
||||
pymax = borderMaxY;
|
||||
|
||||
if ( e.a == 1.0 && e.b >= 0.0 )
|
||||
{
|
||||
s1 = e.ep[1];
|
||||
s2 = e.ep[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
s1 = e.ep[0];
|
||||
s2 = e.ep[1];
|
||||
}
|
||||
|
||||
if ( e.a == 1.0 )
|
||||
{
|
||||
y1 = pymin;
|
||||
|
||||
if ( s1 != null && s1.Coord.Y > pymin )
|
||||
y1 = s1.Coord.Y;
|
||||
if ( y1 > pymax )
|
||||
y1 = pymax;
|
||||
x1 = e.c - e.b * y1;
|
||||
y2 = pymax;
|
||||
|
||||
if ( s2 != null && s2.Coord.Y < pymax )
|
||||
y2 = s2.Coord.Y;
|
||||
if ( y2 < pymin )
|
||||
y2 = pymin;
|
||||
x2 = e.c - e.b * y2;
|
||||
if ( ( (x1 > pxmax) & (x2 > pxmax) ) | ( (x1 < pxmin) & (x2 < pxmin) ) )
|
||||
return;
|
||||
|
||||
if ( x1 > pxmax )
|
||||
{
|
||||
x1 = pxmax;
|
||||
y1 = ( e.c - x1 ) / e.b;
|
||||
}
|
||||
if ( x1 < pxmin )
|
||||
{
|
||||
x1 = pxmin;
|
||||
y1 = ( e.c - x1 ) / e.b;
|
||||
}
|
||||
if ( x2 > pxmax )
|
||||
{
|
||||
x2 = pxmax;
|
||||
y2 = ( e.c - x2 ) / e.b;
|
||||
}
|
||||
if ( x2 < pxmin )
|
||||
{
|
||||
x2 = pxmin;
|
||||
y2 = ( e.c - x2 ) / e.b;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
x1 = pxmin;
|
||||
if ( s1 != null && s1.Coord.X > pxmin )
|
||||
x1 = s1.Coord.X;
|
||||
if ( x1 > pxmax )
|
||||
x1 = pxmax;
|
||||
y1 = e.c - e.a * x1;
|
||||
|
||||
x2 = pxmax;
|
||||
if ( s2 != null && s2.Coord.X < pxmax )
|
||||
x2 = s2.Coord.X;
|
||||
if ( x2 < pxmin )
|
||||
x2 = pxmin;
|
||||
y2 = e.c - e.a * x2;
|
||||
|
||||
if (((y1 > pymax) & (y2 > pymax)) | ((y1 < pymin) & (y2 < pymin)))
|
||||
return;
|
||||
|
||||
if ( y1 > pymax )
|
||||
{
|
||||
y1 = pymax;
|
||||
x1 = ( e.c - y1 ) / e.a;
|
||||
}
|
||||
if ( y1 < pymin )
|
||||
{
|
||||
y1 = pymin;
|
||||
x1 = ( e.c - y1 ) / e.a;
|
||||
}
|
||||
if ( y2 > pymax )
|
||||
{
|
||||
y2 = pymax;
|
||||
x2 = ( e.c - y2 ) / e.a;
|
||||
}
|
||||
if ( y2 < pymin )
|
||||
{
|
||||
y2 = pymin;
|
||||
x2 = ( e.c - y2 ) / e.a;
|
||||
}
|
||||
}
|
||||
|
||||
pushGraphEdge(e.reg[0], e.reg[1], new Vector2((float)x1, (float)y1), new Vector2((float)x2, (float)y2));
|
||||
}
|
||||
|
||||
private void endpoint( Edge e, int lr, Site s )
|
||||
{
|
||||
e.ep[lr] = s;
|
||||
if ( e.ep[RE - lr] == null )
|
||||
return;
|
||||
clip_line ( e );
|
||||
}
|
||||
|
||||
/* returns true if p is to right of halfedge e */
|
||||
private bool right_of(Halfedge el, DoubleVector2 p)
|
||||
{
|
||||
Edge e;
|
||||
Site topsite;
|
||||
bool right_of_site;
|
||||
bool above, fast;
|
||||
double dxp, dyp, dxs, t1, t2, t3, yl;
|
||||
|
||||
e = el.ELedge;
|
||||
topsite = e.reg[1];
|
||||
|
||||
if ( p.X > topsite.Coord.X )
|
||||
right_of_site = true;
|
||||
else
|
||||
right_of_site = false;
|
||||
|
||||
if ( right_of_site && el.ELpm == LE )
|
||||
return true;
|
||||
if (!right_of_site && el.ELpm == RE )
|
||||
return false;
|
||||
|
||||
if ( e.a == 1.0 )
|
||||
{
|
||||
dxp = p.X - topsite.Coord.X;
|
||||
dyp = p.Y - topsite.Coord.Y;
|
||||
fast = false;
|
||||
|
||||
if ( (!right_of_site & (e.b < 0.0)) | (right_of_site & (e.b >= 0.0)) )
|
||||
{
|
||||
above = dyp >= e.b * dxp;
|
||||
fast = above;
|
||||
}
|
||||
else
|
||||
{
|
||||
above = p.X + p.Y * e.b > e.c;
|
||||
if ( e.b < 0.0 )
|
||||
above = !above;
|
||||
if ( !above )
|
||||
fast = true;
|
||||
}
|
||||
if ( !fast )
|
||||
{
|
||||
dxs = topsite.Coord.X - ( e.reg[0] ).Coord.X;
|
||||
above = e.b * (dxp * dxp - dyp * dyp)
|
||||
< dxs * dyp * (1.0 + 2.0 * dxp / dxs + e.b * e.b);
|
||||
|
||||
if ( e.b < 0 )
|
||||
above = !above;
|
||||
}
|
||||
}
|
||||
else // e.b == 1.0
|
||||
{
|
||||
yl = e.c - e.a * p.X;
|
||||
t1 = p.Y - yl;
|
||||
t2 = p.X - topsite.Coord.X;
|
||||
t3 = yl - topsite.Coord.Y;
|
||||
above = t1 * t1 > t2 * t2 + t3 * t3;
|
||||
}
|
||||
return ( el.ELpm == LE ? above : !above );
|
||||
}
|
||||
|
||||
private Site rightreg(Halfedge he)
|
||||
{
|
||||
if (he.ELedge == (Edge) null)
|
||||
// if this halfedge has no edge, return the bottom site (whatever
|
||||
// that is)
|
||||
{
|
||||
return (bottomsite);
|
||||
}
|
||||
|
||||
// if the ELpm field is zero, return the site 0 that this edge bisects,
|
||||
// otherwise return site number 1
|
||||
return (he.ELpm == LE ? he.ELedge.reg[RE] : he.ELedge.reg[LE]);
|
||||
}
|
||||
|
||||
private double dist( Site s, Site t )
|
||||
{
|
||||
double dx, dy;
|
||||
dx = s.Coord.X - t.Coord.X;
|
||||
dy = s.Coord.Y - t.Coord.Y;
|
||||
return Math.Sqrt ( dx * dx + dy * dy );
|
||||
}
|
||||
|
||||
// create a new site where the HalfEdges el1 and el2 intersect - note that
|
||||
// the Point in the argument list is not used, don't know why it's there
|
||||
private Site intersect( Halfedge el1, Halfedge el2 )
|
||||
{
|
||||
Edge e1, e2, e;
|
||||
Halfedge el;
|
||||
double d, xint, yint;
|
||||
bool right_of_site;
|
||||
Site v; // vertex
|
||||
|
||||
e1 = el1.ELedge;
|
||||
e2 = el2.ELedge;
|
||||
|
||||
if ( e1 == null || e2 == null )
|
||||
return null;
|
||||
|
||||
// if the two edges bisect the same parent, return null
|
||||
if ( e1.reg[1] == e2.reg[1] )
|
||||
return null;
|
||||
|
||||
d = e1.a * e2.b - e1.b * e2.a;
|
||||
if ( -1.0e-10 < d && d < 1.0e-10 )
|
||||
return null;
|
||||
|
||||
xint = ( e1.c * e2.b - e2.c * e1.b ) / d;
|
||||
yint = ( e2.c * e1.a - e1.c * e2.a ) / d;
|
||||
|
||||
if ( (e1.reg[1].Coord.Y < e2.reg[1].Coord.Y)
|
||||
|| (e1.reg[1].Coord.Y == e2.reg[1].Coord.Y && e1.reg[1].Coord.X < e2.reg[1].Coord.X) )
|
||||
{
|
||||
el = el1;
|
||||
e = e1;
|
||||
}
|
||||
else
|
||||
{
|
||||
el = el2;
|
||||
e = e2;
|
||||
}
|
||||
|
||||
right_of_site = xint >= e.reg[1].Coord.X;
|
||||
if ((right_of_site && el.ELpm == LE)
|
||||
|| (!right_of_site && el.ELpm == RE))
|
||||
return null;
|
||||
|
||||
// create a new site at the point of intersection - this is a new vector
|
||||
// event waiting to happen
|
||||
v = new Site();
|
||||
v.Coord.X = xint;
|
||||
v.Coord.Y = yint;
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax, deltax,
|
||||
* deltay (can all be estimates). Performance suffers if they are wrong;
|
||||
* better to make nsites, deltax, and deltay too big than too small. (?)
|
||||
*/
|
||||
private bool voronoi_bd()
|
||||
{
|
||||
Site newsite, bot, top, temp, p;
|
||||
Site v;
|
||||
DoubleVector2 newintstar = null;
|
||||
int pm;
|
||||
Halfedge lbnd, rbnd, llbnd, rrbnd, bisector;
|
||||
Edge e;
|
||||
|
||||
PQinitialize();
|
||||
ELinitialize();
|
||||
|
||||
bottomsite = nextone();
|
||||
newsite = nextone();
|
||||
while (true)
|
||||
{
|
||||
if (!PQempty())
|
||||
{
|
||||
newintstar = PQ_min();
|
||||
}
|
||||
// if the lowest site has a smaller y value than the lowest vector
|
||||
// intersection,
|
||||
// process the site otherwise process the vector intersection
|
||||
|
||||
if (newsite != null && (PQempty()
|
||||
|| newsite.Coord.Y < newintstar.Y
|
||||
|| (newsite.Coord.Y == newintstar.Y
|
||||
&& newsite.Coord.X < newintstar.X)))
|
||||
{
|
||||
/* new site is smallest -this is a site event */
|
||||
// get the first HalfEdge to the LEFT of the new site
|
||||
lbnd = ELleftbnd((newsite.Coord));
|
||||
// get the first HalfEdge to the RIGHT of the new site
|
||||
rbnd = ELright(lbnd);
|
||||
// if this halfedge has no edge,bot =bottom site (whatever that
|
||||
// is)
|
||||
bot = rightreg(lbnd);
|
||||
// create a new edge that bisects
|
||||
e = bisect(bot, newsite);
|
||||
|
||||
// create a new HalfEdge, setting its ELpm field to 0
|
||||
bisector = HEcreate(e, LE);
|
||||
// insert this new bisector edge between the left and right
|
||||
// vectors in a linked list
|
||||
ELinsert(lbnd, bisector);
|
||||
|
||||
// if the new bisector intersects with the left edge,
|
||||
// remove the left edge's vertex, and put in the new one
|
||||
if ((p = intersect(lbnd, bisector)) != null)
|
||||
{
|
||||
PQdelete(lbnd);
|
||||
PQinsert(lbnd, p, dist(p, newsite));
|
||||
}
|
||||
lbnd = bisector;
|
||||
// create a new HalfEdge, setting its ELpm field to 1
|
||||
bisector = HEcreate(e, RE);
|
||||
// insert the new HE to the right of the original bisector
|
||||
// earlier in the IF stmt
|
||||
ELinsert(lbnd, bisector);
|
||||
|
||||
// if this new bisector intersects with the new HalfEdge
|
||||
if ((p = intersect(bisector, rbnd)) != null)
|
||||
{
|
||||
// push the HE into the ordered linked list of vertices
|
||||
PQinsert(bisector, p, dist(p, newsite));
|
||||
}
|
||||
newsite = nextone();
|
||||
} else if (!PQempty())
|
||||
/* intersection is smallest - this is a vector event */
|
||||
{
|
||||
// pop the HalfEdge with the lowest vector off the ordered list
|
||||
// of vectors
|
||||
lbnd = PQextractmin();
|
||||
// get the HalfEdge to the left of the above HE
|
||||
llbnd = ELleft(lbnd);
|
||||
// get the HalfEdge to the right of the above HE
|
||||
rbnd = ELright(lbnd);
|
||||
// get the HalfEdge to the right of the HE to the right of the
|
||||
// lowest HE
|
||||
rrbnd = ELright(rbnd);
|
||||
// get the Site to the left of the left HE which it bisects
|
||||
bot = leftreg(lbnd);
|
||||
// get the Site to the right of the right HE which it bisects
|
||||
top = rightreg(rbnd);
|
||||
|
||||
v = lbnd.vertex; // get the vertex that caused this event
|
||||
makevertex(v); // set the vertex number - couldn't do this
|
||||
// earlier since we didn't know when it would be processed
|
||||
endpoint(lbnd.ELedge, lbnd.ELpm, v);
|
||||
// set the endpoint of
|
||||
// the left HalfEdge to be this vector
|
||||
endpoint(rbnd.ELedge, rbnd.ELpm, v);
|
||||
// set the endpoint of the right HalfEdge to
|
||||
// be this vector
|
||||
ELdelete(lbnd); // mark the lowest HE for
|
||||
// deletion - can't delete yet because there might be pointers
|
||||
// to it in Hash Map
|
||||
PQdelete(rbnd);
|
||||
// remove all vertex events to do with the right HE
|
||||
ELdelete(rbnd); // mark the right HE for
|
||||
// deletion - can't delete yet because there might be pointers
|
||||
// to it in Hash Map
|
||||
pm = LE; // set the pm variable to zero
|
||||
|
||||
if (bot.Coord.Y > top.Coord.Y)
|
||||
// if the site to the left of the event is higher than the
|
||||
// Site
|
||||
{ // to the right of it, then swap them and set the 'pm'
|
||||
// variable to 1
|
||||
temp = bot;
|
||||
bot = top;
|
||||
top = temp;
|
||||
pm = RE;
|
||||
}
|
||||
e = bisect(bot, top); // create an Edge (or line)
|
||||
// that is between the two Sites. This creates the formula of
|
||||
// the line, and assigns a line number to it
|
||||
bisector = HEcreate(e, pm); // create a HE from the Edge 'e',
|
||||
// and make it point to that edge
|
||||
// with its ELedge field
|
||||
ELinsert(llbnd, bisector); // insert the new bisector to the
|
||||
// right of the left HE
|
||||
endpoint(e, RE - pm, v); // set one endpoint to the new edge
|
||||
// to be the vector point 'v'.
|
||||
// If the site to the left of this bisector is higher than the
|
||||
// right Site, then this endpoint
|
||||
// is put in position 0; otherwise in pos 1
|
||||
|
||||
// if left HE and the new bisector intersect, then delete
|
||||
// the left HE, and reinsert it
|
||||
if ((p = intersect(llbnd, bisector)) != null)
|
||||
{
|
||||
PQdelete(llbnd);
|
||||
PQinsert(llbnd, p, dist(p, bot));
|
||||
}
|
||||
|
||||
// if right HE and the new bisector intersect, then
|
||||
// reinsert it
|
||||
if ((p = intersect(bisector, rrbnd)) != null)
|
||||
{
|
||||
PQinsert(bisector, p, dist(p, bot));
|
||||
}
|
||||
} else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (lbnd = ELright(ELleftend); lbnd != ELrightend; lbnd = ELright(lbnd))
|
||||
{
|
||||
e = lbnd.ELedge;
|
||||
clip_line(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<GraphEdge> MakeVoronoiGraph(List<Vector2> sites, int width, int height)
|
||||
{
|
||||
double[] xVal = new double[sites.Count];
|
||||
double[] yVal = new double[sites.Count];
|
||||
for (int i = 0; i < sites.Count; i++)
|
||||
{
|
||||
xVal[i] = sites[i].X;
|
||||
yVal[i] = sites[i].Y;
|
||||
}
|
||||
return generateVoronoi(xVal, yVal, 0, width, 0, height);
|
||||
}
|
||||
|
||||
public List<GraphEdge> MakeVoronoiGraph(double[] xVal, double[] yVal, int width, int height)
|
||||
{
|
||||
return generateVoronoi(xVal, yVal, 0, width, 0, height);
|
||||
}
|
||||
|
||||
} // Voronoi Class End
|
||||
} // namespace Voronoi2 End
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Created by SharpDevelop.
|
||||
* User: Burhan
|
||||
* Date: 17/06/2014
|
||||
* Time: 09:29 م
|
||||
*
|
||||
* To change this template use Tools | Options | Coding | Edit Standard Headers.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 James Humphreys. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY James Humphreys ``AS IS\" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those of the
|
||||
authors and should not be interpreted as representing official policies, either expressed
|
||||
or implied, of James Humphreys.
|
||||
*/
|
||||
|
||||
/*
|
||||
* C# Version by Burhan Joukhadar
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
using Barotrauma;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Voronoi2
|
||||
{
|
||||
public class DoubleVector2
|
||||
{
|
||||
public double X, Y;
|
||||
|
||||
public DoubleVector2()
|
||||
{
|
||||
}
|
||||
|
||||
public DoubleVector2(double x, double y)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
|
||||
public void SetPoint(double x, double y)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
double length = System.Math.Sqrt(X * X + Y * Y);
|
||||
X /= length;
|
||||
Y /= length;
|
||||
}
|
||||
}
|
||||
|
||||
// use for sites and vertecies
|
||||
public class Site
|
||||
{
|
||||
public DoubleVector2 Coord;
|
||||
public int SiteNbr;
|
||||
|
||||
public void SetPoint(Vector2 point)
|
||||
{
|
||||
Coord.SetPoint(point.X, point.Y);
|
||||
}
|
||||
|
||||
public Site ()
|
||||
{
|
||||
Coord = new DoubleVector2();
|
||||
}
|
||||
}
|
||||
|
||||
public class Edge
|
||||
{
|
||||
public double a = 0, b = 0, c = 0;
|
||||
public Site[] ep;
|
||||
public Site[] reg;
|
||||
public int edgenbr;
|
||||
|
||||
public Edge ()
|
||||
{
|
||||
ep = new Site[2];
|
||||
reg = new Site[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Halfedge
|
||||
{
|
||||
public Halfedge ELleft, ELright;
|
||||
public Edge ELedge;
|
||||
public bool deleted;
|
||||
public int ELpm;
|
||||
public Site vertex;
|
||||
public double ystar;
|
||||
public Halfedge PQnext;
|
||||
|
||||
public Halfedge ()
|
||||
{
|
||||
PQnext = null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CellType
|
||||
{
|
||||
Solid, Empty, Edge, Path, Removed
|
||||
}
|
||||
|
||||
public class VoronoiCell
|
||||
{
|
||||
public List<GraphEdge> Edges;
|
||||
public Site Site;
|
||||
|
||||
public List<Vector2> BodyVertices;
|
||||
|
||||
public Body Body;
|
||||
|
||||
public CellType CellType;
|
||||
|
||||
public Vector2 Translation;
|
||||
|
||||
public Vector2 Center
|
||||
{
|
||||
get { return new Vector2((float)Site.Coord.X, (float)Site.Coord.Y) + Translation; }
|
||||
}
|
||||
|
||||
public VoronoiCell(Vector2[] vertices)
|
||||
{
|
||||
Edges = new List<GraphEdge>();
|
||||
BodyVertices = new List<Vector2>();
|
||||
|
||||
Vector2 midPoint = Vector2.Zero;
|
||||
foreach (Vector2 vertex in vertices)
|
||||
{
|
||||
midPoint += vertex;
|
||||
}
|
||||
midPoint /= vertices.Length;
|
||||
|
||||
|
||||
for (int i = 1; i < vertices.Length; i++ )
|
||||
{
|
||||
GraphEdge ge = new GraphEdge(vertices[i-1], vertices[i]);
|
||||
|
||||
System.Diagnostics.Debug.Assert(ge.Point1 != ge.Point2);
|
||||
|
||||
Edges.Add(ge);
|
||||
}
|
||||
|
||||
GraphEdge lastEdge = new GraphEdge(vertices[0], vertices[vertices.Length-1]);
|
||||
|
||||
Edges.Add(lastEdge);
|
||||
|
||||
Site = new Site();
|
||||
Site.SetPoint(midPoint);
|
||||
}
|
||||
|
||||
public VoronoiCell(Site site)
|
||||
{
|
||||
Edges = new List<GraphEdge>();
|
||||
BodyVertices = new List<Vector2>();
|
||||
//bodies = new List<Body>();
|
||||
this.Site = site;
|
||||
}
|
||||
|
||||
public bool IsPointInside(Vector2 point)
|
||||
{
|
||||
foreach (GraphEdge edge in Edges)
|
||||
{
|
||||
if (MathUtils.LinesIntersect(point, Center, edge.Point1 + Translation, edge.Point2 + Translation)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class GraphEdge
|
||||
{
|
||||
public Vector2 Point1, Point2;
|
||||
public Site Site1, Site2;
|
||||
public VoronoiCell Cell1, Cell2;
|
||||
|
||||
public bool IsSolid;
|
||||
|
||||
public bool OutsideLevel;
|
||||
|
||||
public Vector2 Center
|
||||
{
|
||||
get { return (Point1 + Point2) / 2.0f; }
|
||||
}
|
||||
|
||||
public GraphEdge(Vector2 point1, Vector2 point2)
|
||||
{
|
||||
this.Point1 = point1;
|
||||
this.Point2 = point2;
|
||||
}
|
||||
|
||||
public VoronoiCell AdjacentCell(VoronoiCell cell)
|
||||
{
|
||||
if (Cell1 == cell)
|
||||
{
|
||||
return Cell2;
|
||||
}
|
||||
else if (Cell2 == cell)
|
||||
{
|
||||
return Cell1;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the normal of the edge that points outwards from the specified cell
|
||||
/// </summary>
|
||||
public Vector2 GetNormal(VoronoiCell cell)
|
||||
{
|
||||
Vector2 dir = Vector2.Normalize(Point1 - Point2);
|
||||
Vector2 normal = new Vector2(dir.Y, -dir.X);
|
||||
if (cell != null && Vector2.Dot(normal, Vector2.Normalize(Center - cell.Center)) < 0)
|
||||
{
|
||||
normal = -normal;
|
||||
}
|
||||
return normal;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "GraphEdge (" + Point1.ToString() + ", " + Point2.ToString() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
// للترتيب
|
||||
public class SiteSorterYX : IComparer<Site>
|
||||
{
|
||||
public int Compare ( Site p1, Site p2 )
|
||||
{
|
||||
DoubleVector2 s1 = p1.Coord;
|
||||
DoubleVector2 s2 = p2.Coord;
|
||||
if ( s1.Y < s2.Y ) return -1;
|
||||
if ( s1.Y > s2.Y ) return 1;
|
||||
if ( s1.X < s2.X ) return -1;
|
||||
if ( s1.X > s2.X ) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user