Slicing a 3d image - c#

I'm trying to slice a 3d representation of a image. Following factors is known:
DimensionX
DimensionY
DimensionZ
voxels[]
Voxels[] is an array of ushorts representing the grayscale of the pixel.
Now i need to slice it in all possible directions. With let we say x, y or z.
I have tree implementations for this, but they have one problem, they don't work with dimensions that are not the same. (Except for get Z Slice, this is working perfectly).
These are the methods:
private ushort[] GetZSlice(int z, ushort[] voxels, int DimensionX, int DimensionY)
{
var res = new ushort[DimensionX * DimensionY];
for(int j = 0; j < DimensionY; j++)
{
for(int i = 0; i < DimensionX; i++)
{
res[j*DimensionX + i] = voxels[z*DimensionX*DimensionY + j*DimensionX + i];
}
}
return res;
}
This method is working perfectly, it does not mather wat i choose as the dimension.
The next two methods, with x or y as depth poses as a harder problem.
private ushort[] GetYSlice(int y, ushort[] voxels, int DimensionX, int DimensionY, int DimensionZ)
{
var res = new ushort[DimensionX * DimensionZ];
for( int i = 0; i < DimensionX; i++)
{
for( int j = 0; j < DimensionX; j++)
{
res[j + i*DimensionX] = voxels[j * DimensionZ * DimensionY + Y*DimensionZ + i]
}
}
return res;
}
private ushort[] GetXSlice(int x, ushort[voxels], int DimensionX, int DimensionY, int DimensionZ)
{
var res = new short[DimensionY * DimensionZ];
for(int i = 0; i < DimensionY; i++)
{
for(int j = 0; j < DimensionZ; j++)
{
res[j + i*DimensionZ] = voxels[i*DimensionY + j*DimensionZ*DimensionX + x]
}
}
return res;
}
How could I improve the last 2 methods so it works with dimensions that are not equal?

Why not make universal slice function using basis vectors? It will be far less code the manage.
Basicly you got U,V axises each mapped into X,Y or Z. And the Slice W is the third unused axis. So you just loop the U,V and leave W as is. Each U,V has a basis vector (ux,uy,uz) , (vx,vy,vz) that describes the increment change in x,y,z coordinates.
I encoded it into my LED cube class in C++...
//---------------------------------------------------------------------------
class LED_cube
{
public:
int xs,ys,zs,***map;
LED_cube() { xs=0; ys=0; zs=0; map=NULL; }
LED_cube(LED_cube& a) { xs=0; ys=0; zs=0; map=NULL; *this=a; }
~LED_cube() { _free(); }
LED_cube* operator = (const LED_cube *a) { *this=*a; return this; }
LED_cube* operator = (const LED_cube &a);
void _free();
void resize(int _xs,int _ys,int _zs);
void cls(int col); // clear cube with col 0x00BBGGRR
void sphere(int x0,int y0,int z0,int r,int col); // draws sphere surface with col 0x00BBGGRR
void slice (char *uv,int slice,int col); // draws (XY,XZ,YZ) slice with col 0x00BBGGRR
void glDraw(); // render cube by OpenGL as 1x1x1 cube at 0,0,0
};
//---------------------------------------------------------------------------
void LED_cube::slice(char *uv,int slice,int col)
{
// detect basis vectors from uv string
int ux=0,uy=0,uz=0,us=0;
int vx=0,vy=0,vz=0,vs=0;
int x=slice,y=slice,z=slice,u,v,x0,y0,z0;
if (uv[0]=='X') { x=0; ux=1; us=xs; }
if (uv[0]=='Y') { y=0; uy=1; us=ys; }
if (uv[0]=='Z') { z=0; uz=1; us=zs; }
if (uv[1]=='X') { x=0; vx=1; vs=xs; }
if (uv[1]=='Y') { y=0; vy=1; vs=ys; }
if (uv[1]=='Z') { z=0; vz=1; vs=zs; }
// render slice
if ((x>=0)&&(x<xs)&&(y>=0)&&(y<ys)&&(z>=0)&&(z<zs))
for (u=0;u<us;u++,x+=ux,y+=uy,z+=uz)
{
x0=x; y0=y; z0=z;
for (v=0;v<vs;v++,x+=vx,y+=vy,z+=vz)
map[x][y][z]=col;
x=x0; y=y0; z=z0;
}
}
//---------------------------------------------------------------------------
As you can see it is quite nice and simple ... and still can be optimized much more. here usage and output example:
cube.resize(32,16,20);
cube.cls(0x00202020);
cube.slice("XY",5,0x000000FF);
cube.slice("XZ",5,0x0000FF00);
cube.slice("YZ",5,0x00FF0000);
cube.glDraw();
As you got your voxels stored in 1D array then just compute the address from x,y,z. so map[x][y][z] will became your voxels[(x*ys*zs)+(y*zs)+z] or what ever combination of axis order you got. This can be totally encoded into the basis vectors so you can have du=(ux*ys*zs)+(uy*zs)+uz and dv=... and increment the address directly not needing any multiplication latter ...

