Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <cmath>
- #include <vector>
- #include <assert.h>
- #include <iomanip>
- #include <queue>
- #include<algorithm>
- const double pi = 3.141592653589793238462643;
- const double accuracy = 0.0;
- const double MAX = 10000000;
- class Vector;
- class Vector2d {
- public:
- long double x;
- long double y;
- Vector2d() = default;
- Vector2d(long double x,long double y) : x(x), y(y){}
- Vector2d(const Vector2d& vector) = default;
- friend bool operator == (const Vector2d& left, const Vector2d& right);
- friend bool operator != (const Vector2d& left, const Vector2d& right);
- friend Vector2d operator + (const Vector2d& left, const Vector2d& right);
- friend bool operator < (const Vector2d& left, const Vector2d& right);
- friend bool operator > (const Vector2d& left, const Vector2d& right);
- friend bool operator >= (const Vector2d& left, const Vector2d& right);
- friend bool operator <= (const Vector2d& left, const Vector2d& right);
- friend Vector2d operator - (const Vector2d& left, const Vector2d& right);
- friend Vector2d operator / (const Vector2d& left, const long double & right);
- void operator += (const Vector2d& other){
- x += other.x;
- y += other.y;
- }
- void operator -= (const Vector2d& other){
- x -= other.x;
- y -= other.y;
- }
- void operator /= (const long double & c){
- assert(c >0);
- x /= c;
- y /= c;
- }
- void operator *= (const long double & c) {
- x *= c;
- y *= c;
- }
- };
- long double distance (const Vector2d& first, const Vector2d& second) {
- return sqrtl(((first.x-second.x)*(first.x-second.x)
- + (first.y-second.y)*(first.y-second.y)));
- }
- long double scalarMul (const Vector2d& first, const Vector2d& second) {
- return first.x * second.x + first.y * second.y;
- }
- /*
- * Арифметические операции
- */
- bool operator < (const Vector2d& left, const Vector2d& right) {
- if (right == left) {
- return false;
- }
- if (right == Vector2d(0,0)) {
- return false;
- }
- if (left == Vector2d(0,0)) {
- return true;
- }
- Vector2d a(0, -1);
- long double x = scalarMul(a, left) * sqrtl(256*(right.x* right.x + right.y*right.y))/16 -
- scalarMul(a, right) * sqrtl(256*(left.x* left.x + left.y*left.y))/16;
- if (x == 0) {
- return left.x* left.x + left.y*left.y < right.x* right.x + right.y*right.y;
- } else {
- return x > -accuracy;
- }
- }
- bool operator <= (const Vector2d& left, const Vector2d& right) {
- return left < right || left == right;
- }
- bool operator > (const Vector2d& left, const Vector2d& right) {
- return !(left <= right);
- }
- bool operator >= (const Vector2d& left, const Vector2d& right) {
- return left > right;
- }
- Vector2d operator + (const Vector2d& left, const Vector2d& right){
- Vector2d data = left;
- data += right;
- return data;
- }
- Vector2d operator - (const Vector2d& left, const Vector2d& right){
- Vector2d data = left;
- data -= right;
- return data;
- }
- Vector2d operator / (const Vector2d& left, const long double & right){
- assert(right != 0);
- Vector2d data = left;
- data /= right;
- return data;
- }
- Vector2d operator * (const Vector2d& left, const long double right){
- Vector2d data = left;
- data *= right;
- return data;
- }
- bool operator == (const Vector2d& left, const Vector2d& right) {
- return fabsl(left.x - right.x) <= accuracy && fabsl(left.y - right.y) <= accuracy;
- }
- bool operator != (const Vector2d& left, const Vector2d& right) {
- return !(left == right);
- }
- long double OrientalSquare (const Vector2d& first, const Vector2d& second) {
- return first.x*second.y - first.y*second.x;
- }
- size_t FindMinVertice(std::vector<std::pair<Vector2d, size_t>> & vertices) {
- size_t minInd = 0;
- Vector2d & min = vertices[minInd].first;
- for (size_t i = 0; i < vertices.size(); ++i) {
- Vector2d & cur = vertices[i].first;
- if (cur.x < min.x || (cur.x == min.x && cur.y < min.y)) {
- min = cur;
- minInd = i;
- }
- }
- return minInd;
- }
- bool isOnTheSameSide(Vector2d & begin, Vector2d& end, Vector2d& p1, Vector2d& p2) {
- Vector2d side = begin - end;
- Vector2d v1 = p1 - end;
- Vector2d v2 = p2 - end;
- long double s1 = OrientalSquare(side, v1);
- long double s2 = OrientalSquare(side, v2);
- return ((s1 >= 0 && s2 >= 0) || (s1 <= 0 && s2 <= 0));
- }
- bool isOnTheSameLine(Vector2d & x, Vector2d & y, Vector2d & z) {
- Vector2d v1 = y - x, v2 = z - x;
- return OrientalSquare(v1, v2) == 0;
- }
- class Vector {
- size_t num;
- public:
- double x;
- double y;
- double z;
- Vector() = default;
- Vector(double x,double y, double z) : x(x), y(y), z(z), num(-1){}
- Vector(const Vector& vector) = default;
- friend bool operator == (const Vector& left, const Vector& right);
- friend bool operator != (const Vector& left, const Vector& right);
- friend Vector operator + (const Vector& left, const Vector& right);
- friend bool operator < (const Vector& left, const Vector& right);
- friend bool operator > (const Vector& left, const Vector& right);
- friend bool operator >= (const Vector& left, const Vector& right);
- friend bool operator <= (const Vector& left, const Vector& right);
- friend Vector operator - (const Vector& left, const Vector& right);
- friend Vector operator / (const Vector& left, const double& right);
- void operator += (const Vector& other){
- x += other.x;
- y += other.y;
- z += other.z;
- }
- void operator -= (const Vector& other){
- x -= other.x;
- y -= other.y;
- z -= other.z;
- }
- void operator /= (const double& c){
- assert(c >0);
- x /= c;
- y /= c;
- z /= c;
- }
- void operator *= (const double& c) {
- x *= c;
- y *= c;
- z *= c;
- }
- size_t getNum() {
- return num;
- }
- void setNum(size_t i) {
- num = i;
- }
- };
- /*
- * Арифметические операции
- */
- Vector operator + (const Vector& left, const Vector& right){
- Vector data = left;
- data += right;
- return data;
- }
- Vector operator - (const Vector& left, const Vector& right){
- Vector data = left;
- data -= right;
- return data;
- }
- Vector operator / (const Vector& left, const double& right){
- assert(right != 0);
- Vector data = left;
- data /= right;
- return data;
- }
- Vector operator * (const Vector& left, const double right){
- Vector data = left;
- data *= right;
- return data;
- }
- /*
- * Операции сравнения
- */
- bool operator > (const Vector& left, const Vector& right) {
- return (left.x>right.x) && (left.y > right.y) && (left.z > right.z);
- }
- bool operator < (const Vector& left, const Vector& right) {
- return (left.x<right.x) && (left.y < right.y) && (left.z < right.z);
- }
- bool operator <= (const Vector& left, const Vector& right) {
- return (left.x<=right.x) && (left.y <= right.y) && (left.z <= right.z);
- }
- bool operator >= (const Vector& left, const Vector& right) {
- return (left.x>=right.x) && (left.y >= right.y) && (left.z >= right.z);
- }
- bool operator == (const Vector& left, const Vector& right) {
- return fabs(left.x - right.x) <= accuracy && fabs(left.y - right.y) <= accuracy;
- }
- bool operator != (const Vector& left, const Vector& right) {
- return !(left == right);
- }
- double scalarMul (const Vector& first, const Vector& second) {
- return first.x * second.x + first.y * second.y + first.z * second.z;
- }
- Vector vectorMul (const Vector& first, const Vector& second) {
- return Vector(first.y*second.z - first.z*second.y,
- first.z*second.x - first.x*second.z,
- first.x*second.y - first.y*second.x);
- }
- double distance (const Vector& first, const Vector& second) {
- return sqrt( 256 *((first.x-second.x)*(first.x-second.x)
- + (first.y-second.y)*(first.y-second.y) +
- (first.z-second.z)*(first.z-second.z)))/16;
- }
- double Volume(const Vector& first, const Vector& second, const Vector& third) {
- return first.x*second.y*third.z + first.y*second.z*third.x + first.z*second.x*third.y -
- first.x*second.z*third.y + first.y*second.x*third.z + first.z*second.y*third.x;
- }
- class Plane {
- public:
- Vector normal;
- double D;
- Plane (const Vector& firstP, const Vector& secondP, const Vector& thirdP):
- normal(vectorMul(firstP - thirdP, secondP - thirdP)),
- D(-scalarMul(normal, thirdP)) {}
- };
- class Face {
- private:
- std::vector<Vector> vertices;
- std::vector<Vector> ConvexHull;
- Plane plane;
- bool isCounted = false;
- bool isXConst = false;
- bool isZConst = false;
- bool isYConst = false;
- void FindConvexHull() {
- std::vector<std::pair<Vector2d, size_t>> verticesProection;
- if (!isZConst) {
- for(size_t i =0; i < vertices.size(); i++) {
- verticesProection.emplace_back(Vector2d(vertices[i].x, vertices[i].y), i);
- }
- } else {
- if (!isXConst) {
- for(size_t i =0; i < vertices.size(); i++) {
- verticesProection.emplace_back(Vector2d(vertices[i].y, vertices[i].z), i);
- }
- } else {
- if(!isYConst) {
- for(size_t i =0; i < vertices.size(); i++) {
- verticesProection.emplace_back(Vector2d(vertices[i].x, vertices[i].z), i);
- }
- }
- }
- }
- std::vector<std::pair<Vector2d, size_t>> vectors(vertices.size());
- std::vector<Vector2d> result;
- size_t minInd = FindMinVertice(verticesProection);
- Vector2d min2D = verticesProection[minInd].first;
- Vector min3D = vertices[verticesProection[minInd].second];
- for (auto &i: verticesProection) {
- vectors.emplace_back(i.first - min2D, i.second);
- }
- std::sort(vectors.begin(), vectors.end());
- Vector2d prev = min2D;
- ConvexHull.push_back(min3D);
- for (auto& i:vectors) {
- Vector2d nextVertice2d = min2D + i.first;
- Vector nextVertice3d = min3D + vertices[i.second];
- if (nextVertice2d != prev) {
- if (result.size() < 2) {
- result.push_back(nextVertice2d);
- ConvexHull.push_back(nextVertice3d);
- } else {
- while(result.size() > 1 && isOnTheSameLine(min2D, result[result.size() - 1], nextVertice2d) ){
- result.pop_back();
- ConvexHull.pop_back();
- }
- size_t j = result.size() - 1;
- while(j > 0 && (isOnTheSameLine(result[j], nextVertice2d, result[(j-1)]) || !isOnTheSameSide(result[j], nextVertice2d,
- result[(j-1)], result[(j + 1)% result.size()]))) {
- --j;
- }
- for (size_t t = result.size() - 1; t > j; --t) {
- result.pop_back();
- ConvexHull.pop_back();
- }
- result.push_back(nextVertice2d);
- ConvexHull.push_back(nextVertice3d);
- }
- }
- prev = nextVertice2d;
- }
- return;
- }
- public:
- Face() : plane(Vector(0,0,0), Vector(0,0,0), Vector(0,0,0)), vertices(0), ConvexHull(0){};
- Face(const Vector& a, const Vector& b, const Vector& c) : plane(a, b, c) {
- vertices.push_back(a);
- vertices.push_back(b);
- vertices.push_back(c);
- if (a.x == b.x && b.x == c.x) {
- isXConst = true;
- }
- if (a.y == b.y && b.y == c.y) {
- isYConst = true;
- }
- if (a.z == b.z && b.z == c.z) {
- isZConst = true;
- }
- }
- Face(std::vector<Vector> & v) : vertices(v) , plane(v[0], v[1%v.size()], v[2%v.size()]) {
- Vector a = v[0];
- Vector b = v[1];
- Vector c = v[2];
- vertices.push_back(a);
- vertices.push_back(b);
- vertices.push_back(c);
- if (a.x == b.x && b.x == c.x) {
- isXConst = true;
- }
- if (a.y == b.y && b.y == c.y) {
- isYConst = true;
- }
- if (a.z == b.z && b.z == c.z) {
- isZConst = true;
- }
- }
- Vector ThirdVertex(const Vector& a, const Vector& b) const {
- for (auto&i : vertices) {
- if (i != a && i != b) {
- return i;
- }
- }
- assert(vertices.size() >= 3);
- return a;
- }
- Vector getNormal() const {
- return plane.normal;
- }
- void push_back(const Vector& a) {
- vertices.push_back(a);
- }
- std::vector<Vector> getConvexHull() {
- if (isCounted) {
- return ConvexHull;
- }
- FindConvexHull();
- isCounted = true;
- return ConvexHull;
- }
- };
- class Edge {
- public:
- Vector begin;
- Vector end;
- const Face& face;
- Edge(Vector begin, Vector end, const Face& face) :begin(begin), end(end), face(face){
- }
- };
- bool isOnOnePlane(Vector& a, Vector& b, Vector& c, Vector &d) {
- return fabs(Volume(b - a, c - a, d - a)) < accuracy;
- }
- class PointsContainer {
- std::vector<Vector> points;
- std::vector<Face> convexHull;
- public:
- PointsContainer() : points(0), convexHull(0){};
- void emplace_back (double x, double y, double z) {
- points.emplace_back(x, y, z);
- size_t last = points.size() - 1;
- points[last].setNum(last);
- }
- Vector FindMaxAngle(Edge& e) {
- const Face& face = e.face;
- Vector thirdVertex = face.ThirdVertex(e.begin, e.end);
- Vector curMin = points[0];
- Vector curNormal = Plane(curMin, e.begin, e.end).normal;
- for (auto& point: points) {
- if (point != e.begin && point != e.end && !isOnOnePlane(e.begin, e.end, point, thirdVertex)) {
- Plane cur = Plane(point, e.begin, e.end);
- if (scalarMul(cur.normal, face.getNormal()) * distance(curNormal, Vector(0,0,0)) -
- scalarMul(curNormal, face.getNormal()) * distance(cur.normal, Vector(0,0,0)) > -accuracy){
- curNormal = cur.normal;
- curMin = point;
- }
- }
- }
- return curMin;
- }
- Face constructFaceWithAllPoints(Vector& a, Vector& b, Vector& c) {
- Face res({a, b, c});
- for (auto& i:points) {
- if (i!=a && i!= b && i!=c) {
- if (isOnOnePlane(a, b, c, i)) {
- res.push_back(i);
- }
- }
- }
- return res;
- }
- void FindFirstFace() {
- Vector& first = points[0];
- for (size_t i = 0; i < points.size(); ++i) {
- Vector & cur = points[i];
- if (cur.x < first.x || (cur.x == first.x && cur.y < first.y) || (cur.x == first.x && cur.y == first.y && cur.z < first.z)) {
- first = cur;
- }
- }
- Vector& second = points[1];
- for (size_t i = 0; i < points.size(); ++i) {
- Vector & cur = points[i];
- if (cur != first) {
- if (scalarMul(cur - first, Vector(1,0,0)) * distance(second, Vector(0,0,0)) -
- scalarMul(second - first, Vector(1, 0, 0)) * distance(cur, Vector(0,0,0)) < accuracy) {
- second = cur;
- }
- }
- }
- Vector third = first;
- bool isInicilized = false;
- for (size_t i = 0; i < points.size(); ++i) {
- Vector & cur = points[i];
- if (cur != first && vectorMul(cur-first, cur-second) != Vector(0,0,0)) {
- if (!isInicilized ||(scalarMul(cur - first, Vector(1,0,0)) * distance(second, Vector(0,0,0)) -
- scalarMul(second - first, Vector(1, 0, 0)) * distance(cur, Vector(0,0,0)) < accuracy)) {
- third = cur;
- isInicilized = true;
- }
- }
- }
- convexHull.push_back(constructFaceWithAllPoints(first, second, third));
- }
- void FindConvexHull () {
- std::vector<std::vector<bool>> isUsed(points.size(), std::vector<bool>(points.size(), 0));
- std::queue<Edge> edgesQ;
- FindFirstFace();
- std::vector<Vector> FaceConvHull = convexHull[0].getConvexHull();
- for (size_t i = 0; i < FaceConvHull.size() + 1; i++) {
- edgesQ.push(Edge(FaceConvHull[i],FaceConvHull[(i+1)%FaceConvHull.size()], convexHull[0]));
- }
- while (!edgesQ.empty()) {
- Edge e = edgesQ.front();
- edgesQ.pop();
- if (!isUsed[e.begin.getNum()][e.end.getNum()]) {
- isUsed[e.begin.getNum()][e.end.getNum()] = true;
- isUsed[e.end.getNum()] [e.begin.getNum()]= true;
- Vector p3 = FindMaxAngle(e);
- convexHull.push_back(constructFaceWithAllPoints(e.begin, e.end, p3));
- size_t last = convexHull.size() - 1;
- std::vector<Vector> FaceConvHull = convexHull[last].getConvexHull();
- for (size_t i = 0; i < FaceConvHull.size() + 1; i++) {
- edgesQ.push(Edge(FaceConvHull[i],FaceConvHull[(i+1)%FaceConvHull.size()], convexHull[last]));
- }
- }
- }
- }
- };
- int main() {
- PointsContainer v;
- double x, y, z;
- int N;
- std::cin >> N;
- for (int i = 0; i < N; i++) {
- std::cin >> x>> y>> z;
- v.emplace_back(x, y, z);
- }
- v.FindConvexHull();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment