1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cmath>
using namespace std;
const double SMALL = 1.0e-10;
// Structures/classes
struct Point{ double x, y; };
// Prototypes
void border( const vector<Point> &p, double thickness, vector<Point> &q );
double signedArea( const vector<Point> &p );
void output( ostream &strm, const vector<Point> &p, vector<Point> &q );
//======================================================================
int main()
{
vector<Point> p = { { 0, 0 }, { 1, 0 }, { 2, 3 }, { 0, 1 }, { 0, 0 } }; // Outside vertices
double thickness = 0.1; // Border thickness
vector<Point> q; // Inside vertices (eventually)
// Compute internal vertices
border( p, thickness, q );
// Output to screen and/or file
ofstream out( "output.txt" );
output( cout, p, q );
output( out, p, q );
out.close();
cout << "\nSigned area is " << signedArea( p ) << '\n';
}
//======================================================================
void border( const vector<Point> &p, double thickness, vector<Point> &q )
{
//=====================================================//
// Assumes: //
// N+1 vertices: p[0], p[1], ... , p[N-1], p[N] //
// Closed polygon: p[0] = p[N] //
// No zero-length sides //
// Returns (by reference, as a parameter): //
// Internal poly: q[0], q[1], ... , q[N-1], q[N] //
//=====================================================//
int N = p.size() - 1;
q.resize(N+1);
double a, b, A, B, d, cross;
double displacement = thickness;
if ( signedArea( p ) < 0 ) displacement = -displacement; // Detects clockwise order
// Unit vector (a,b) along last edge
a = p[N].x - p[N-1].x;
b = p[N].y - p[N-1].y;
d = sqrt( a * a + b * b );
a /= d;
b /= d;
// Loop round the polygon, dealing with successive intersections of lines
for ( int i = 0; i < N; i++ )
{
// Unit vector (A,B) along previous edge
A = a;
B = b;
// Unit vector (a,b) along next edge
a = p[i+1].x - p[i].x;
b = p[i+1].y - p[i].y;
d = sqrt( a * a + b * b );
a /= d;
b /= d;
// New vertex
cross = A * b - a * B;
if ( abs( cross ) < SMALL ) // Degenerate cases: 0 or 180 degrees at vertex
{
q[i].x = p[i].x - displacement * b;
q[i].y = p[i].y + displacement * a;
}
else // Usual case
{
q[i].x = p[i].x + displacement * ( a - A ) / cross;
q[i].y = p[i].y + displacement * ( b - B ) / cross;
}
}
// Close the inside polygon
q[N] = q[0];
}
//======================================================================
double signedArea( const vector<Point> &p )
{
double A = 0;
//========================================================//
// Assumes: //
// N+1 vertices: p[0], p[1], ... , p[N-1], p[N] //
// Closed polygon: p[0] = p[N] //
// Returns: //
// Signed area: +ve if anticlockwise, -ve if clockwise //
//========================================================//
int N = p.size() - 1;
for ( int i = 0; i < N; i++ ) A += p[i].x * p[i+1].y - p[i+1].x * p[i].y;
A *= 0.5;
return A;
}
//======================================================================
void output( ostream &strm, const vector<Point> &p, vector<Point> &q )
{
int N = p.size() - 1;
// Formatting (adapt to your needs)
strm.setf( ios::fixed ); // fixed or scientific
strm.precision( 6 ); // Decimal digits after point
#define SP << " " << setw( 12 ) << // Spacer and field width
for ( int i = 0; i <= N; i++ ) strm SP p[i].x SP p[i].y SP q[i].x SP q[i].y << '\n';
}
//======================================================================
|