How to modify this code so the program can take user input instead of predefined input:
the code is to check if two line are intersecting or not in this code the values of the points are given but i want the program to ask the values at the run time.
struct point
{
lli x, y;
};
int orientation(point p1, point p2, point p3)
{
int val = (p2.y - p1.y) * (p3.x - p2.x) -
(p2.x -p1.x) * (p3.y -p2.y);
if (val == 0) return 0;
return (val > 0)? 1: 2;
}
bool validprojection(int a, int b, int c, int d)
{
if (a > b)
swap(a,b);
if (c > d)
swap(c, d);
return max(a, c) <= min(b, d);
}
bool doIntersect(point a, point b, point c, point d)
{
int o1 = orientation(a, b, c);
int o2 = orientation(a, b, d);
int o3 = orientation(c, d, a);
int o4 = orientation(c, d, b);
if(o1 != o2 && o3 != o4)
return true;
if (o1 == 0 && o4 == 0)
{
if(validprojection(a.x, b.x, c.x, d.x) && validprojection(a.y, b.y, c.y, d.y))
return true;
}
return false;
}
predefined input:
how can i modify this part so it will ask user to input the values of point
int main()
{
cout<<"To find the intersection point of two line segment";
point p1 = {1, 1}, p2 = {10, 1}, p3 = {1, 2}, p4 = {10, 2};
doIntersect(p1, p2, p3, p4)? cout << "yes\n": cout<< "No\n";
p1 = {10, 0}, p2 = {0, 10}, p3 = {0, 0}, p4 = {10, 10};
doIntersect(p1, p2, p3, p4)? cout << "yes\n": cout<< "No\n";
return 0;
Code
#include <iostream>
#include <string>
#include <sstream>
std::ostream &operator<<(std::ostream &os, Point &p) {
return os << p.x << ',' << p.y;
}
int main() {
Point points[2][2];
std::string line;
while (true) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
std::cout << "Line " << i + 1<< ", Point " << j + 1 << " (x,y): "; // Prints: "Line i, Point j (x,y): "
std::getline(std::cin, line);
if (line.size() == 0) {
goto end;
}
std::stringstream ss(line);
ss >> points[i][j].x;
ss.ignore(1, ',');
ss >> points[i][j].y;
line.clear();
}
}
bool intersect = doIntersect(points[0][0], points[0][1], points[1][0], points[1][1]);
std::cout << "The lines 1 [(" << points[0][0] << "), (" << points[0][1] << ")] and 2 " << "[(" << points[1][0] << "), (" << points[1][1] << ")] " << (intersect ? "do" : "don't") << "intersect\n" << std::endl; // Double new line intended, Prints: "The lines 1 [(x,y), (x,y)] and 2 [(x,y), (x,y)] do/don't intersect"
}
end: return 0;
}
Explaination
std::ostream& operator<<.....: Make Point ostreamable (usable with cout).
Point points[2][2]: a 2 x 2 point array (2 lines, 2 points each)
string line: a string for user input
while (true): repeat the cycle of "Get input, Check if lines intersect" (remove it if you want the program to exit after completing the cycle once)
The cycle:
A. Get input:
2 nested loops, one for lines, the other for points
Print Line i, Point j (x,y):
std::getline: Read till the user presses enter
If the input is empty, terminate the program
Read a number into point.x, ignore the ',' then read another number into point.y
B. Check if lines intersect
Use the doIntersect and save the result into a variable
Print: The lines 1 [(x,y), (x,y)] and 2 [(x,y), (x,y)] do/don't intersect where (do/don't) depends on whether the result is true (lines intersect) or not
how can i modify this part so it will ask user to input the values of point
You can do this by using operator overloading. In particular you can overload operator>> as shown below. The below shown program asks for input from user and use those point entered by the user to check if they intersect or not.
#include <iostream>
using namespace std;
struct point
{
int x, y;
//default constructor
point(): x(0), y(0)
{
}
//overload operator>>
friend std::istream &operator>>(std::istream &is, point& inputPoint);
};
int orientation(point p1, point p2, point p3)
{
int val = (p2.y - p1.y) * (p3.x - p2.x) -
(p2.x -p1.x) * (p3.y -p2.y);
if (val == 0) return 0;
return (val > 0)? 1: 2;
}
bool validprojection(int a, int b, int c, int d)
{
if (a > b)
swap(a,b);
if (c > d)
swap(c, d);
return max(a, c) <= min(b, d);
}
bool doIntersect(point a, point b, point c, point d)
{
int o1 = orientation(a, b, c);
int o2 = orientation(a, b, d);
int o3 = orientation(c, d, a);
int o4 = orientation(c, d, b);
if(o1 != o2 && o3 != o4)
return true;
if (o1 == 0 && o4 == 0)
{
if(validprojection(a.x, b.x, c.x, d.x) && validprojection(a.y, b.y, c.y, d.y))
return true;
}
return false;
}
//define overloaded operator>>
std::istream &operator>>(std::istream &is, point& inputPoint)
{
std::cout<<"Enter x value: ";
std::cin >> inputPoint.x ;
std::cout<<"Enter y value: ";
std::cin >> inputPoint.y;
//check if input succeeded
if(cin)
{
//do something if needed
;
}
else
{
inputPoint = point();//otherwise leave the object in DEFAULT STATE
}
return is;
}
int main()
{
cout<<"To find the intersection point of two line segment"<<std::endl;
//TAKE INPUT(x and y values) FROM USER
point p1;
std::cin >> p1;
point p2;
std::cin >> p2;
point p3;
std::cin >> p3;
point p4;
std::cin >> p4;
//check if intersect
doIntersect(p1, p2, p3, p4)? cout << "yes\n": cout<< "No\n";
//AGAIN TAKE INPUT FROM USER
std::cin >> p1;
std::cin >> p2;
std::cin >> p3;
std::cin >> p4;
doIntersect(p1, p2, p3, p4)? cout << "yes\n": cout<< "No\n";
return 0;
}
The output of the above program can be seen here.
Related
I'm trying to solve this problem using the slicing technic.
But I just passed the first two test cases in this gym (Problem A)
2017-2018 ACM-ICPC East Central North America Regional Contest (ECNA 2017)
The whole step in my code looks like this:
calculate the total area using vector cross when inputting the polygon information.
find all the endpoints and intersection points, and record x value of them.
for each slice (sort x list and for each interval) find the lines from every polygon which crosses this interval and store this smaller segment.
sort segments.
for each trapezoid or triangle, calculate the area if this area is covered by some polygon.
sum them all to find the cover area.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<typename T> using p = pair<T, T>;
template<typename T> using vec = vector<T>;
template<typename T> using deq = deque<T>;
// #define dbg
#define yccc ios_base::sync_with_stdio(false), cin.tie(0)
#define al(a) a.begin(),a.end()
#define F first
#define S second
#define eb emplace_back
const int INF = 0x3f3f3f3f;
const ll llINF = 1e18;
const int MOD = 1e9+7;
const double eps = 1e-9;
const double PI = acos(-1);
double fcmp(double a, double b = 0, double eps = 1e-9) {
if (fabs(a-b) < eps) return 0;
return a - b;
}
template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& a) { in >> a.F >> a.S; return in; }
template<typename T1, typename T2>
ostream& operator<<(ostream& out, pair<T1, T2> a) { out << a.F << ' ' << a.S; return out; }
struct Point {
double x, y;
Point() {}
Point(double x, double y) : x(x), y(y) {}
Point operator+(const Point& src) {
return Point(src.x + x, src.y + y);
}
Point operator-(const Point& src) {
return Point(x - src.x, y - src.y);
}
Point operator*(double src) {
return Point(x * src, y * src);
}
//* vector cross.
double operator^(Point src) {
return x * src.y - y * src.x;
}
};
struct Line {
Point sp, ep;
Line() {}
Line(Point sp, Point ep) : sp(sp), ep(ep) {}
//* check if two segment intersect.
bool is_intersect(Line src) {
if (fcmp(ori(src.sp) * ori(src.ep)) < 0 and fcmp(src.ori(sp) * src.ori(ep)) < 0) {
double t = ((src.ep - src.sp) ^ (sp - src.sp)) / ((ep - sp) ^ (src.ep - src.sp));
return fcmp(t) >= 0 and fcmp(t, 1) <= 0;
}
return false;
}
//* if two segment intersect, find the intersection point.
Point intersect(Line src) {
double t = ((src.ep - src.sp) ^ (sp - src.sp)) / ((ep - sp) ^ (src.ep - src.sp));
return sp + (ep - sp) * t;
}
double ori(Point src) {
return (ep - sp) ^ (src - sp);
}
bool operator<(Line src) const {
if (fcmp(sp.y, src.sp.y) != 0)
return sp.y < src.sp.y;
return ep.y < src.ep.y;
}
};
int next(int i, int n) {
return (i + 1) % n;
}
int main()
{
yccc;
int n;
cin >> n;
//* the point list and the line list of polygons.
vec<vec<Point>> p_list(n);
vec<vec<Line>> l_list(n);
//* x's set for all endpoints and intersection points
vec<double> x_list;
//* initializing point list and line list
double total = 0, cover = 0;
for (int i = 0; i < n; i++) {
int m;
cin >> m;
p_list[i].resize(m);
for (auto &k : p_list[i]) {
cin >> k.x >> k.y;
x_list.eb(k.x);
}
l_list[i].resize(m);
for (int k = 0; k < m; k++) {
l_list[i][k].sp = p_list[i][k];
l_list[i][k].ep = p_list[i][next(k, m)];
}
//* calculate the polygon area.
double tmp = 0;
for (int k = 0; k < m; k++) {
tmp += l_list[i][k].sp.x * l_list[i][k].ep.y - l_list[i][k].sp.y * l_list[i][k].ep.x;
}
total += abs(tmp);
}
//* find all intersection points
for (int i = 0; i < n; i++)
for (int k = i+1; k < n; k++) {
for (auto li : l_list[i])
for (auto lk : l_list[k])
if (li.is_intersect(lk)) {
x_list.eb(li.intersect(lk).x);
}
}
sort(al(x_list));
auto same = [](double a, double b) -> bool {
return fcmp(a, b) == 0;
};
x_list.resize(unique(al(x_list), same) - x_list.begin());
//* for each slicing, calculate the cover area.
for (int i = 0; i < x_list.size() - 1; i++) {
vec<pair<Line, int>> seg;
for (int k = 0; k < n; k++) {
for (auto line : l_list[k]) {
//* check if line crosses this slicing
if (fcmp(x_list[i], min(line.sp.x, line.ep.x)) >= 0 and fcmp(max(line.sp.x, line.ep.x), x_list[i+1]) >= 0) {
Point sub = line.ep - line.sp;
double t_sp = (x_list[i] - line.sp.x) / sub.x, t_ep = (x_list[i+1] - line.sp.x) / sub.x;
seg.eb(Line(Point(x_list[i], line.sp.y + sub.y * t_sp), Point(x_list[i+1], line.sp.y + sub.y * t_ep)), k);
}
}
}
//* sort this slicing
sort(al(seg));
deq<bool> inside(n);
int count = 0;
Line prev;
// cout << x_list[i] << ' ' << x_list[i+1] << endl;
//* calculate cover area in this slicing.
for (int k = 0; k < seg.size(); k++) {
if (count)
cover += ((seg[k].F.sp.y - prev.sp.y) + (seg[k].F.ep.y - prev.ep.y)) * (x_list[i+1] - x_list[i]);
prev = seg[k].F;
// cout << seg[k].S << ": (" << seg[k].F.sp.x << ", " << seg[k].F.sp.y << "), (" << seg[k].F.ep.x << ", " << seg[k].F.ep.y << ")" << endl;
inside[k] = !inside[k];
count += (inside[k] ? 1 : -1);
}
}
//* answer
cout << total / 2 << ' ' << cover / 2;
}
I can't not figure out which part I made a mistake :(
Firstly, I would like to apologise for my bad English.
when I submit the code below to DomJudge I got TimeLimit ERROR.
I can't think of ways to solve this question albeit I searched all over the internet and still couldn't find a solution.
Can someone give me a hint?
Question:
Here are N linear function fi(x) = aix + bi, where 1 ≤ i ≤ N。Define F(x) = maxifi(x). Please compute
the following equation for the input c[i], where 1 ≤ i ≤ m.
**Σ(i=1 to m) F(c[i])**
For example, given 4 linear function as follows. f1(x) = –x, f2 = x, f3 = –2x – 3, f4 = 2x – 3. And the
input is c[1] = 4, c[2] = –5, c[3] = –1, c[4] = 0, c[5] = 2. We have F(c[1]) = 5, F(c[2]) = 7, F(c[3])
= 1, F(c[4]) = 0, F(c[5]) = 2. Then,
**Σ(i=1 to 5)𝐹(𝑐[𝑖])
= 𝐹(𝑐[1]) + 𝐹(𝑐[2]) + 𝐹(𝑐[3]) + 𝐹(𝑐[4]) + 𝐹([5]) = 5 + 7 + 1 + 0 + 2 = 15**
Input Format:
The first line contains two positive integers N and m. The next N lines will contain two integers ai
and bi, and the last line will contain m integers c[1], c[2], c[3],…, c[m]. Each element separated by
a space.
Output Format:
Please output the value of the above function.
question image:https://i.stack.imgur.com/6HeaA.png
Sample Input:
4 5
-1 0
1 0
-2 -3
2 -3
4 -5 -1 0 2
Sample Output:
15
My Program
#include <iostream>
#include <vector>
struct L
{
int a;
int b;
};
int main()
{
int n{ 0 };
int m{ 0 };
while (std::cin >> n >> m)
{
//input
std::vector<L> arrL(n);
for (int iii{ 0 }; iii < n; ++iii)
{
std::cin >> arrL[iii].a >> arrL[iii].b;
}
//find max in every linear polymore
int answer{ 0 };
for (int iii{ 0 }; iii < m; ++iii)
{
int input{ 0 };
int max{ 0 };
std::cin >> input;
max = arrL[0].a * input + arrL[0].b;
for (int jjj{ 1 }; jjj < n; ++jjj)
{
int tmp{arrL[jjj].a * input + arrL[jjj].b };
if (tmp > max)max = tmp;
}
answer += max;
}
//output
std::cout << answer << '\n';
}
return 0;
}
Your solution is O(n*m).
A faster solution is obtained by iteratively determinating the "dominating segments", and the correspong crossing points, called "anchors" in the following.
Each anchor is linked to two segments, on its left and on its right.
The first step consists in sorting the lines according to the a values, and then adding each new line iteratively.
When adding line i, we know that this line is dominant for large input values, and must be added (even if it will be removed in the following steps).
We calculate the intersection of this line with the previous added line:
if the intersection value is higher than the rightmost anchor, then we add a new anchor corresponding to this new line
if the intersection value is lower than the rightmost anchor, then we know that we have to suppress this last anchor value. In this case, we iterate the process, calculating now the intersection with the right segment of the previous anchor.
Complexity is dominated by sorting: O(nlogn + mlogm). The anchor determination process is O(n).
When we have the anchors, then determining the rigtht segment for each input x value is O(n+ m). If needed, this last value could be further reduced with a binary search (not implemented).
Compared to first version of the code, a few errors have been corrected. These errors were concerning some corner cases, with some identical lines at the extreme left (i.e. lowest values of a). Besides, random sequences have been generated (more than 10^7), for comparaison of the results with those obtained by OP's code. No differences were found. It is likely that if some errors remain, they correspond to other unknown corner cases. The algorithm by itself looks quite valid.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
// lines of equation `y = ax + b`
struct line {
int a;
int b;
friend std::ostream& operator << (std::ostream& os, const line& coef) {
os << "(" << coef.a << ", " << coef.b << ")";
return os;
}
};
struct anchor {
double x;
int segment_left;
int segment_right;
friend std::ostream& operator << (std::ostream& os, const anchor& anc) {
os << "(" << anc.x << ", " << anc.segment_left << ", " << anc.segment_right << ")";
return os;
}
};
// intersection of two lines
double intersect (line& seg1, line& seg2) {
double x;
x = double (seg1.b - seg2.b) / (seg2.a - seg1.a);
return x;
}
long long int max_funct (std::vector<line>& lines, std::vector<int> absc) {
long long int sum = 0;
auto comp = [&] (line& x, line& y) {
if (x.a == y.a) return x.b < y.b;
return x.a < y.a;
};
std::sort (lines.begin(), lines.end(), comp);
std::sort (absc.begin(), absc.end());
// anchors and dominating segments determination
int n = lines.size();
std::vector<anchor> anchors (n+1);
int n_anchor = 1;
int l0 = 0;
while ((l0 < n-1) && (lines[l0].a == lines[l0+1].a)) l0++;
int l1 = l0 + 1;
if (l0 == n-1) {
anchors[0] = {0.0, l0, l0};
} else {
while ((l1 < n-1) && (lines[l1].a == lines[l1+1].a)) l1++;
double x = intersect(lines[l0], lines[l1]);
anchors[0] = {x, l0, l1};
for (int i = l1 + 1; i < n; ++i) {
if ((i != (n-1)) && lines[i].a == lines[i+1].a) continue;
double x = intersect(lines[anchors[n_anchor-1].segment_right], lines[i]);
if (x > anchors[n_anchor-1].x) {
anchors[n_anchor].x = x;
anchors[n_anchor].segment_left = anchors[n_anchor - 1].segment_right;
anchors[n_anchor].segment_right = i;
n_anchor++;
} else {
n_anchor--;
if (n_anchor == 0) {
x = intersect(lines[anchors[0].segment_left], lines[i]);
anchors[0] = {x, anchors[0].segment_left, i};
n_anchor = 1;
} else {
i--;
}
}
}
}
// sum calculation
int j = 0; // segment index (always increasing)
for (int x: absc) {
while (j < n_anchor && anchors[j].x < x) j++;
line seg;
if (j == 0) {
seg = lines[anchors[0].segment_left];
} else {
if (j == n_anchor) {
if (anchors[n_anchor-1].x < x) {
seg = lines[anchors[n_anchor-1].segment_right];
} else {
seg = lines[anchors[n_anchor-1].segment_left];
}
} else {
seg = lines[anchors[j-1].segment_right];
}
}
sum += seg.a * x + seg.b;
}
return sum;
}
int main() {
std::vector<line> lines = {{-1, 0}, {1, 0}, {-2, -3}, {2, -3}};
std::vector<int> x = {4, -5, -1, 0, 2};
long long int sum = max_funct (lines, x);
std::cout << "sum = " << sum << "\n";
lines = {{1,0}, {2, -12}, {3, 1}};
x = {-3, -1, 1, 5};
sum = max_funct (lines, x);
std::cout << "sum = " << sum << "\n";
}
One possible issue is the loss of information when calculating the double x corresponding to line intersections, and therefoe to anchors. Here is a version using Rational to avoid such loss.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
struct Rational {
int p, q;
Rational () {p = 0; q = 1;}
Rational (int x, int y) {
p = x;
q = y;
if (q < 0) {
q -= q;
p -= p;
}
}
Rational (int x) {
p = x;
q = 1;
}
friend std::ostream& operator << (std::ostream& os, const Rational& x) {
os << x.p << "/" << x.q;
return os;
}
friend bool operator< (const Rational& x1, const Rational& x2) {return x1.p*x2.q < x1.q*x2.p;}
friend bool operator> (const Rational& x1, const Rational& x2) {return x2 < x1;}
friend bool operator<= (const Rational& x1, const Rational& x2) {return !(x1 > x2);}
friend bool operator>= (const Rational& x1, const Rational& x2) {return !(x1 < x2);}
friend bool operator== (const Rational& x1, const Rational& x2) {return x1.p*x2.q == x1.q*x2.p;}
friend bool operator!= (const Rational& x1, const Rational& x2) {return !(x1 == x2);}
};
// lines of equation `y = ax + b`
struct line {
int a;
int b;
friend std::ostream& operator << (std::ostream& os, const line& coef) {
os << "(" << coef.a << ", " << coef.b << ")";
return os;
}
};
struct anchor {
Rational x;
int segment_left;
int segment_right;
friend std::ostream& operator << (std::ostream& os, const anchor& anc) {
os << "(" << anc.x << ", " << anc.segment_left << ", " << anc.segment_right << ")";
return os;
}
};
// intersection of two lines
Rational intersect (line& seg1, line& seg2) {
assert (seg2.a != seg1.a);
Rational x = {seg1.b - seg2.b, seg2.a - seg1.a};
return x;
}
long long int max_funct (std::vector<line>& lines, std::vector<int> absc) {
long long int sum = 0;
auto comp = [&] (line& x, line& y) {
if (x.a == y.a) return x.b < y.b;
return x.a < y.a;
};
std::sort (lines.begin(), lines.end(), comp);
std::sort (absc.begin(), absc.end());
// anchors and dominating segments determination
int n = lines.size();
std::vector<anchor> anchors (n+1);
int n_anchor = 1;
int l0 = 0;
while ((l0 < n-1) && (lines[l0].a == lines[l0+1].a)) l0++;
int l1 = l0 + 1;
if (l0 == n-1) {
anchors[0] = {0.0, l0, l0};
} else {
while ((l1 < n-1) && (lines[l1].a == lines[l1+1].a)) l1++;
Rational x = intersect(lines[l0], lines[l1]);
anchors[0] = {x, l0, l1};
for (int i = l1 + 1; i < n; ++i) {
if ((i != (n-1)) && lines[i].a == lines[i+1].a) continue;
Rational x = intersect(lines[anchors[n_anchor-1].segment_right], lines[i]);
if (x > anchors[n_anchor-1].x) {
anchors[n_anchor].x = x;
anchors[n_anchor].segment_left = anchors[n_anchor - 1].segment_right;
anchors[n_anchor].segment_right = i;
n_anchor++;
} else {
n_anchor--;
if (n_anchor == 0) {
x = intersect(lines[anchors[0].segment_left], lines[i]);
anchors[0] = {x, anchors[0].segment_left, i};
n_anchor = 1;
} else {
i--;
}
}
}
}
// sum calculation
int j = 0; // segment index (always increasing)
for (int x: absc) {
while (j < n_anchor && anchors[j].x < x) j++;
line seg;
if (j == 0) {
seg = lines[anchors[0].segment_left];
} else {
if (j == n_anchor) {
if (anchors[n_anchor-1].x < x) {
seg = lines[anchors[n_anchor-1].segment_right];
} else {
seg = lines[anchors[n_anchor-1].segment_left];
}
} else {
seg = lines[anchors[j-1].segment_right];
}
}
sum += seg.a * x + seg.b;
}
return sum;
}
long long int max_funct_op (const std::vector<line> &arrL, const std::vector<int> &x) {
long long int answer = 0;
int n = arrL.size();
int m = x.size();
for (int i = 0; i < m; ++i) {
int input = x[i];
int vmax = arrL[0].a * input + arrL[0].b;
for (int jjj = 1; jjj < n; ++jjj) {
int tmp = arrL[jjj].a * input + arrL[jjj].b;
if (tmp > vmax) vmax = tmp;
}
answer += vmax;
}
return answer;
}
int main() {
long long int sum, sum_op;
std::vector<line> lines = {{-1, 0}, {1, 0}, {-2, -3}, {2, -3}};
std::vector<int> x = {4, -5, -1, 0, 2};
sum_op = max_funct_op (lines, x);
sum = max_funct (lines, x);
std::cout << "sum = " << sum << " sum_op = " << sum_op << "\n";
}
To reduce the time complexity from O(n*m) to something near O(nlogn), we need to order the input data in some way.
The m points where the target function is sampled can be easily sorted using std::sort, which has an O(mlogm) complexity in terms of comparisons.
Then, instead of searching the max between all the lines for each point, we can take advantage of a divide-and-conquer technique.
Some considerations can be made in order to create such an algorithm.
If there are no lines or no sample points, the answer is 0.
If there is only one line, we can evaluate it at each point, accumulating the values and return the result. In case of two lines we could easily accumulate the max between two values. Searching for the intersection and then separating the intervals to accumulate only the correct value may be more complicated, with multiple corner cases and overflow issues.
A recursive function accepting a list of lines, points and two special lines left and right, may start by calculating the middle point in the set of points. Then it could find the two lines (or the only one) that have the greater value at that point. One of them also have the greatest slope between all the ones passing for that maximum point, that would be the top "right". The other one, the top "left" (which may be the same one), have the least slope.
We can partition all the remaining lines in three sets.
All the lines having a greater slope than the "top right" one (but lower intercept). Those are the ones that we need to evaluate the sum for the subset of points at the right of the middle point.
All the lines having a lower slope than the "top left" one (but lower intercept). Those are the ones that we need to evaluate the sum for the subset of points at the left of the middle point.
The remaining lines, that won't partecipate anymore and can be removed. Note this includes both "top right" and "top left".
Having splitted both the points and the lines, we can recurively call the same function passing those subsets, along with the previous left line and "top left" as left and right to the left, and the "top right" line with the previous right as left and right to the right.
The return value of this function is the sum of the value at the middle point plus the return values of the two recursive calls.
To start the procedure, we don't need to evaluate the correct left and right at the extreme points, we can use an helper function as entry point which sorts the points and calls the recursive function passing all the lines, the points and two dummy values (the lowest possible line, y = 0 + std::numeric_limits<T>::min()).
The following is a possible implementation:
#include <algorithm>
#include <iostream>
#include <vector>
#include <numeric>
#include <limits>
struct Line
{
using value_type = long;
using result_type = long long;
value_type slope;
value_type intercept;
auto operator() (value_type x) const noexcept {
return static_cast<result_type>(x) * slope + intercept;
}
static constexpr Line min() noexcept {
return { 0, std::numeric_limits<value_type>::min()};
}
};
auto result_less_at(Line::value_type x)
{
return [x] (Line const& a, Line const& b) { return a(x) < b(x); };
}
auto slope_less_than(Line::value_type slope)
{
return [slope] (Line const& line) { return line.slope < slope; };
}
auto slope_greater_than(Line::value_type slope)
{
return [slope] (Line const& line) { return slope < line.slope; };
}
auto accumulate_results(Line const& line)
{
return [line] (Line::result_type acc, Line::value_type x) {
return acc + line(x);
};
}
struct find_max_lines_result_t
{
Line::result_type y_max;
Line left, right;
};
template< class LineIt, class XType >
auto find_max_lines( LineIt first_line, LineIt last_line
, Line left, Line right
, XType x )
{
auto result{ [left, right] (const auto max_left, const auto max_right)
-> find_max_lines_result_t {
if ( max_left < max_right )
return { max_right, right, right };
else if ( max_right < max_left )
return { max_left, left, left };
else
return { max_left, left, right };
}(left(x), right(x))
};
std::for_each( first_line, last_line
, [x, &result] (Line const& line) mutable {
auto const y{ line(x) };
if ( y == result.y_max ) {
if ( result.right.slope < line.slope )
result.right = line;
if ( line.slope < result.left.slope )
result.left = line;
}
else if ( result.y_max < y ) {
result = {y, line, line};
}
} );
return result;
}
template< class SampleIt >
auto sum_left_right_values( SampleIt const first_x, SampleIt const last_x
, Line const left, Line const right )
{
return std::accumulate( first_x, last_x, Line::result_type{},
[left, right] (Line::result_type acc, Line::value_type x) {
return acc + std::max(left(x), right(x)); } );
}
template< class LineIt, class XType >
auto find_max_result( LineIt const first_line, LineIt const last_line
, Line const left, Line const right
, XType const x )
{
auto const y_max{ std::max(left(x), right(x)) };
LineIt const max_line{ std::max_element(first_line, last_line, result_less_at(x)) };
return max_line == last_line ? y_max : std::max(y_max, (*max_line)(x));
}
template <class LineIt, class SampleIt>
auto sum_lines_max_impl( LineIt const first_line, LineIt const last_line,
SampleIt const first_x, SampleIt const last_x,
Line const left, Line const right )
{
if ( first_x == last_x ) {
return Line::result_type{};
}
if ( first_x + 1 == last_x ) {
return find_max_result(first_line, last_line, left, right, *first_x);
}
if ( first_line == last_line ) {
return sum_left_right_values(first_x, last_x, left, right);
}
auto const mid_x{ first_x + (last_x - first_x - 1) / 2 };
auto const top{ find_max_lines(first_line, last_line, left, right, *mid_x) };
auto const right_begin{ std::partition( first_line, last_line
, slope_less_than(top.left.slope) ) };
auto const right_end{ std::partition( right_begin, last_line
, slope_greater_than(top.right.slope) ) };
return top.y_max + sum_lines_max_impl( first_line, right_begin
, first_x, mid_x
, left, top.left )
+ sum_lines_max_impl( right_begin, right_end
, mid_x + 1, last_x
, top.right, right );
}
template <class LineIt, class SampleIt>
auto sum_lines_max( LineIt first_line, LineIt last_line
, SampleIt first_sample, SampleIt last_sample )
{
if ( first_line == last_line )
return Line::result_type{};
std::sort(first_sample, last_sample);
return sum_lines_max_impl( first_line, last_line
, first_sample, last_sample
, Line::min(), Line::min() );
}
int main()
{
std::vector<Line> lines{ {-1, 0}, {1, 0}, {-2, -3}, {2, -3} };
std::vector<long> points{ 4, -5, -1, 0, 2 };
std::cout << sum_lines_max( lines.begin(), lines.end()
, points.begin(), points.end() ) << '\n';
}
Testable here.
#include <iostream>
#include <iomanip>
#include <cmath>
#include "lineType.h"
using namespace std;
int main()
{
double x, y;
double a = 1.;
double b = 0.;
double c = 1.;
double d = 2.;
double e = 0.;
double f = 3.;
double g = 0.;
double h = 4.;
double i = -1.;
lineType line1(a, b, c);
lineType line2(d, e, f);
lineType line3(g, h, i);
cout << "Line 1: ";
line1.display();
if (line1.isParallel(line2)) cout << "line1 is parallel to line 2" << endl;
if (line1.isPerp(line3)) cout << "line 1 is perpendicular to line 3" << endl;
if (line2.intersect(line3, x, y))
cout << "The intersection of lines 2 and 3 is at point(" << x << ", " << y << ")" << endl;
else
cout << "Lines 2 and 3 do not intersect." << endl;
return 0;
}
This is the code I am testing and the issue I am getting is c2661 no overloaded function takes 3 arguments
My Header file is:
#pragma once
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
class lineType
{
private:
double a;
double b;
double c;
public:
void display() const;
bool isParallel(const lineType& line) const;
bool isPerp(const lineType& line) const;
bool intersect(const lineType& line, double& x, double& y);
lineType();
lineType(double a2, double b2, double c2);
~lineType();
};
This is the lineType.cpp file that was wanted
#include "lineType.h"
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
void lineType::display() const
{
cout << a << "x + " << b << "y = " << c << endl;
}
bool lineType::isParallel(const lineType& line) const
{
if (a == 0 && line.a == 0)
return 1;
if (b == 0 && line.b == 0)
return 1;
else if (-a / b == -line.a / line.b)
return 1;
else
return 0;
}
bool lineType::isPerp(const lineType& line) const
{
if (a == 0 && line.b == 0)
return 1;
if (b == 0 && line.a == 0)
return 1;
else if (-a / b == line.b / line.a)
return 1;
else
return 0;
}
bool lineType::intersect(const lineType& line, double& x, double& y)
{
if (a == 0)
x = c / b;
if (line.a == 0)
x = line.c / line.b;
if (b == 0)
y = c / a;
if (line.b == 0)
{
y = line.c / line.a;
}
else
{
x = ((a*line.c) - (c*line.a)) / ((b*line.a) - (a*line.b));
y = ((c*line.b) - (b*line.c)) / ((b*line.a) - (a*line.b));
}
if (a == 0 && line.a == 0)
return 0;
if (b == 0 && line.b == 0)
return 0;
return 1;
}
lineType::lineType()
{
a = 0;
b = 0;
c = 0;
}
lineType::lineType(double a2, double b2, double c2)
{
a = a2;
b = b2;
c = c2;
}
lineType::~lineType()
{
}
The error message that appears
Error (active) E0289 no instance of constructor "lineType::lineType" matches the argument list Project1 line 20
Same error message for lines 21 and 22 in the source.cpp file. so I am not sure what is occuring?
lineType::lineType, which is the constructor, is implicitely generated, since you did not provide any user defined constructors. Default-generated constructors take no arguments, yet you try to provide three arguments in lines:
lineType line1(a, b, c);
lineType line2(d, e, f);
lineType line3(g, h, i);
I suspect you wanted to take advantage of aggregate initialisation, which you can't unfortunately use, since your a, b and c variables are private. You might want to add such constructor yourself:
lineType(const double a, const double b, const double c)
:a(a), b(b), c(c) { }
But that's not all. You have couple more problems with your code. Notably:
if (line1.isParallel(line2)) cout << "line1 is parallel to line 2" << endl;
contains a typo. It should be isParrallel, as declared in your class (which is also a typo) instead of isParallel. Fix either of these.
Lastly, the line:
if (line2.intersect(line3, x, y))
will not compile, since intersect() returns void, not bool. if statements require that they are provided either bools or something that's implicitely convertible to bool type. Make your function return bool, which is the logical assumption for a function that's name starts with is.
Just signed up, because my mind is blowing up on this stupid error.
I was calculating elliptic curves in a quick and dirty way with everything in 1 source-file.
Then I thought about cleaning up my code and start to separate the functions and classes in different files.
It's been a long time for me programming in C++ so I guess it is a really stupid beginner mistake.
So I am getting LNK1169-Error and LNK2005-Error and the solutions I found are about including .cpp which I am not doing. I although found out about the extern-keyword, but that seems to be kind of the solution for global variables.
Maybe someone can help me.
EDIT:
Sorry for putting that much code. I just don't know what is relevant for the error and what's not.
The error I am getting are like this:
fatal error LNK1169: one or more multiply defined symbols found. Elliptic 1 C:\Users\Björn\documents\visual studio 2015\Projects\Elliptic 1\Debug\Elliptic 1.exe
error LNK2005 "public: int __thiscall Value::operator==(class Value const &)" (??8Value##QAEHABV0##Z) already defined in Tests.obj
error LNK2005 "public: int __thiscall Value::operator==(int)" (??8Value##QAEHH#Z) already defined in Tests.obj
Here is my code:
Value.hpp
#pragma once
extern int PRIME;
// An own Int-Class to overload operators with modulo
class Value
{
public:
int v;
static friend std::ostream& operator<<(std::ostream& os, const Value& a);
Value()
{
this->v = 0;
}
Value(int a)
{
this->v = a;
}
Value operator+(const Value& other)
{
return Value((this->v + other.v) % PRIME);
}
Value operator+(int a)
{
return Value((this->v + a) % PRIME);
}
Value operator-(const Value& other)
{
Value t = Value((v - other.v) % PRIME);
if (t.v < 0)
{
t = t + PRIME;
return t;
}
return t;
}
Value operator-(int a)
{
Value t = Value((v - a) % PRIME);
if (t.v < 0)
{
t = t + PRIME;
return t;
}
return t;
}
void operator=(const Value other)
{
this->v = other.v;
}
Value operator*(const Value& a);
Value operator*(int a);
Value operator^(int a);
Value operator/(const Value& a);
int operator!=(int b);
int operator!=(const Value& b);
int operator==(int b);
int operator==(const Value& b);
Value operator~();
};
Value Value::operator*(const Value& a)
{
return Value((this->v*a.v) % PRIME);
}
Value Value::operator*(int a)
{
return Value((this->v*a) % PRIME);
}
Value Value::operator^(int b)
{
Value ret(1);
Value mul(this->v);
while (b)
{
if (b & 1)
ret = (ret * mul);
b = (b >> 1);
mul = mul * mul;
}
return ret;
}
Value Value::operator/(const Value& a)
{
if (a.v == 0)
return Value(0);
Value f = (Value)a ^ (PRIME - 2);
return *this * f;
}
int Value::operator!=(int b)
{
if (this->v != b)
return 1;
return 0;
}
int Value::operator!=(const Value& b)
{
if (this->v != b.v)
return 1;
return 0;
}
int Value::operator==(int b)
{
if (this->v == b)
return 1;
return 0;
}
int Value::operator==(const Value& b)
{
if (this->v == b.v)
return 1;
return 0;
}
Value Value::operator~()
{
return *this ^ ((PRIME - 1 + 2) / 4);
}
std::ostream& operator<<(std::ostream& os, const Value& a)
{
return os << a.v;
}
Point.hpp
#pragma once
#include "Value.hpp"
#include <iostream>
class Point
{
public:
Value x;
Value y;
Value z = 0;
static friend std::ostream& operator<<(std::ostream& os, const Point& p);
Point(int a, int b)
{
x.v = a;
y.v = b;
}
Point(int a, int b, int c)
{
x.v = a;
y.v = b;
z.v = c;
}
Point(Value a, Value b)
{
x.v = a.v;
y.v = b.v;
}
Point(Value a, Value b, Value c)
{
x.v = a.v;
y.v = b.v;
z.v = c.v;
}
Point& operator=(const Point& other)
{
x.v = other.x.v;
y.v = other.y.v;
z.v = other.z.v;
return *this;
}
int operator==(Point& other)
{
if (this->x == other.x && this->y == other.y && this->z == other.z)
return 1;
return 0;
}
int operator!=(Point& other)
{
if (this->x != other.x || this->y != other.y || this->z != other.z)
return 1;
return 0;
}
};
std::ostream& operator<<(std::ostream& os, const Point& p)
{
if ((Value)p.z == 0)
return os << "(" << p.x.v << "," << p.y.v << ")";
else
return os << "(" << p.x.v << "," << p.y.v << "," << p.z.v << ")";
}
Helper.hpp
#pragma once
#include "Point.hpp"
#include <vector>
// Forward declaration
int isEC(Value a, Value b);
Value calcEC(int x, Value a, Value b);
int testSqr(Value ySqr);
// Point Addition
Point add(Point p1, Point p2, Value a)
{
// 2D Addition
if (p1.z == 0 && p2.z == 0)
{
// 2 different points
if (p1.x.v != p2.x.v || p1.y.v != p2.y.v)
{
// m = (y2-y1)/(x2-x1)
Value h = p2.y - p1.y;
Value j = p2.x - p1.x;
Value m = h / j;
// x3 = m^2-x1-x2
Value f = m*m;
Value g = f - p1.x;
Value x3 = g - p2.x;
// y3 = m(x1-x3)-y1
Value t = p1.x - x3;
Value l = m * t;
Value y3 = l - p1.y;
if (x3.v < 0)
x3 = x3 + PRIME;
if (y3.v < 0)
y3 = y3 + PRIME;
return Point(x3, y3);
}
// Same points
else
{
// m = (3*x1^2+a)/(2*y1)
Value f = p1.x ^ 2;
Value g = f * 3;
Value h = g + a;
Value j = p1.y * 2;
Value m = h / j;
// x3 = m^2-2*x1
Value t = m*m;
Value x = p1.x * 2;
Value x3 = t - x;
// y3 = m(x1-x3)-y1
Value z = p1.x - x3;
Value i = m * z;
Value y3 = i - p1.y;
if (x3.v < 0)
x3 = x3 + PRIME;
if (y3.v < 0)
y3 = y3 + PRIME;
return Point(x3, y3);
}
}
// 3D Addition - Same points
else if (p1 == p2 && p1.z == 1 && p2.z == 1)
{
Value A = p1.y ^ 2;
Value B = p1.x * A * 4;
Value C = (A ^ 2) * 8;
Value D = (p1.x ^ 2)* 3 + a*(p1.z ^ 4);
//Value x3 = (((3 * (p1.x ^ 2) + a*(p1.z ^ 4)) ^ 2) - 8 * p1.x*(p1.y ^ 2));
Value x3 = (D ^ 2) - B * 2;
//Value y3 = (3 * (p1.x ^ 2) + a*(p1.z ^ 4)*(4 * p1.x*(p1.y ^ 2) - x3) - 8 * (p1.y ^ 4));
Value y3 = D*(B - x3) - C;
Value z3 = p1.y*p1.z * 2;
return Point(x3, y3, z3);
}
// 3D Addition - 2 different points
else if (p1 != p2)
{
Value A = p1.z ^ 2;
Value B = p1.z * A;
Value C = p2.x * A;
Value D = p2.y * B;
Value E = C - p1.x;
Value F = D - p1.y;
Value G = E ^ 2;
Value H = G * E;
Value I = p1.x * G;
Value x3 = (F ^ 2) - (H + (I * 2));
Value y3 = F*(I - x3) - p1.y*H;
Value z3 = p1.z * E;
return Point(x3, y3, z3);
}
return Point(0, 0, 0);
}
// Find all points and print them
std::vector<Point> findAllPoints(Value a, Value b)
{
Value ySqr;
std::vector<Point> vec;
std::cout << "Alle Punkte fuer a = " << a << ", b = " << b << " und Prime = " << PRIME << std::endl;
// Is it an elliptic curve?
if (isEC(a, b))
{
// Test all x-Values
for (int x = 0; x <= PRIME - 1;x++)
{
// y^2
ySqr = calcEC(x, a, b);
// Test ySqr for square by root
if (testSqr(ySqr))
{
//sqrt operator ~
Value yPos = ~ySqr;
std::cout << "(" << x << "," << yPos << ")\t";
Value yNeg = yPos - (yPos * 2);
// Save found points into vector
vec.push_back(Point(x, yPos));
vec.push_back(Point(x, yNeg));
if (yNeg != 0)
std::cout << "(" << x << "," << yNeg << ")\t";
}
}
//vec.insert(vec.begin(), Point(INFINITY, INFINITY));
std::cout << std::endl;
}
else
// Not an ellpitic curve
std::cout << "\na and b are not leading to an ellptic curve.";
return vec;
}
// Test if a and b lead to an EC
int isEC(Value a, Value b)
{
if ((a ^ 3) * 4 + (b ^ 2) * 27 != 0)
return 1;
return 0;
}
// Calculate y^2
Value calcEC(int x, Value a, Value b)
{
return Value(a*x + (x ^ 3) + b);
}
// Test ySqr for square by root
int testSqr(Value ySqr)
{
if ((ySqr ^ ((PRIME - 1) / 2)) == 1 || ySqr == 0)
return 1;
return 0;
}
Tests.hpp
#pragma once
#include "Helper.hpp"
class Tests
{
public:
void twoDAdd(Value a, Value b);
void twoDDoubling(Value a, Value b);
void threeDAdd(Value a, Value b);
void threeDDoubling(Value a, Value b);
};
Tests.cpp
#pragma once
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <math.h>
#include <time.h>
#include "Tests.hpp"
// 2D - Addition
void Tests::twoDAdd(Value a, Value b)
{
std::cout << "\n========== 2D Addition ==========\n";
Point p2D1 = Point(5, 22);
Point p2D2 = Point(16, 27);
std::cout << p2D1 << " + " << p2D2 << " = " << add(p2D1, p2D2, a);
std::cout << std::endl;
}
// 2D - Doubling
void Tests::twoDDoubling(Value a, Value b)
{
std::cout << "\n========== 2D Doubling ==========\n";
Point p2D1 = Point(5, 22);
std::cout << "2 * " << p2D1 << " = " << add(p2D1, p2D1, a);
std::cout << std::endl << std::endl;
}
// 3D - Addition
void Tests::threeDAdd(Value a, Value b)
{
std::cout << "\n========== 3D Addition ==========\n";
std::cout << "All points for a = " << a << ", b = " << b << " and prime = " << PRIME << std::endl;
std::vector<Point> allPoints = findAllPoints(a, b);
std::srand(time(NULL));
int random = std::rand() % (allPoints.capacity() - 1);
Point tmp = allPoints.at(random);
std::cout << std::endl << "Random Point 1: " << tmp << std::endl << std::endl;
tmp.z = 1;
Point p1 = add(tmp, tmp, a);
std::cout << p1 << std::endl;
random = std::rand() % (allPoints.capacity() - 1);
tmp = allPoints.at(random);
std::cout << std::endl << "Random Point 2: " << tmp << std::endl << std::endl;
tmp.z = 1;
Point p2 = add(tmp, tmp, a);
std::cout << p2 << std::endl;
Point p3 = add(p1, p2, a);
std::cout << p3 << std::endl;
}
// 3D - Doubling
void Tests::threeDDoubling(Value a, Value b)
{
std::cout << "\n========== 3D Doubling ==========\n";
std::cout << "All points for a = " << a << ", b = " << b << " and prime = " << PRIME << std::endl;
std::vector<Point> allPoints = findAllPoints(a, b);
int random = std::rand() % (allPoints.capacity() - 1);
Point tmp = allPoints[random];
std::cout << std::endl << "Random Point: " << tmp << std::endl << std::endl;
Point p1 = add(tmp, tmp, a);
std::cout << p1 << std::endl;
tmp.z = 1;
Point p2 = add(tmp, tmp, a);
std::cout << p2 << std::endl;
Point p3 = Point(p2.x / (p2.z ^ 2), p2.y / (p2.z ^ 3));
std::cout << p3 << std::endl;
if (p1 == p3)
std::cout << "Point p1 == Point p3" << std::endl;
else
std::cout << "Point p1 != Point p3" << std::endl;
}
Main.cpp
#pragma once
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <math.h>
#include <time.h>
#include "Tests.hpp"
int PRIME = 29;
void main()
{/*
Value a = 4;
Value b = 20;
std::vector<Point> allPoints = findAllPoints(a, b);
/*
// Tests ausfuehren
twoDAdd(a, b);
twoDDoubling(a, b);
threeDAdd(a, b);
threeDDoubling(a, b);
*/
std::cout << std::endl;
system("pause");
}
Thanks in advance and please excuse my "inperfect" way of coding.
This is happening because you have function definition in header files. Every file that we'll import your header files will have a body function - this is the reason why you have this error. If you want to have the definitions inside header files, you must use inline keyword. Otherwise you need to implement them in .cpp files (the "correct" way of solving this issue).
e.g
// Test if a and b lead to an EC
inline int isEC(Value a, Value b)
{
if ((a ^ 3) * 4 + (b ^ 2) * 27 != 0)
return 1;
return 0;
}
// Calculate y^2
inline Value calcEC(int x, Value a, Value b)
{
return Value(a*x + (x ^ 3) + b);
}
// Test ySqr for square by root
inline int testSqr(Value ySqr)
{
if ((ySqr ^ ((PRIME - 1) / 2)) == 1 || ySqr == 0)
return 1;
return 0;
}
/*
* File: ShapeTwoD.h
* Author: Administrator
*
* Created on October 30, 2012, 12:05 AM
*/
#ifndef SHAPETWOD_H
#define SHAPETWOD_H
#include <string>
#include <math.h>
using namespace std;
struct Point {
int x, y;
};
class ShapeTwoD {
public:
ShapeTwoD(string shapename, bool containsWS);
string getName();
bool getContainsWarpSpace();
string toString();
virtual double computeArea();
virtual bool isPointInShape(Point P, Point* V, int n);
virtual bool isPointOnShape(Point A, Point B, Point C, int slope, int intercept, int left, int top, int right, int bottom, int dx, int dy);
void setName(string shapename);
void setContainsWarpSpace(bool containsWS);
private:
string name;
bool containsWarpSpace;
};
class Cross : public ShapeTwoD {
public:
Cross(string shapename = "Cross", bool containsWS, int vertices = 12, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
int getVert();
void setVert(int vertices);
Point getOrd();
void setOrd(Point ordinates[]);
virtual double computeArea(Point A[], int vertices);
private:
int vert;
Point ord[];
};
class Rectangle : public ShapeTwoD {
public:
Rectangle(string shapename = "Rectangle", bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
int getVert();
void setVert(int vertices);
Point getOrd();
void setOrd(Point ordinates[]);
virtual double computeArea(Point A, Point B);
private:
int vert;
Point ord[];
};
class Square : public ShapeTwoD {
public:
Square(string shapename = "Square", bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
int getVert();
void setVert(int vertices);
Point getOrd();
void setOrd(Point ordinates[]);
virtual double computeArea(Point A, Point B);
private:
int vert;
Point ord[];
};
#endif /* SHAPETWOD_H */
/*
* File: ShapeTwoD.cpp
* Author: Administrator
*
* Created on October 30, 2012, 12:05 AM
*/
#include "ShapeTwoD.h"
#include <sstream>
ShapeTwoD::ShapeTwoD(string shapename, bool containsWS) {
name = shapename;
containsWarpSpace = containsWS;
}
string ShapeTwoD::getName() {
return name;
}
void ShapeTwoD::setName(string shapename) {
name = shapename;
};
bool ShapeTwoD::getContainsWarpSpace() {
return containsWarpSpace;
}
void ShapeTwoD::setContainsWarpSpace(bool containsWS) {
containsWarpSpace = containsWS;
}
string cvtBool(bool b) {
stringstream ss;
ss << b;
return ss.str();
}
string ShapeTwoD::toString() {
return "Name:\t" + name + "\nSpecial Type:\t" + cvtBool(containsWarpSpace) + "\n";
}
// Formulas gotten from http://www.mathopenref.com/coordpolygonarea.html
// http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm
int pointsInShape;
int pointsOnShape;
double ShapeTwoD::computeArea() {
// Based on Pick's Thorem
double area = pointsInShape + (pointsOnShape / 2) - 1;
return area;
}
float isLeft(Point P0, Point P1, Point P2) {
return ((P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y));
}
bool ShapeTwoD::isPointInShape(Point P, Point* V, int n) {
// Input: P = a point,
// V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
int wn = 0; // the winding number counter
// loop through all edges of the polygon
for (int i = 0; i < n; i++) { // edge from V[i] to V[i+1]
if (V[i].y <= P.y) { // start y <= P.y
if (V[i + 1].y > P.y) // an upward crossing
if (isLeft(V[i], V[i + 1], P) > 0) // P left of edge
++wn; // have a valid up intersect
} else { // start y > P.y (no test needed)
if (V[i + 1].y <= P.y) // a downward crossing
if (isLeft(V[i], V[i + 1], P) < 0) // P right of edge
--wn; // have a valid down intersect
}
}
pointsInShape += wn;
return true;
}
bool ShapeTwoD::isPointOnShape(Point A, Point B, Point C, int slope, int intercept, int left, int top, int right, int bottom, int dx, int dy) {
// Linear equation
dx = B.x - A.x;
dy = B.y - A.y;
slope = dy / dx;
intercept = y1 - slope * A.x;
if (A.x < B.x) {
left = A.x;
right = B.x;
} else {
left = B.x;
right = A.x;
}
if (A.y < B.y) {
top = A.y;
bottom = B.y;
} else {
top = B.y;
bottom = A.y;
}
if (slope * C.x + intercept > (C.y - 0.01) && slope * C.x + intercept < (C.y + 0.01)) {
if (C.x >= left && C.x <= right && C.y >= top && C.y <= bottom) {
pointsOnShape++;
return true;
}
}
}
Cross::Cross(string shapename, bool containsWS, int vertices = 12, Point ordinates[]):ShapeTwoD(shapename, containsWS) {
vert = vertices;
ord[] = ordinates[];
}
int Cross::getVert() {
return vert;
}
void Cross::setVert(int vertices) {
vert = vertices;
}
Point Cross::getOrd() {
return ord[];
}
void Cross::setOrd(Point ordinates[]) {
ord[] = ordinates[];
}
double Cross::computeArea(Point A[], int vertices) {
/* If you know the coordinates of the vertices of a polygon, this algorithm can be used to find the area.
* Parameters
* X, Y Arrays of the x and y coordinates of the vertices, traced in a clockwise direction, starting at any vertex. If you trace them counterclockwise, the result will be correct but have a negative sign.
* numPoints The number of vertices
* Returns the area of the polygon
*/
double area = 0;
int j = vertices - 1; // The last vertex is the 'previous' one to the first
for (int i = 0; i < vertices; i++) {
area = (area + (A[j].x + A[i].x) * (A[j].y - A[i].y))/2;
j = i;
}
return area;
}
Rectangle::Rectangle(string shapename, bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS) {
vert = vertices;
ord[] = ordinates[];
}
int Rectangle::getVert() {
return vert;
}
void Rectangle::setVert(int vertices) {
vert = vertices;
}
void Rectangle::getOrd() {
return ord[];
}
void Rectangle::setOrd(Point ordinates[]) {
ord[] = ordinates[];
}
double Rectangle::computeArea(Point A, Point B, Point C) {
double length = sqrt(pow((A.x - B.x), 2) + pow((A.y - B.y), 2));
double width = sqrt(pow((B.x - C.x), 2) + pow((B.y - C.y), 2));
double area = length * width;
return area;
}
Square::Square(string shapename, bool containsWS, int vertices, Point ordinates[]):ShapeTwoD(shapename, containsWS) {
vert = vertices;
ord[] = ordinates[];
}
int Square::getVert() {
return vert;
}
void Square::setVert(int vertices) {
vert = vertices;
}
void Square::getOrd() {
return ord[];
}
void Square::setOrd(Point ordinates[]) {
ord[] = ordinates[];
}
double Square::computeArea(Point A, Point B) {
double length = sqrt(pow((A.x - B.x), 2) + pow((A.y - B.y), 2));
double area = pow(length, 2);
return area;
}
/*
* File: Assn2.cpp
* Author: Administrator
*
* Created on October 29, 2012, 11:58 PM
*/
#include "ShapeTwoD.h"
#include <iostream>
#include <math.h>
#include <string>
#include <vector>
using namespace std;
// Global declarations
void menu(), option1(), option2(), option3(), option4();
int choice, vert;
string shape, special;
double area;
bool containsWS;
vector<ShapeTwoD> stdv;
int main() {
cout << "Welcome to Assn2 program!\n\n";
// When user enters 5 as input, the program quits
while (choice != 5) {
menu();
/* switch evaluates expression and checks if it is equivalent to constant1,
* if it is, it executes group of statements 1 until it finds the break statement.
* When it finds this break statement the program jumps to the end of the switch selective structure.
* If expression was not equal to constant1 it will be checked against constant2.
* If it is equal to this, it will execute group of statements 2 until a break keyword is found,
* and then will jump to the end of the switch selective structure.
*/
switch (choice) {
case 1:
option1();
break;
case 2:
option2();
break;
case 3:
option3();
break;
case 4:
option4();
break;
}
}
}
void menu() {
cout << "1) Input sensor data\n";
cout << "2) Compute area (for all records)\n";
cout << "3) Print shapes report\n";
cout << "4) Sort shape data\n";
cout << "5) Quit\n\n";
cout << "Please enter your choice: ";
cin >> choice;
cout << "\n";
}
void option1() {
cout << "[ Input sensor data ]\n";
cout << "Please enter name of Shape (Cross, Rectangle or Square): ";
cin >> shape;
cout << "Please enter Special type (NS or WS): ";
cin >> special;
if (special == "WS") {
containsWS = true;
}
else {
containsWS = false;
}
if (shape == "Cross") {
vert = 12;
for (int v = 0; v < vert; v++) {
Point ordinates[v];
cout << "Please enter x-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].x;
cout << "Please enter y-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].y;
Cross cross(shape, containsWS, vert, ordinates[v]);
stdv.push_back(cross);
}
}
if (shape == "Rectangle") {
vert = 4;
for (int v = 0; v < vert; v++) {
Point ordinates[v];
cout << "Please enter x-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].x;
cout << "Please enter y-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].y;
Rectangle rectangle(shape, containsWS, vert, ordinates[v]);
stdv.push_back(rectangle);
}
}
else {
shape = "Square";
vert = 4;
for (int v = 0; v < vert; v++) {
Point ordinates[v];
cout << "Please enter x-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].x;
cout << "Please enter y-ordinate of pt. " << (v+1) << ":";
cin >> ordinates[v].y;
Square square(shape, containsWS, vert, ordinates[v]);
stdv.push_back(square);
}
}
cout << "Record successfully stored. Going back to main menu";
}
void option2() {
if (stdv.size() != 0) {
for (int count = 0; count < stdv.size(); count++) {
area = stdv.at(count).computeArea();
//Debugging purpose
cout << (count+1) << ")" << stdv.at(count).getName() << "\t" << area;
}
cout << "Computation completed! (" << stdv.size() << " records were updated)\n\n";
}
}
Here I'm trying to insert an array of the struct Point into my class constructors (Cross, Rectangle, Square). But it returned me some errors which I don't really get.
Assn2.cpp:113: error: no matching function for call to
`Cross::Cross(std::string&, bool&, int&, Point&)'
ShapeTwoD.h:41: note: candidates are: Cross::Cross(const Cross&)
ShapeTwoD.h:43: note: Cross::Cross(std::string, bool,
int, Point*)
Assn2.cpp:136: error: no matching function for call to
`Rectangle::Rectangle(std::string&, bool&, int&, Point&)
ShapeTwoD.h:56: note: candidates are: Rectangle::Rectangle(const
Rectangle&)
ShapeTwoD.h:58: note: Rectangle::Rectangle(std::string, bool, int,
Point*)
your function declaration won't even compile, the parameter with default value can't be in the front of argument without default value:
Cross(string shapename = "Cross", bool containsWS, int vertices = 12, Point ordinates[])
Rectangle(string shapename = "Rectangle", bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
Square(string shapename = "Square", bool containsWS, int vertices = 4, Point ordinates[]):ShapeTwoD(shapename, containsWS){}
you either make all parameters having all default values or change the order, for example below is valid function declaration:
Cross(bool containsWS, Point ordinates[], string shapename = "Cross", int vertices = 12)