Exercise 13, from Chapter 12 of Stroustrup's Programming principles and practice using c++.
A superellipse is a two-dimensional shape defined by the equation
Look up superellipse on the web to get a better idea of what such
shapes look like. Write a program that draws "starlike" patterns by
connecting points on a superellipse. Take a, b, m, n, and N as
arguments.
Select N points on the superellipse defined by a, b, m,
and n. Make the points equally spaced for some definition of
"equal" Connect each of those N points to one or more other points
(if you like you can make the number of points connected to another
argument or just use N-1, i.e., all me orner points).
i have a vector that contains points with which i can build the superellipse
i cant get the second part of exercise - how to find N-points lying on superellipse to build stars?
thanks
//------------------------------------------------------------------------------
struct Point {
int x, y;
Point(int xx, int yy) : x(xx), y(yy) { }
Point() :x(0), y(0) { }
};
//------------------------------------------------------------------------------
int sgn(double d) {
if (d < 0)
return -1;
if (d == 0)
return 0;
if (d > 0)
return 1;
// exception
error("sgn: something gone wrong\n");
}
//------------------------------------------------------------------------------
vector<Point> superellipse(double a, double b, double m, double n, double precision = 0.01, int xCenter = 200, int yCenter = 200) {
if (precision >= 1.00 || precision < 0.001)
error ("use numbers from range [0.001 ; 1.00) for precision parametr\n");
vector<Point> points;
Point temp;
Point P;
for (double d = -1.0; d < 1.00; d += precision) {
double t = d*M_PI;
int x = pow((abs(cos(t))),2.0/m) * a * sgn(cos(t));
int y = pow((abs(sin(t))),2.0/n) * b * sgn(sin(t));
P = Point(x + xCenter, y + yCenter);
if (P != temp) // ignore dublicates
points.push_back(P);
temp = P;
}
return points;
}
//------------------------------------------------------------------------------
1.scratch
vector<Point> superellipse (/*...*/) {
/* */
return points;
}
2.put
class Superellipse {
std::vector<Point> _points;
void draw_connected(const Point& A, const Point& B);
public:
void draw_star(/* params */);
Superellipse(/* params*/){
/* initialize _points*/
}
};
i cant get the second part of exercise - how to find N-points lying on
superellipse to build stars?
???
You already have the points in your vector.
http://www.stroustrup.com/Programming/programming_ch12.pdf
if you like you can make the number of points connect to another
argument or just use N–1, i.e., all the other points
void Superellipse::draw_star (/* */){
int N = _points.size();
for (int i = 0; i < N; ++i) {
for (int j = i + 1; j < N; ++j) {
draw_connected (_points[i], _points[j]);
}
}
}
Related
I have a problem, probably, with memory leaking in C++ threads. I receive a runtime error with code 11. I am writing an optimization algorithm, which aims to optimize parameters of 2D reactors. It generates instances of reforming function, which creates Reformer objects. The reformers have 2 different parameters, which can differ locally in a single reformer and are passed to the reforming function from the main function. To specify, each reformer is divided into a specified number of zones (same dimensions and locations in each reformer), and each zone can have different parameters. Therefore, size of each of 2 vectors is equal to [NUMBER OF REFORMERS] * [NUMBER OF ZONES]. Then, the reforming function creates Segment objects, which number is equal to the number of zones.
I assume that the issue here is that threads try to access the same vector simultaneously and I would really appreciate a solution for that matter.
Remarks:
If I change the main.cpp to substitute the threads with a usual loop, no error is returned.
If I comment out the setProp method in the set_segments functions, no error is returned (with threads).
Threads are highly recommended here, due to long computation time of a single Reformer, and I have an access to a multi-core computing units.
To clarify, I will explain everything with a minimal reproducible example:
input.h
#include <iostream>
#include <fstream>
#include <vector>
#include <thread>
int reactor_no = 2; // number of reformers
int zones_X = 5; // number of zones in a single reformer, X direction
int zones_Y = 2; // number of zones in a single reformer, Y direction
double dim_X = 0.5; // reactor's length
double dim_Y = 0.2; // reactor's height
double wall_t = 0.1; // thickness of the reactor wall
size_t zones = zones_X * zones_Y;
Reformer.h:
#include "input.h"
class Reformer {
public:
Reformer() {}
Reformer(const double& L, const double& Y, const double& wall_t,
const int& zones_X = 1, const int& zones_Y = 1) {
length_ = L;
height_ = Y;
zonesX_ = zones_X;
zonesY_ = zones_Y;
wall_thickness_ = wall_t;
dx_ = length_ / static_cast<double> (zonesX_);
dr_ = height_ / static_cast<double> (zonesY_);
}
private:
double wall_thickness_; // wall thickness (m)
double length_; // recactor length (m)
double height_; // reactor height (m) (excluding wall thickness)
int zonesX_; // number of segments in the X direction
int zonesY_; // number of segments in the Y direction
double dx_; // segment width (m)
double dr_; // segment height (m)
}
Segment.h:
#include "input.h"
class Segment{
public:
Segment() : Segment(0, 0) {}
Segment(int i, int j) {
i_ = i;
j_ = j;
}
void setXR(const double& dx, const double& dr, const int& SL, const int& SR) {
x0_ = i_ * dx;
x1_ = x0_ + dx;
r0_ = j_ * dr;
r1_ = r0_ + dr;
if (i_ == SL - 1) {
x1_ = length;
}
if (j_ == SR - 1) {
r1_ = radius;
}
}
void setWall() {
x0_ = 0;
x1_ = length;
r0_ = radius;
r1_ = radius + wall_t;
}
void setProp(const double& por, const double& por_s, const bool& cat) {
porosity_ = por;
catalyst_ = cat;
}
private:
size_t i_; //segment column no.
size_t j_; //segment row no.
double x0_; //beginning of segment - x coordinate (m)
double x1_; //ending of segment - x coordinate (m)
double r0_; //beginning of segment - r coordinate (m)
double r1_; //ending of segment - r coordinate (m)
int catalyst_; //1 - catalytic, 0 - non-catalytic
double porosity_; //porosity (-)
};
main.cpp:
#include "input.h"
int main() {
int zones = zones_X * zones_Y;
size_t pop_size = reactor_no * zones;
std::vector<int> cat;
cat.reserve(pop_size);
std::vector<double> porosity;
porosity.reserve(pop_size); // the values in the vectors are not important, therefore I will just fill them with 1s
for (int i = 0; i < pop_size; i++) {
cat[i] = 1;
porosity[i] = 1.0;
}
std::vector<std::thread> Ref;
Ref.reserve(reactor_no);
for (k = 0; k < reactor_no; k++) {
Ref.emplace_back(reforming, k, cat, porosity);
}
for (auto &X : Ref) { X.join(); }
}
reforming.cpp:
#include "input.h"
void reforming(const int m, const std::vector<int>& cat_check, const std::vector<double>& por) {
Reformer reactor(length, radius, wall_t, zonesX, zonesY);
std::vector<Segment> seg; // vector holding segment objects
seg.reserve(zones);
set_segments(seg, reactor, zones, m, por, por_s, cat_check);
}
set_segments function:
#include "input.h"
void set_segments(std::vector<Segment> &seg, Reformer &reac, const int m,
const std::vector<double> &por, const std::vector<int> &check) {
int i, j, k, n;
double dx = dim_X / static_cast<double> (zones_X);
double dy = dim_Y / static_cast<double> (zones_Y);
std::vector<Segment*> ptr_seg;
ptr_seg.reserve(zones);
k = 0;
for (i = 0; i < zones_X; i++) {
for (j = 0; j < zones_Y; j++) {
n = m * zones + (i * zones_Y + j);
seg.emplace_back(Segment(i, j));
seg[k].setProp(por[n], check[n]);
seg[k].setXR(dx, dy, zones_X, zones_Y);
k++;
}
}
}
Adding std::ref() to the reforming function call parameters solved the problem.
for (k = 0; k < spec_max; k++) {
Ref.emplace_back(reforming, k, std::ref(cat), std::ref(porosity));
}
I'm working on visualizing the Mandelbrot set as well as a few other fractals and there's a lot of duplicated code but no code reuse.
One of the functions I am using is below:
/**
* determines whether a pixel lies in the set
* #params x, y - x and y coordinates on R/I axes
* #param c - a complex number
*/
void calculateSet(int x, int y, Complex c) {
Complex z = c.clone();
int n = 0;
for (; n < maxDepth; n++) {
if (z.dis() > 4) { break; }
z = z^2 + c;
}
// some code using n to color the set
}
This follows the Mandelbrot set:
z_(n+1) = z_n^2 + c
But look at the relevant code for the Burning Ship set:
void calculateSet(int x, int y, Complex c) {
Complex z = c.clone();
int n = 0;
for (; n < maxDepth; n++) {
if (z.dis() > 4) { break; }
z = abs(z)^2 + c; // ***
}
// follows z_(n+1) = abs(z_1)^2 + c
}
All the code save for the starred line is identical. Right now I have separate classes for Mandelbrot, BurningShip, and a few others with the only difference being that one line.
Is there a way to define this expression and pass to a generalized Set class?
Some pseudocode:
class Set {
// ...
Set(Type expression) {
// ...
// x, y, c initialized
// ...
calculateSet(x, y, c, expression);
}
void calculateSet(int x, int y, Complex c, Type e) {
Complex z = c.clone();
int n = 0;
for (; n < maxDepth; n++) {
if (z.dis() > 4) { break; }
z = e;
}
}
};
And I can just use Set to describe any kind of set I wish?
Set mandelbrot = Set(Type("z^2 + c"));
Set burningship = Set(Type("abs(z)^2 + c"));
// etc
I could use if/else statements to have just one class, but it's not generalized.
Since you're limited to C++03, you can use a function pointer relatively painlessly.
Complex mandlebrotCompute(Complex z, Complex c) {
return z*z + c;
}
void calculateSet(int x, int y, Complex c, Complex (*func)(Complex, Complex)) {
Complex z = c.clone();
int n = 0;
for (; n < maxDepth; n++) {
if (z.dis() > 4) { break; }
z = func(z, c);
}
}
It is used like the following:
Complex foo;
calculateSet(1, 2, foo, mandlebrotCompute);
It might help make the code cleaner to use a typedef for the function pointer.
You can make a template, with the function as template argument.
I believe this is the method that provides the most inlining opportunities.
typedef Complex (*Function)(const Complex&, const Complex&);
template<Function fn>
class Set
{
// ...
void calculateSet(int x, int y, Complex c) {
Complex z = c;
int n = 0;
for (; n < maxDepth; n++) {
if (z.dis() > 4) { break; }
z = fn(z, c)
}
// some code...
}
}
Complex mandelbrot_fn(const Complex& z, const Complex& c)
{
return z^2 + c;
}
Complex burning_fn(const Complex& z, const Complex& c)
{
return abs(z)^2 + c;
}
Set<mandelbrot_fn> mandelbrot;
Set<burning_fn> burning_ship;
That is what lambdas are for I guess.
template<typename Lam>
class Set
{
private:
Lam lam;
public:
Set (Lam&& lam) : lam(lam) {}
void calculateSet(int x, int y, Complex c)
{
Complex z = c.clone();
int n = 0;
for (; n < maxDepth; n++) {
if (z.dis() > 4) { break; }
z = lam(z, c);
}
}
};
You can use this class like this:
auto mandelbrot = Set([](Complex z, Complex c) -> Complex {
return (z*z) + c;
});
auto burningShip = Set([](Complex z, Complex c) -> Complex {
return abs((z*z)) + c;
});
mandelbrot.calculateSet(...);
burningShip .calculateSet(...);
Is there any way I can modify the poisson-disk points generator finding here.I need to generate new poisson points using the coordinates of points in the textfile.txt to improve the distribution. below the c++ code of poisson-disk sampling in a unit square.
poissonGenerator.h:
#include <vector>
#include <random>
#include <stdint.h>
#include <time.h>
namespace PoissoGenerator
{
class DefaultPRNG
{
public:
DefaultPRNG()
: m_Gen(std::random_device()())
, m_Dis(0.0f, 1.f)
{
// prepare PRNG
m_Gen.seed(time(nullptr));
}
explicit DefaultPRNG(unsigned short seed)
: m_Gen(seed)
, m_Dis(0.0f, 1.f)
{
}
double RandomDouble()
{
return static_cast <double>(m_Dis(m_Gen));
}
int RandomInt(int Max)
{
std::uniform_int_distribution<> DisInt(0, Max);
return DisInt(m_Gen);
}
private:
std::mt19937 m_Gen;
std::uniform_real_distribution<double> m_Dis;
};
struct sPoint
{
sPoint()
: x(0)
, y(0)
, m_valid(false){}
sPoint(double X, double Y)
: x(X)
, y(Y)
, m_valid(true){}
double x;
double y;
bool m_valid;
//
bool IsInRectangle() const
{
return x >= 0 && y >= 0 && x <= 1 && y <= 1;
}
//
bool IsInCircle() const
{
double fx = x - 0.5f;
double fy = y - 0.5f;
return (fx*fx + fy*fy) <= 0.25f;
}
};
struct sGridPoint
{
sGridPoint(int X, int Y)
: x(X)
, y(Y)
{}
int x;
int y;
};
double GetDistance(const sPoint& P1, const sPoint& P2)
{
return sqrt((P1.x - P2.x)*(P1.x - P2.x) + (P1.y - P2.y)*(P1.y - P2.y));
}
sGridPoint ImageToGrid(const sPoint& P, double CellSize)
{
return sGridPoint((int)(P.x / CellSize), (int)(P.y / CellSize));
}
struct sGrid
{
sGrid(int W, int H, double CellSize)
: m_W(W)
, m_H(H)
, m_CellSize(CellSize)
{
m_Grid.resize((m_H));
for (auto i = m_Grid.begin(); i != m_Grid.end(); i++){ i->resize(m_W); }
}
void Insert(const sPoint& P)
{
sGridPoint G = ImageToGrid(P, m_CellSize);
m_Grid[G.x][G.y] = P;
}
bool IsInNeighbourhood(sPoint Point, double MinDist, double CellSize)
{
sGridPoint G = ImageToGrid(Point, CellSize);
//number of adjacent cell to look for neighbour points
const int D = 5;
// Scan the neighbourhood of the Point in the grid
for (int i = G.x - D; i < G.x + D; i++)
{
for (int j = G.y - D; j < G.y + D; j++)
{
if (i >= 0 && i < m_W && j >= 0 && j < m_H)
{
sPoint P = m_Grid[i][j];
if (P.m_valid && GetDistance(P, Point) < MinDist){ return true; }
}
}
}
return false;
}
private:
int m_H;
int m_W;
double m_CellSize;
std::vector< std::vector< sPoint> > m_Grid;
};
template <typename PRNG>
sPoint PopRandom(std::vector<sPoint>& Points, PRNG& Generator)
{
const int Idx = Generator.RandomInt(Points.size() - 1);
const sPoint P = Points[Idx];
Points.erase(Points.begin() + Idx);
return P;
}
template <typename PRNG>
sPoint GenerateRandomPointAround(const sPoint& P, double MinDist, PRNG& Generator)
{
// Start with non-uniform distribution
double R1 = Generator.RandomDouble();
double R2 = Generator.RandomDouble();
// radius should be between MinDist and 2 * MinDist
double Radius = MinDist * (R1 + 1.0f);
//random angle
double Angle = 2 * 3.141592653589f * R2;
// the new point is generated around the point (x, y)
double X = P.x + Radius * cos(Angle);
double Y = P.y + Radius * sin(Angle);
return sPoint(X, Y);
}
// Return a vector of generated points
// NewPointsCount - refer to bridson-siggraph07-poissondisk.pdf
// for details (the value 'k')
// Circle - 'true' to fill a circle, 'false' to fill a rectangle
// MinDist - minimal distance estimator, use negative value for default
template <typename PRNG = DefaultPRNG>
std::vector<sPoint> GeneratePoissonPoints(rsize_t NumPoints, PRNG& Generator, int NewPointsCount = 30,
bool Circle = true, double MinDist = -1.0f)
{
if (MinDist < 0.0f)
{
MinDist = sqrt(double(NumPoints)) / double(NumPoints);
}
std::vector <sPoint> SamplePoints;
std::vector <sPoint> ProcessList;
// create the grid
double CellSize = MinDist / sqrt(2.0f);
int GridW = (int)(ceil)(1.0f / CellSize);
int GridH = (int)(ceil)(1.0f / CellSize);
sGrid Grid(GridW, GridH, CellSize);
sPoint FirstPoint;
do
{
FirstPoint = sPoint(Generator.RandomDouble(), Generator.RandomDouble());
} while (!(Circle ? FirstPoint.IsInCircle() : FirstPoint.IsInRectangle()));
//Update containers
ProcessList.push_back(FirstPoint);
SamplePoints.push_back(FirstPoint);
Grid.Insert(FirstPoint);
// generate new points for each point in the queue
while (!ProcessList.empty() && SamplePoints.size() < NumPoints)
{
#if POISSON_PROGRESS_INDICATOR
// a progress indicator, kind of
if (SamplePoints.size() % 100 == 0) std::cout << ".";
#endif // POISSON_PROGRESS_INDICATOR
sPoint Point = PopRandom<PRNG>(ProcessList, Generator);
for (int i = 0; i < NewPointsCount; i++)
{
sPoint NewPoint = GenerateRandomPointAround(Point, MinDist, Generator);
bool Fits = Circle ? NewPoint.IsInCircle() : NewPoint.IsInRectangle();
if (Fits && !Grid.IsInNeighbourhood(NewPoint, MinDist, CellSize))
{
ProcessList.push_back(NewPoint);
SamplePoints.push_back(NewPoint);
Grid.Insert(NewPoint);
continue;
}
}
}
#if POISSON_PROGRESS_INDICATOR
std::cout << std::endl << std::endl;
#endif // POISSON_PROGRESS_INDICATOR
return SamplePoints;
}
}
and the main program is:
poisson.cpp
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <fstream>
#include <memory.h>
#define POISSON_PROGRESS_INDICATOR 1
#include "PoissonGenerator.h"
const int NumPoints = 20000; // minimal number of points to generate
int main()
{
PoissonGenerator::DefaultPRNG PRNG;
const auto Points =
PoissonGenerator::GeneratePoissonPoints(NumPoints,PRNG);
std::ofstream File("Poisson.txt", std::ios::out);
File << "NumPoints = " << Points.size() << std::endl;
for (const auto& p : Points)
{
File << " " << p.x << " " << p.y << std::endl;
}
system("PAUSE");
return 0;
}
Suppose you have a point in the space [0,1] x [0,1], in the form of a std::pair<double, double>, but desire points in the space [x,y] x [w,z].
The function object
struct ProjectTo {
double x, y, w, z;
std::pair<double, double> operator(std::pair<double, double> in)
{
return std::make_pair(in.first * (y - x) + x, in.second * (z - w) + w);
}
};
will transform such an input point into the desired output point.
Suppose further you have a std::vector<std::pair<double, double>> points, all drawn from the input distribution.
std::copy(points.begin(), points.end(), points.begin(), ProjectTo{ x, y, w, z });
Now you have a vector of points in the output space.
I was writing this code to find the minimum distance between 2 points.The code I have written gives me the minimum distance correctly but does not give the correct coordinates from which the minimum distance is computed.Kindly help me identify the problem according to me this is the correct approach to print the points as well along with the minimum distance.
#include<bits/stdc++.h>
#define FOR(i,N) for(int i=0;i<(N);i++)
#define rep(i,a,n) for(int i=(a);i<(n);i++)
using namespace std;
struct point {
int x;
int y;
};
typedef struct point point;
void printarr(point arr[], int n) {for(int i = 0; i < n; i++) cout <<
arr[i].x << " " << arr[i].y << endl; cout << endl;
bool comparex(const point& X, const point& Y) { return X.x < Y.x; }
bool comparey(const point& X, const point& Y) { return X.y < Y.y; }
float getdis(point X, point Y) { return sqrt((X.x - Y.x)*(X.x - Y.x) + (X.y
- Y.y)*(X.y - Y.y)); }
float brutedis(point P[], int n, point A[]) {
float d = INT_MAX;
float temp;
FOR(i, n) {
rep(j, i+1, n) {
temp = getdis(P[i],P[j]);
if(temp < d) {
d = temp;
A[0].x = P[i].x; A[0].y = P[i].y;
A[1].x = P[j].x ; A[1].y = P[j].y;
}
}
}
return d;
}
float stripdis(point P[], int n, float d, point A[]) {
float temp = d;
float dis;
sort(P, P + n, comparey);
FOR(i, n) {
rep(j,i+1,n) {
if(abs(P[j].y - P[i].y) < d) {
dis = getdis(P[j], P[i]);
if(dis < temp) {
temp = dis;
A[0].x = P[i].x; A[0].y = P[i].y;
A[1].x = P[j].x ; A[1].y = P[j].y;
}
}
}
}
return temp;
}
float solve(point P[], int n, point A[]) {
if(n <= 3) return brutedis(P, n, A);
int mid = n/2;
point M = P[mid];
float d = min(solve(P, mid, A), solve(P+mid, n-mid, A));
point strip[n];
int j = 0;
int i = 0;
while(i < n) {
if(abs(P[i].x - M.x) < d) strip[j++] = P[i];
i++;
}
return min(d, stripdis(strip, j, d, A));
}
int main() {
point P[] = {{0, 0}, {-4,1}, {-7, -2}, {4, 5}, {1, 1}};
int n = sizeof(P) / sizeof(P[0]);
sort(P, P+n, comparex);
point A[2];
cout << "Minimum Distance = " << solve(P, n, A) << "\n";
printarr(A, 2);
//printarr(P, n);
return 0;
}
To the extent I can follow your badly formatted code, brutedis unconditionally modifies A[] and it gets called again after you have found the right answer (but don't know you found the right answer).
So if the first call were best in min(solve(P, mid, A), solve(P+mid, n-mid, A)); the second could still call brutedis and destroy A[]
You call solve twice, both giving it A as the parameter. Each of these calls always overwrite A, but only one returns the correct answer. And they both call brutedis that also always overwrites A.
The easiest way to fix this is to introduce an additional parameter to all these functions, that would contain the minimal distance found so far, the same way you did with stripdis.
float solve(point P[], int n, float d, point A[]) {
if(n <= 3) return brutedis(P, n, d, A);
...
d = solve(P, mid, d, A);
d = solve(P+mid, n-mid, d, A);
d = stripdis(strip, j, d, A));
...
float brutedis(point P[], int n, float d, point A[])
{
// float d = INT_MAX -- Not needed
Thus A will only be overeritten if the distance between the new pair of points is globally minimal so far.
No need to call min as each function already keeps the minimum of d and the distance it finds.
That is because after getting the correct coordinates in "A" array, you are again updating that. just look for the below statement in your code:
float d = min(solve(P, mid, A), solve(P+mid, n-mid, A));
this will give correct minimum distance but not correct coordinates. Just think about it, if your first call to solve, in the above statement has the minimum distance coordinates, then your second call is going to modify the coordinates in A[]. take a pen and paper and try to solve for the coordinates you have, it'll give you better understanding.
This question already has answers here:
How do I use arrays in C++?
(5 answers)
Why aren't variable-length arrays part of the C++ standard?
(10 answers)
Closed 8 years ago.
I was implementing a version of the closest pair problem using the algorithmic technique of divide and conquer. However, when I try and compile my code, in several spots I get the error "Expected constant expression". I am aware that arrays are supposed to have constant values in them, but I'm not quite sure what's wrong in this case. I tried to research solutions and many people suggested using malloc, but it seems to be generally frowned upon. Would someone be able to help me fix this? Below is the code with the errors commented hopefully well enough that you can see them. Thank you so much in advance for your help, I really appreciate it!
#include <iostream>
#include <float.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
//A struct to represent the points on an x,y plane
struct Point{
int x, y;
};
//function to sort x coordinates
int compareX(const void* a, const void* b){
Point *p1 = (Point *)a, *p2 = (Point *)b;
return (p1->x - p2->x);
}
//function to sort y coordinates
int compareY(const void* a, const void* b){
Point *p1 = (Point *)a, *p2 = (Point *)b;
return (p1->y - p2->y);
}
//function to find the distance between any two points
float dist(Point p1, Point p2){
return sqrt( (float)(p1.x - p2.x) * (p1.x - p2.x) +
(float)(p1.y - p2.y) * (p1.y - p2.y)
);
}
//utility function to find the minimum of any two float values
float min(float x, float y){
if(x < y)
return x;
else
return y;
}
//brute force function to find the closest of two points
float bruteforce(Point P[], int n){
float min = FLT_MAX;
for(int i=0; i<n; i++){
for(int j = i+1; j < n; j++)
if(dist(P[i], P[j]) < min)
min = dist(P[i], P[j]);
}
return min;
}
//function to find the distance between the closest points of a given size
float closestArray(Point array1[], int size, float d){
float min = d; //initialize the minimum distance as d
//go through the points 1 by 1 and try the next until the difference is smaller than d
for (int i=0; i < size; i++)
for (int j= i + 1; j< size && (array1[i].y - array1[i].y) < min; j++)
if(dist(array1[i],array1[j]) < min)
min = dist(array1[i], array1[j]);
return min;
}
float closestPoint(Point Px[], Point Py[], int n){
if(n <= 3)
return bruteforce(Px, n);
//find the middle point
int mid = n/2;
Point midPoint = Px[mid];
//divide the points along the vertical line
Point Pyleft[mid + 1]; //left of vertical line <--- ERROR
Point Pyright[n-mid-1]; //right of vertical line <--- ERROR
int li = 0; //index of left subarray
int ri = 0; //index of right subarray
for ( int i =0; i<n; i++){
if (Py[i].x <= midPoint.x)
Pyleft[li++] = Py[i];
else
Pyright[ri++] = Py[i];
}
//calculate the smallest ditance dl on the left middle point and dr on the right side
float dl = closestPoint(Px, Pyleft, mid);
float dr = closestPoint(Px + mid, Pyright, n-mid);
//find the smaller of the two distances
float d = min(dl, dr);
//build another array Q that contains points closer than d to the line passing through the middle
Point q[n]; // <--- ERROR
int j = 0;
for (int i = 0; i<n; i++)
if(abs(Py[i].x - midPoint.x) < d)
q[j] = Py[i], j++;
return min(d, closestArray(q, j, d) );
}
//function that finds the smallerst distance
float closest(Point P[], int n){
Point Px[n]; //<--- ERROR
Point Py[n]; //<---ERROR
for(int i=0; i < n; i++)
{
Px[i] = P[i];
Py[i] = P[i];
}
qsort(Px, n, sizeof(Point), compareX);
qsort(Py, n, sizeof(Point), compareY);
//recursive function to find smallest distance
return closestPoint(Px, Py, n);
}
int main()
{
Point P[] = {{2, 3}, {12, 30}, {40, 50}, {5, 1}, {12, 10}, {3, 4}};
int n = sizeof(P) / sizeof(P[0]);
cout << "The smallest distance is " << closest(P, n);
return 0;
}