Related

C# having a list what's the best way to print a board

Having a list of 25 integers. What'd be the better approach to make a 5x5 board?
List<int> x = Enumerable.Repeat(0, 25).ToList();
Here's a list that's filled with 0. In the image below I had represented this list was B(a).
I did this image to show you what's the problem I'm facing to. Notice that for example B(b)[6] has a value of 7.
In a classic Matrix 5x5 the value of 6 would be 19. I'm not pretty sure how to face this problem, I think that for the game it'd better be treated like a list but with the purpose of showing the board it's a must to be like that.
How could I print this kind of board?
I would argue that the first step would be to convert the array to some representation of 2D data in some way, and then have a print method using the 2D data as input. One way to do this would be to create a wrapper around the array with methods suitable to indexing into the 1D array. For example:
public class My2DArray<T>
public int Width { get; }
public int Height { get; }
public T[] Data { get; }
public My2DArray(int width, T[] data)
{
Width = width;
Height = data.Length / width; // might want to check there is no remainder here
Data = data;
}
public T this[int x, int y]
{
get => Data[y * Width + x];
set => Data[y * Width + x] = value;
}
public string ToString(string valueSeparator , string rowSeparator)
{
var sb = new StringBuilder();
for (int y = 0; y < Height; y++)
{
var row = y * Width;
for (int x = 0; x < Width; x++)
{
sb.Append(Data[row + x])
.Append(valueSeparator);
}
sb.Append(rowSeparator);
}
return sb.ToString();
}
}

C# Have problems generating random 2d array from smaller arrays

I am trying to generate a random 2D array, from a number of smaller arrays. I plan to use it some day to generate a random game map.
Each smaller array is called "Island". Each of them is manually predefined.
char[,] Island1 = new char[,]
{
{'A', 'A', 'A'},
{'A','B','A'},
{'A','A','A'}
};
char[,] Island2 = new char[,]
{
{'C', 'C'},
{'C','C'}
};
char[,] Island3 = new char[,]
{
{'D', 'D', 'D'},
{'D','D','D'},
{'D','D','D'}
};
I am trying to generate a larger array, with all smaller ones inside, placed randomly.
What's important, is that smaller arrays shouldn't overlap each other.
public static Boolean CanPlaceIsland(int StartX, int StartY, Island thisIsland)
{
Boolean Answer = true;
for (int i = StartX; i<StartX+thisIsland.CellArray.GetLength(0);i++)
{
for (int j = StartX; j<StartY+thisIsland.CellArray.GetLength(1);j++)
{
if (WorldMap[i,j].Terrain!='.')
Answer = false;
}
}
return Answer;
}
I am trying to go through each island, one by one, and only add new one, if it doesn't overlap non-empty squares.
Here's updated method for filling the map with islands (previous version could cause infinite loop).
public static void CreateEmptyMap()
{
WorldMap = new Cell[WorldX, WorldY];
for (int i=0; i<WorldX; i++)
for (int j=0; j<WorldY; j++)
WorldMap[i,j] = new Cell('.');
}
public static void FillMap()
{
int IslandsPlaced=0;
foreach(Island thisIsland in IslandsList)
{
Boolean check = false;
int x = 0;
int y = 0;
Random w = rnd;
int SideA = thisIsland.CellArray.GetLength(0);
int SideB = thisIsland.CellArray.GetLength(1);
int WorldSideA = WorldMap.GetLength(0);
int WorldSideB = WorldMap.GetLength(1);
x = w.Next(2, WorldSideA-SideA-1);
y = w.Next(2,WorldSideB-SideB-1);
check = CanPlaceIsland(x,y,thisIsland);
if (check==true)
{
PlaceIsland(x,y,thisIsland);
IslandsPlaced++;
}
}
if (IslandsPlaced!=IslandsList.Count())
{
CreateEmptyMap();
FillMap();
}
}
The placing:
public static void PlaceIsland(int x, int y, Island thisIsland)
{
int SideA = thisIsland.CellArray.GetLength(0);
int SideB = thisIsland.CellArray.GetLength(1);
for (int i=0; i<SideA;i++)
{
for (int j=0; j<SideB;j++)
{
WorldMap[x+i,y+j] = thisIsland.CellArray[i,j];
}
}
}
However, sometimes islands still overlap, and I can't find why.
..........
..........
..........
..........
....AAA...
..DDDBA...
..DDDAA...
..DDD.....
..........
..........
Your bug is in CanPlaceIsland:
for (int j = StartX; //error here!
j < StartY + thisIsland.CellArray.GetLength(1);
j++) { ... }
Should be:
for (int j = StartY;
j < StartY + thisIsland.CellArray.GetLength(1);
j++) { ... }
Looks like a typical copy and paste bug...
Apart from that, if your maps are rather crowded, you risk entering an infinite loop if there is no solution for a given island.
Computing if one or more valid solutions exist and if the combination you are currently in is one of them can be expensive and somewhat tricky so, unless you really have to deal with crowded maps where a solution must be given, I'd bale out after a predetermined number of failed attempts placing an island; you might get false negatives once in a while but its probably something you can live with.

