Merge branch 'master' of https://bitbucket.org/Regalis11/repo
Conflicts: Subsurface_Solution.v12.suo
This commit is contained in:
@@ -204,6 +204,9 @@ namespace Subsurface
|
|||||||
Hull.EditWater = !Hull.EditWater;
|
Hull.EditWater = !Hull.EditWater;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "generatelevel":
|
||||||
|
Game1.Level = new Level(Game1.localRandom.Next(), 20, 5000, 5000);
|
||||||
|
break;
|
||||||
case "fowenabled":
|
case "fowenabled":
|
||||||
case "fow":
|
case "fow":
|
||||||
case "drawfow":
|
case "drawfow":
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ namespace Subsurface
|
|||||||
public static EditMapScreen EditMapScreen;
|
public static EditMapScreen EditMapScreen;
|
||||||
public static EditCharacterScreen EditCharacterScreen;
|
public static EditCharacterScreen EditCharacterScreen;
|
||||||
|
|
||||||
|
public static Level Level;
|
||||||
|
|
||||||
public static GameSession GameSession;
|
public static GameSession GameSession;
|
||||||
|
|
||||||
public static GameClient Client;
|
public static GameClient Client;
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
using FarseerPhysics;
|
||||||
|
using FarseerPhysics.Common;
|
||||||
|
using FarseerPhysics.Dynamics;
|
||||||
|
using FarseerPhysics.Factories;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Voronoi2;
|
||||||
|
|
||||||
|
namespace Subsurface
|
||||||
|
{
|
||||||
|
class Level
|
||||||
|
{
|
||||||
|
private int seed;
|
||||||
|
|
||||||
|
List<Body> bodies;
|
||||||
|
List<VoronoiCell> cells;
|
||||||
|
|
||||||
|
public Level(int seed, int siteCount, int width, int height)
|
||||||
|
{
|
||||||
|
this.seed = seed;
|
||||||
|
|
||||||
|
Voronoi voronoi = new Voronoi(1.0);
|
||||||
|
|
||||||
|
List<PointF> sites = new List<PointF>();
|
||||||
|
Random rand = new Random(seed);
|
||||||
|
|
||||||
|
for (int i = 0; i < siteCount; i++)
|
||||||
|
{
|
||||||
|
sites.Add(new PointF((float)(rand.NextDouble() * width), (float)(rand.NextDouble() * width)));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GraphEdge> graphEdges = MakeVoronoiGraph(sites, voronoi, width, height);
|
||||||
|
|
||||||
|
cells = new List<VoronoiCell>();
|
||||||
|
foreach (GraphEdge ge in graphEdges)
|
||||||
|
{
|
||||||
|
for (int i = 0; i<2; i++)
|
||||||
|
{
|
||||||
|
int site = (i==0) ? ge.site1 : ge.site2;
|
||||||
|
VoronoiCell cell = cells.Find(c => c.site == site);
|
||||||
|
if (cell == null)
|
||||||
|
{
|
||||||
|
cell = new VoronoiCell(site);
|
||||||
|
cells.Add(cell);
|
||||||
|
}
|
||||||
|
if (!cell.edges.Contains(ge)) cell.edges.Add(ge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bodies = new List<Body>();
|
||||||
|
foreach (VoronoiCell cell in cells)
|
||||||
|
{
|
||||||
|
//List of vectors defining my custom poly
|
||||||
|
List<Vector2> vlist = new List<Vector2>();
|
||||||
|
foreach (GraphEdge ge in cell.edges)
|
||||||
|
{
|
||||||
|
if (vlist.Contains(ge.point1)) continue;
|
||||||
|
vlist.Add(ge.point1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vlist.Count < 2) continue;
|
||||||
|
|
||||||
|
for (int i = 0; i < vlist.Count; i++ )
|
||||||
|
{
|
||||||
|
vlist[i] = ConvertUnits.ToSimUnits(vlist[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//get farseer 'vertices' from vectors
|
||||||
|
Vertices _shapevertices = new Vertices(vlist);
|
||||||
|
//_shapevertices.Sort(less);
|
||||||
|
|
||||||
|
//feed vertices array to BodyFactory.CreatePolygon to get a new farseer polygonal body
|
||||||
|
Body _newBody = BodyFactory.CreatePolygon(Game1.world, _shapevertices, 15);
|
||||||
|
_newBody.BodyType = BodyType.Static;
|
||||||
|
_newBody.CollisionCategories = Physics.CollisionWall;
|
||||||
|
|
||||||
|
bodies.Add(_newBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int Compare(Vector2 a, Vector2 b, Vector2 center)
|
||||||
|
{
|
||||||
|
if (a.X - center.X >= 0 && b.X - center.X < 0) return 1;
|
||||||
|
if (a.X - center.X < 0 && b.X - center.X >= 0) return -1;
|
||||||
|
if (a.X - center.X == 0 && b.X - center.X == 0)
|
||||||
|
{
|
||||||
|
if (a.Y - center.Y >= 0 || b.Y - center.Y >= 0) return Math.Sign(a.Y - b.Y);
|
||||||
|
return Math.Sign(b.Y-a.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the cross product of vectors (center -> a) x (center -> b)
|
||||||
|
float det = (a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y);
|
||||||
|
if (det < 0) return 1;
|
||||||
|
if (det > 0) return -1;
|
||||||
|
|
||||||
|
// points a and b are on the same line from the center
|
||||||
|
// check which point is closer to the center
|
||||||
|
float d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y);
|
||||||
|
float d2 = (b.X - center.X) * (b.X - center.X) + (b.Y - center.Y) * (b.Y - center.Y);
|
||||||
|
return Math.Sign(d1 - d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GraphEdge> MakeVoronoiGraph(List<PointF> sites, Voronoi voronoi, 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 voronoi.generateVoronoi(xVal, yVal, 0, width, 0, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
foreach (VoronoiCell cell in cells)
|
||||||
|
{
|
||||||
|
for (int i = 0; i<cell.edges.Count; i++)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, cell.edges[i].point1, cell.edges[i].point2, Microsoft.Xna.Framework.Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,976 @@
|
|||||||
|
/*
|
||||||
|
* 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 Point PQ_min ()
|
||||||
|
{
|
||||||
|
Point answer = new Point ();
|
||||||
|
|
||||||
|
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( Point 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 ();
|
||||||
|
allEdges.Add ( newEdge );
|
||||||
|
newEdge.point1 = point1;
|
||||||
|
newEdge.point2 = point2;
|
||||||
|
|
||||||
|
newEdge.site1 = leftSite.sitenbr;
|
||||||
|
newEdge.site2 = rightSite.sitenbr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, Point 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;
|
||||||
|
Point 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Voronoi Class End
|
||||||
|
} // namespace Voronoi2 End
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* 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 Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Voronoi2
|
||||||
|
{
|
||||||
|
public class Point
|
||||||
|
{
|
||||||
|
public double x, y;
|
||||||
|
|
||||||
|
public Point ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPoint ( double x, double y )
|
||||||
|
{
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use for sites and vertecies
|
||||||
|
public class Site
|
||||||
|
{
|
||||||
|
public Point coord;
|
||||||
|
public int sitenbr;
|
||||||
|
|
||||||
|
public Site ()
|
||||||
|
{
|
||||||
|
coord = new Point();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 class VoronoiCell
|
||||||
|
{
|
||||||
|
public List<GraphEdge> edges;
|
||||||
|
public int site;
|
||||||
|
|
||||||
|
public VoronoiCell(int site)
|
||||||
|
{
|
||||||
|
edges = new List<GraphEdge>();
|
||||||
|
this.site = site;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GraphEdge
|
||||||
|
{
|
||||||
|
public Vector2 point1, point2;
|
||||||
|
public int site1, site2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// للترتيب
|
||||||
|
public class SiteSorterYX : IComparer<Site>
|
||||||
|
{
|
||||||
|
public int Compare ( Site p1, Site p2 )
|
||||||
|
{
|
||||||
|
Point s1 = p1.coord;
|
||||||
|
Point 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -183,6 +183,8 @@ namespace Subsurface
|
|||||||
BlendState.AlphaBlend,
|
BlendState.AlphaBlend,
|
||||||
null, null, null, null,
|
null, null, null, null,
|
||||||
cam.Transform);
|
cam.Transform);
|
||||||
|
|
||||||
|
if (Game1.Level!=null) Game1.Level.Render(spriteBatch);
|
||||||
|
|
||||||
Map.DrawBack(spriteBatch);
|
Map.DrawBack(spriteBatch);
|
||||||
|
|
||||||
|
|||||||
@@ -124,9 +124,12 @@
|
|||||||
<Compile Include="Map\Entity.cs" />
|
<Compile Include="Map\Entity.cs" />
|
||||||
<Compile Include="Map\Explosion.cs" />
|
<Compile Include="Map\Explosion.cs" />
|
||||||
<Compile Include="Map\IDamageable.cs" />
|
<Compile Include="Map\IDamageable.cs" />
|
||||||
|
<Compile Include="Map\Level.cs" />
|
||||||
<Compile Include="Map\Lights\ConvexHull.cs" />
|
<Compile Include="Map\Lights\ConvexHull.cs" />
|
||||||
<Compile Include="Map\Lights\LightManager.cs" />
|
<Compile Include="Map\Lights\LightManager.cs" />
|
||||||
<Compile Include="Map\MapHash.cs" />
|
<Compile Include="Map\MapHash.cs" />
|
||||||
|
<Compile Include="Map\Voronoi.cs" />
|
||||||
|
<Compile Include="Map\VoronoiElements.cs" />
|
||||||
<Compile Include="Physics\PhysicsBody.cs" />
|
<Compile Include="Physics\PhysicsBody.cs" />
|
||||||
<Compile Include="Networking\NetworkEvent.cs" />
|
<Compile Include="Networking\NetworkEvent.cs" />
|
||||||
<Compile Include="Networking\NetworkMember.cs" />
|
<Compile Include="Networking\NetworkMember.cs" />
|
||||||
|
|||||||
@@ -9,6 +9,6 @@
|
|||||||
<ErrorReportUrlHistory />
|
<ErrorReportUrlHistory />
|
||||||
<FallbackCulture>en-US</FallbackCulture>
|
<FallbackCulture>en-US</FallbackCulture>
|
||||||
<VerifyUploadedFiles>false</VerifyUploadedFiles>
|
<VerifyUploadedFiles>false</VerifyUploadedFiles>
|
||||||
<ProjectView>ProjectFiles</ProjectView>
|
<ProjectView>ShowAllFiles</ProjectView>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Reference in New Issue
Block a user