Randomly generate blocks on a flat map

I'm trying to randomly generate blocks on a flat map and make it so that they don't overlap each other.
I have made a matrix (c# array) of the size of the map (500x500), the blocks have a scale between 1 and 5.
The code works but if a generated block overlaps another one, it is destroyed and not regenerated somewhere else.
Only around 80 of the 1000 blocks I try to generate don't overlap another block.
Here is a picture of the map with around 80 blocks generated, the green squares are blocks
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
bool elementFound = false;
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el;
// Randomly generate block size and position
int size = Random.Range(minScale, maxScale + 1);
int x = Random.Range(0, mapSizex + 1 - size);
int y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
if (elementFound)
continue;
else {
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
}
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
}
}
I thought of 3 possible fixes
I should set the size of the block depending of the place it has.
I should use another randomization algorithm.
I'm not doing this right.
What do you think is the best idea ?
UPDATE
I got the code working much better. I now try to instantiate the blocks multiple times if needed (maximum 5 for the moment) and I fixed the bugs. If there are already many elements on the map, they will not always be instantiated and that's what I wanted, I just have to find the right amount of times it will try to instantiate the block.
I tried instantiating 1280 elements on a 500x500 map. It takes only about 1.5 second and it instantiated 1278/1280 blocks (99.843%).
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
bool elementFound = false;
int cnt = 0;
// Generate every block
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el = null;
// Randomly generate block size and position
int size, x, y, tryCnt = 0;
// Try maximum 5 times to generate the block
do {
elementFound = false;
// Randomly set block size and position
size = Random.Range(minScale, maxScale + 1);
x = Random.Range(0, mapSizex + 1 - size);
y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
tryCnt++;
} while (elementFound && tryCnt < 5);
if (tryCnt >= 5 && elementFound) continue;
// Instantiate the block
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
cnt++;
}
print("Instantiated " + cnt + "/" + ratio * generationDefault);
}
This is incredibly difficult to do well.
Here's a quick solution you'll maybe like ... depending on your scene.
actualWidth = 500 //or whatever. assume here is square
// your blocks are up to 5 size
chunkWidth = actualWidth / 5
// it goes without saying, everything here is an int
kChunks = chunkWidth*chunkWidth
List<int> shuf = Enumerable.Range(1,kChunks).OrderBy(r=>Random.value).ToList();
howManyWanted = 1000
shuf = shuf.Take(howManyWanted)
foreach( i in shuf )
x = i % actualWidth
y = i / actualWidth
make block at x y
put block in list allBlocks
HOWEVER ............
...... you'll see that this looks kind of "regular", so do this:
Just randomly perturb all the blocks. Remember, video game programming is about clever tricks!
Ideally, you have to start from the middle and work your way out; in any event you can't just do them in a line. Shuffling is OK. So, do this ..
harmonic = 3 //for example. TRY DIFFERENT VALUES
function rh = Random.Range(1,harmonic) (that's 1 not 0)
function rhPosNeg
n = rh
n = either +n or -n
return n
function onePerturbation
{
allBlocks = allBlocks.OrderBy(r => Random.value) //essential
foreach b in allBlocks
newPotentialPosition = Vector2(rhPosNeg,rhPosNeg)
possible = your function to check if it is possible
to have a block at newPotentialPosition,
however be careful not to check "yourself"
if possible, move block to newPotentialPosition
}
The simplest approach is just run onePerturbation, say, three times. Have a look at it between each run. Also try different values of the harmonic tuning factor.
There are many ways to perturb fields of differently-sized blocks, above is a KISS solution that hopefully looks good for your situation.
Coding note...
How to get sets of unique random numbers.
Just to explain this line of code...
List<int> shuf = Enumerable.Range(1,kChunks).OrderBy(r=>Random.value).ToList();
If you are new to coding: say you want to do this: "get a hundred random numbers, from 1 to million, but with no repeats".
Fortunately, this is a very well known problem with a very simple solution.
The way you get numbers with no repeats, is simply shuffle all the numbers, and then take how many you want off the top.
For example, say you need a random couple of numbers from 1-10 but with no repeats.
So, here's the numbers 1-10 shuffled: 3,8,6,1,2,7,10,9,4,5
Simply take what you need off the front: so, 3, 8, 6 etc.
So to make an example let's say you want twelve numbers, no repeats, from 1 through 75. So the first problem is, you want a List with all the numbers up to 75, but shuffled. In fact you do that like this ..
List<int> shuf = Enumerable.Range(1,75).OrderBy(r=>Random.value).ToList();
So that list is 75 items long. You can check it by saying foreach(int r in shuf) Debug.Log(r);. Next in the example you only want 12 of those numbers. Fortunately there's a List call that does this:
shuf = shuf.Take(12)
So, that's it - you now have 12 numbers, no repeats, all random between 1 and 75. Again you can check with foreach(int r in shuf) Debug.Log(r);
In short, when you want "n" numbers, no repeats, between 1 and Max, all you have to so is this:
List<int> shuf = Enumerable.Range(1,Max).OrderBy(r=>Random.value).ToList();
shuf = shuf.Take(n);
et voilĂ , you can check the result with foreach(int r in shuf) Debug.Log(r);
I just explain this at length because the question is often asked "how to get random numbers that are unique". This is an "age-old" programming trick and the answer is simply that you shuffle an array of all the integers involved.
Interestingly, if you google this question ("how to get random numbers that are unique") it's one of those rare occasions where google is not much help, because: whenever this question is asked, you get a plethora of keen new programmers (who have not heard the simple trick to do it properly!!) writing out huge long complicated ideas, leading to further confusion and complication.
So that's how you make random numbers with no repeats, fortunately it is trivial.
if (elementFound) continue; will skip out this current loop iteration. You need to wrap the int x=Random..; int y=Random()..; part in a while loop with the condition being while(/* position x/y already occupued*/) { /* generate new valid point */} like this for example:
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el;
// Randomly generate block size and position
bool elementFound = false;
int size, x, y;
do
{
elementFound = false;
size = Random.Range(minScale, maxScale + 1);
x = Random.Range(0, mapSizex + 1 - size);
y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
} while(elementFound);
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
}
}
You shouldn't be getting that many collisions.
Assuming your blocks were ALL 5 units wide and you're trying to fit them into a grid of 500,500 you would have 100*100 spaces for them at minimum, which gives 10,000 spaces into which to fit 1,000 blocks.
Try playing around with this code:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var result = PlaceNonOverlappingBlocks(1000, 5, 500, 500);
}
static List<Block> PlaceNonOverlappingBlocks(int count, int maxBlockSize, int mapX, int mapY)
{
var map = new bool[mapY, mapX];
var rng = new Random();
var result = new List<Block>(count);
int collisions = 0;
while (count > 0)
{
int size = rng.Next(1, maxBlockSize + 1);
int x = rng.Next(0, mapX - size);
int y = rng.Next(0, mapY - size);
if (fits(map, x, y, size))
{
result.Add(new Block(x, y, size));
addToMap(map, x, y, size);
--count;
}
else
{
if (++collisions> 100000)
throw new InvalidOperationException("Hell has frozen over");
}
}
// This is just for diagnostics, and can be removed.
Console.WriteLine($"There were {collisions} collisions.");
return result;
}
static void addToMap(bool[,] map, int px, int py, int size)
{
for (int x = px; x < px+size; ++x)
for (int y = py; y < py + size; ++y)
map[y, x] = true;
}
static bool fits(bool[,] map, int px, int py, int size)
{
for (int x = px; x < px + size; ++x)
for (int y = py; y < py + size; ++y)
if (map[y, x])
return false;
return true;
}
internal class Block
{
public int X { get; }
public int Y { get; }
public int Size { get; }
public Block(int x, int y, int size)
{
X = x;
Y = y;
Size = size;
}
}
}
}

OpenCvSharp PCA Exception: Unsupported combination of input and output array formats

I'm using OpenCVSharp (OpenCvSharp3-AnyCPU Version 3.0.0.20150823 running in Visual Studio 2015 and installed via NuGet) to access OpenCV from C#, but when calling Cv2.PCACompute I get a generic OpenCVException stating that I have an Unsupported combination of input and output array formats.
My goal is to use PCA to find the primary axis of a pixel blob. This is my (stripped down) code at present:
using OpenCvSharp;
public struct point2D
{
public int X;
public int Y;
public point2D(int X, int Y)
{
this.X = X;
this.Y = Y;
}
}
public static void PCA2D()
{
int height = 5;
int width = 5;
int[] image = new int[]
{
0,0,0,0,1,
0,0,0,1,0,
0,0,1,0,0,
0,1,0,0,0,
1,0,0,0,0,
}
// extract the datapoints
List<point2D> dataPoints = new List<point2D>();
for (int row = 0; row < height; ++row)
{
for (int col = 0; col < width; ++col)
{
if (image[row * width + col] == 1)
{
dataPoints.Add(new point2D(col, row));
}
}
}
// create the input matrix
Mat input = new Mat(dataPoints.Length, 2, MatType.CV_32SC1);
for (int i = 0; i < dataPoints.Length; ++i)
{
input.Set(i, 0, dataPoints[i].X);
input.Set(i, 1, dataPoints[i].Y);
}
Mat mean = new Mat();
Mat eigenvectors = new Mat();
// OpenCVException occurs here: unsupported combination of input and output array formats
Cv2.PCACompute(input, mean, eigenvectors);
// Code to get orientation from the eigenvectors
}
I haven't been able to find any documentation on how to initialise the mean and eigenvector Mats, or if the way I'm calling PCACompute is even correct. Some insight into the correct procedure for using PCACompute would be immensely helpful.
So it turns out that dataPoints cannot be MatType.CV_32SC1. Changing the code to the following allowed it to work:
// create the input matrix
Mat input = new Mat(dataPoints.Length, 2, MatType.CV_32FC1);
for (int i = 0; i < dataPoints.Length; ++i)
{
input.Set(i, 0, (float)dataPoints[i].X);
input.Set(i, 1, (float)dataPoints[i].Y);
}

Simple Cluster algorithm 2D. Detecting clumps of points

Anyone know a simple algorithm to implement in C# to detect monster groups in a 2D game.
EX:
100 Range around the char there are monsters. I want to detect which monsters are within range 2 of each other, and if there is at-least 5 together, use the Area of Effect skill on that location. Otherwise use the single-target skill.
A link to an implementation would be great, C# preferably. I just get lost reading the Wikipedia articles.
EDIT:
"your question is incomplete. what do you want to do exactly? do you want to find all groups? the biggest group? any group, if there are groups, none otherwise? please be more specific." -gilad hoch
I want to find all groups within 100 units of range around the main character. The groups should be formed if there are at-least 5 or more monsters all within 2 range of each other, or maybe within 10 range from the center monster.
So the result should be probably a new List of groups or a List of potential target locations.
a very simple clustering algorithm is the k-mean algorithm. it is like
create random points
assign all points to the nearest point, and create groups
relocate the original points to the middle of the groups
do the last two steps several times.
an implementation you can find for example here, or just google for "kmean c#"
http://kunuk.wordpress.com/2011/09/20/markerclusterer-with-c-example-and-html-canvas-part-3/
I recently implemented the algorithm given in this paper by Efraty, which solves the problem by considering the intersections of circles of radius 2 centered at each given point. In simple terms, if you order the points in which two circles intersect in clockwise order, then you can do something similar to a line sweep to figure out the point in which a bomb (or AoE spell) needs to be launched to hit the most enemies. The implementation is this:
#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;
#define INF 1e16
#define eps 1e-8
#define MAXN 210
#define RADIUS 2
struct point {
double x,y;
point() {}
point(double xx, double yy) : x(xx), y(yy) {}
point operator*(double ot) {
return point(x*ot, y*ot);
}
point operator+(point ot) {
return point(x+ot.x, y+ot.y);
}
point operator-(point ot) {
return point(x-ot.x, y-ot.y);
}
point operator/(double ot) {
return point(x/ot, y/ot);
}
};
struct inter {
double x,y;
bool entry;
double comp;
bool operator< (inter ot) const {
return comp < ot.comp;
}
};
double dist(point a, point b) {
double dx = a.x-b.x;
double dy = a.y-b.y;
return sqrt(dx*dx+dy*dy);
}
int N,K;
point p[MAXN];
inter it[2*MAXN];
struct distst {
int id, dst;
bool operator<(distst ot) const {return dst<ot.dst;}
};
distst dst[200][200];
point best_point;
double calc_depth(double r, int i) {
int left_inter = 0;
point left = p[i];
left.y -= r;
best_point = left;
int tam = 0;
for (int k = 0; k < N; k++) {
int j = dst[i][k].id;
if (i==j) continue;
double d = dist(p[i], p[j]);
if (d > 2*r + eps) break;
if (fabs(d)<eps) {
left_inter++;
continue;
}
bool is_left = dist(p[j], left) < r+eps;
if (is_left) {
left_inter++;
}
double a = (d*d) / (2*d);
point diff = p[j] - p[i];
point p2 = p[i] + (diff * a) / d;
double h = sqrt(r*r - a*a);
it[tam].x = p2.x + h*( p[j].y - p[i].y ) / d;
it[tam].y = p2.y - h*( p[j].x - p[i].x ) / d;
it[tam+1].x = p2.x - h*( p[j].y - p[i].y ) / d;
it[tam+1].y = p2.y + h*( p[j].x - p[i].x ) / d;
it[tam].x -= p[i].x;
it[tam].y -= p[i].y;
it[tam+1].x -= p[i].x;
it[tam+1].y -= p[i].y;
it[tam].comp = atan2(it[tam].x, it[tam].y);
it[tam+1].comp = atan2(it[tam+1].x, it[tam+1].y);
if (it[tam] < it[tam+1]) {
it[tam].entry = true;
it[tam+1].entry = false;
}
else {
it[tam].entry = false;
it[tam+1].entry = true;
}
if (is_left) {
swap(it[tam].entry, it[tam+1].entry);
}
tam+=2;
}
int curr,best;
curr = best = left_inter;
sort(it,it+tam);
for (int j = 0; j < tam; j++) {
if (it[j].entry) curr++;
else curr--;
if (curr > best) {
best = curr;
best_point = point(it[j].x, it[j].y);
}
}
return best;
}
int main() {
scanf("%d", &N);
for (int i = 0; i < N; i++) {
scanf("%lf %lf", &p[i].x, &p[i].y);
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
dst[i][j].id = j;
dst[i][j].dst = dist(p[i],p[j]);
}
sort(dst[i],dst[i]+N);
}
int best = 0;
point target = p[0];
for (int i = 0; i < N; i++) {
int depth = calc_depth(RADIUS, i);
if (depth > best) {
best = depth;
target = best_point;
}
}
printf("A bomb at (%lf, %lf) will hit %d target(s).\n", target.x, target.y, best+1);
}
Sample usage:
2 (number of points)
0 0
3 0
A bomb at (1.500000, 1.322876) will hit 2 targets.

Categories

Resources