├── .gitignore ├── CImg.h ├── LICENSE.md ├── Makefile ├── README ├── Visibility_Graph_Algorithm.pdf ├── autorun.sh ├── data.cvs ├── data_space.cvs ├── geometry.h ├── line.cpp ├── line.h ├── node.h ├── plot.m ├── point.cpp ├── point.h ├── skiplist.h ├── vgraph.cpp └── vgraph.dSYM └── Contents └── Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | vgraph 2 | .DS_Store 3 | *.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Dave Coleman 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | g++ -o vgraph vgraph.cpp point.cpp line.cpp -I.. -O3 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 4 | #g++ -o vgraph vgraph.cpp point.cpp line.cpp -I.. -g -Wall -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 5 | # g++ -o vgraph vgraph.cpp -I.. -Wall -W -lm -ansi -pedantic -O3 -fno-tree-pre -Dcimg_use_vt100 -I/usr/X11R6/include -L/usr/X11R6/lib -lpthread -lX11 6 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Visibility Graph 2 | A O(n^2 log n) implementation of constructing a visibility graph 3 | 4 | by Dave Coleman 5 | A project for Advanced Algorithms at CU Boulder 6 | 7 | ------------- 8 | 9 | -------------------------------------------------------------------------------- /Visibility_Graph_Algorithm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davetcoleman/visibility_graph/e0416582b3d67b1b2294fabf112b1c8b114a98b2/Visibility_Graph_Algorithm.pdf -------------------------------------------------------------------------------- /autorun.sh: -------------------------------------------------------------------------------- 1 | make 2 | ./vgraph 3 | -------------------------------------------------------------------------------- /data.cvs: -------------------------------------------------------------------------------- 1 | 9,6026 2 | 25,62585 3 | 100,1.42313e+06 4 | 289,1.47751e+07 5 | 961,2.34027e+08 6 | 3136,2.914e+09 -------------------------------------------------------------------------------- /data_space.cvs: -------------------------------------------------------------------------------- 1 | 9,47 2 | 25,131 3 | 100,423 4 | 289,1167 5 | 961,3984 6 | 3136,12905 -------------------------------------------------------------------------------- /geometry.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOMETRY_H_INCLUDED 2 | #define GEOMETRY_H_INCLUDED 3 | 4 | class Geometry 5 | { 6 | public: 7 | // int id; // for removing, comparing, etc 8 | 9 | virtual void print() = 0; 10 | virtual double value() = 0; 11 | 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /line.cpp: -------------------------------------------------------------------------------- 1 | #include "line.h" 2 | 3 | Point * center; 4 | Line * center_line; 5 | double atomic; 6 | double atomic_space; 7 | 8 | using namespace std; 9 | 10 | Line::Line() 11 | { 12 | cout << "You are calling the function wrong"; 13 | exit(0); 14 | } 15 | Line::Line(int x1, int y1, int x2, int y2) 16 | { 17 | // Order a and b such that a.x > b.x 18 | if( x1 > x2 ) 19 | { 20 | a = new Point(x1, y1); 21 | b = new Point(x2, y2); 22 | } 23 | else 24 | { 25 | b = new Point(x1, y1); 26 | a = new Point(x2, y2); 27 | } 28 | 29 | // Change ID 30 | static int id_counter = 0; 31 | id = id_counter++; 32 | 33 | // Keep track of its visited history 34 | visited = false; 35 | visitedStartPoint = false; 36 | 37 | // cout << "LINE" << endl; 38 | updateCalcs(); 39 | 40 | // cout << "LINE" << endl; 41 | 42 | // Used for checking if we need to refresh our distance amount 43 | theta_cache = 3*M_PI; // some angle bigger than 2PI, aka INF 44 | //distance(); 45 | 46 | // cout << "END LINE \n" << endl; 47 | } 48 | Line::~Line() 49 | { 50 | //delete a; 51 | //delete b; 52 | } 53 | void Line::print() 54 | { 55 | cout << "Line: x1: " << a->x << " y1: " << a->y << " x2: " << b->x 56 | << " y2: " << b->y << "\t ID: " << id << endl; 57 | } 58 | double Line::value() 59 | { 60 | // calculate distance from midpoint at a given theta, 61 | // with resepct to the baseline 62 | 63 | //if( theta_cache != center->theta ) // check if our cached version is still fresh enough 64 | { 65 | //cout << "Recalculaing distance for line " << id << endl; 66 | distance(); 67 | } 68 | 69 | return dist; 70 | } 71 | void Line::updateCalcs() 72 | { 73 | // Find Slope and y-intercept of this line for future distance calculations 74 | double denom = (b->x - a->x); 75 | if( denom == 0 ) 76 | { 77 | //cout << "This program does not support perfectly verticle lines." << endl; 78 | //exit(0); 79 | 80 | // Perturb: 81 | // b->x = b->x + 1; 82 | denom = 0.000000001; //(b->x - a->x); 83 | } 84 | m = (b->y - a->y)/denom; 85 | 86 | // cout << m << " M " << endl; 87 | 88 | y_intercept = a->y - m*a->x; 89 | // cout << y_intercept << " m " << endl; 90 | } 91 | void Line::distance() 92 | { 93 | // First find the intesection of this line and the sweep line: 94 | double xi; 95 | double yi; 96 | center_intercept( xi, yi ); 97 | 98 | //cout << "The intercept is x: " << xi << " y: " << yi << endl; 99 | //cout << "M: " << m << " b: " << y_intercept << endl; 100 | 101 | // Now find the distance between these two lines: 102 | dist = sqrt( pow(center->x - xi, 2.0) + pow(center->y - yi,2.0) ); 103 | 104 | //cout << "Distance: " << dist << endl << endl; 105 | theta_cache = center->theta; 106 | } 107 | 108 | void Line::center_intercept(double &xi, double &yi) 109 | { 110 | xi = double( y_intercept - center_line->y_intercept ) / double( center_line->m - m ); 111 | yi = m*xi + y_intercept; 112 | } 113 | -------------------------------------------------------------------------------- /line.h: -------------------------------------------------------------------------------- 1 | #ifndef LINE_H_INCLUDED 2 | #define LINE_H_INCLUDED 3 | 4 | #include 5 | #include "point.h" 6 | #include "geometry.h" 7 | #include 8 | 9 | class Line: public Geometry 10 | { 11 | public: 12 | Point * a; 13 | Point * b; 14 | bool visitedStartPoint; // has the base/sweep line crossed at least one of 15 | // the verticies? 16 | bool visited; // has the sweep line been on the line (as in, maybe it was init on it) 17 | 18 | int id; 19 | double dist; // distance from center 20 | double theta_cache; // used for deciding if the dist cache needs to be refreshed 21 | double m; // slope of line 22 | double y_intercept; // y-intercept of line 23 | 24 | Line(); 25 | Line(int _x1, int _y1, int _x2, int _y2); 26 | ~Line(); 27 | virtual void print(); 28 | virtual double value(); 29 | 30 | void updateCalcs(); 31 | void distance(); 32 | void center_intercept(double &xi, double &yi); 33 | }; 34 | 35 | 36 | // This global needs to be visible to classes: 37 | extern Point * center; 38 | extern Line * center_line; 39 | extern double atomic; 40 | extern double atomic_space; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /node.h: -------------------------------------------------------------------------------- 1 | #include "line.h" 2 | 3 | //------------------------------------------------------------------------------------------- 4 | // Node Class 5 | //------------------------------------------------------------------------------------------- 6 | template 7 | class node{ 8 | public: 9 | node *below; // node below in tower 10 | node *next; // next node in skip list 11 | int level; // level of this current node 12 | int height; // full number of levels in tower 13 | T data; 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /plot.m: -------------------------------------------------------------------------------- 1 | clear 2 | clc 3 | 4 | data = csvread('data_space.cvs') 5 | 6 | n = data(:,1) 7 | logger1 = 7.*(n.^1); 8 | logger2 = 3.*(n.^1); 9 | 10 | loglog( data(:,1),data(:,2),'bo-', ... 11 | data(:,1),logger1,'k:',data(:,1),logger2,'k:') 12 | 13 | 14 | set(gca,'FontSize',14) 15 | 16 | legend('Numerical Results','O(n)','Location','NorthWest') 17 | xlabel('Input size, n') 18 | ylabel('Space Usage, S') 19 | title('Atomic Space Usage of Lee Visibility Graph Algorithm'); 20 | 21 | -------------------------------------------------------------------------------- /point.cpp: -------------------------------------------------------------------------------- 1 | #include "point.h" 2 | 3 | 4 | Point::Point() 5 | { 6 | static int id_counter = 0; 7 | id = id_counter++; 8 | } 9 | Point::Point(int _x1, int _y1) 10 | { 11 | x = _x1; 12 | y = _y1; 13 | Point(); 14 | } 15 | void Point::print() 16 | { 17 | std::cout << "Point x: " << x << " y: " << y << " \t ID: " << id << std::endl; 18 | } 19 | double Point::value() 20 | { 21 | // this is the angular distance from the base line 22 | // for point.cpp, we just cache the initial calculation 23 | return theta; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /point.h: -------------------------------------------------------------------------------- 1 | #ifndef POINT_H_INCLUDED 2 | #define POINT_H_INCLUDED 3 | 4 | #include 5 | #include "geometry.h" 6 | 7 | class Point: public Geometry 8 | { 9 | public: 10 | int x; 11 | int y; 12 | void* parentLine; 13 | int id; // for removing, comparing, etc 14 | double theta; // anglular amount from base line 15 | 16 | Point(); 17 | Point(int _x1, int _y1); 18 | 19 | virtual void print(); 20 | virtual double value(); 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /skiplist.h: -------------------------------------------------------------------------------- 1 | /* Skip List 2 | CSCI 5454 Algorithms 3 | Dave Coleman | david.t.coleman@colorado.edu 4 | 5 | 2/2/2012 6 | 7 | Implementation of Skip Lists 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "node.h" 14 | //#include "point.h" 15 | using namespace std; 16 | 17 | // ----------------------------------------------------------------------------------- 18 | // Skip List Class 19 | // ----------------------------------------------------------------------------------- 20 | template 21 | class skiplist{ 22 | // used for testing 23 | public: 24 | int maxLevel; 25 | 26 | private: 27 | node *root; 28 | 29 | // ----------------------------------------------------------------------------------- 30 | // Get Random Level 31 | // ----------------------------------------------------------------------------------- 32 | int getRandLevel() 33 | { 34 | int randResult = 1; 35 | int level = 0; 36 | while(randResult) 37 | { 38 | 39 | randResult = rand() % 2; 40 | if(randResult) 41 | { 42 | ++level; 43 | } 44 | 45 | if(level > maxLevel) 46 | { 47 | randResult = 0; // to end the while loop 48 | } 49 | } 50 | return level; 51 | 52 | } 53 | // ----------------------------------------------------------------------------------- 54 | // Create New Node 55 | // ----------------------------------------------------------------------------------- 56 | node* createNode( int level, int height, T data) 57 | { 58 | // Check if we are below level 0 59 | if(level < 0) 60 | { 61 | return NULL; 62 | } 63 | else // make a new node below 64 | { 65 | node *newNode = new node(); 66 | newNode->level = level; 67 | newNode->next = NULL; 68 | newNode->below = createNode( level - 1, height, data); 69 | newNode->height = height; 70 | newNode->data = data; 71 | 72 | atomic_space++; 73 | 74 | return newNode; 75 | } 76 | } 77 | 78 | public: 79 | 80 | // Constructor: 81 | skiplist() 82 | { 83 | root = NULL; 84 | maxLevel = 0; 85 | 86 | srand ( time(NULL) ); // seed the random generator 87 | } 88 | // ----------------------------------------------------------------------------------- 89 | // ADD 90 | // ----------------------------------------------------------------------------------- 91 | void add( T data) 92 | { 93 | //cout << "ADD: "; 94 | //data.print(); 95 | 96 | // Special Cases ------------------------------------------------------------------- 97 | 98 | if(!root) // no root has been established yet 99 | { 100 | root = createNode( 0, 0, data); 101 | return; 102 | } 103 | 104 | if( root->data->value() > data->value() ) // new value goes before root 105 | { 106 | T temp_data = root->data; 107 | node *n = root; 108 | 109 | for(int l = maxLevel; l >= 0; --l) 110 | { 111 | atomic += 1; 112 | // change the root to the new value 113 | n->data = data; 114 | n = n->below; 115 | } 116 | data = temp_data; 117 | } 118 | 119 | // Regular insert after root ------------------------------------------------------- 120 | 121 | // Determine what level this new node will be at 122 | int level = getRandLevel(); 123 | 124 | // If new node is at whole new level, go ahead and update root node to be higher 125 | if(level > maxLevel) 126 | { 127 | maxLevel ++; 128 | node *newRoot = new node(); 129 | newRoot->data = root->data; 130 | newRoot->next = NULL; 131 | newRoot->below = root; 132 | newRoot->level = maxLevel; 133 | root = newRoot; 134 | 135 | atomic_space++; 136 | } 137 | 138 | // Create the new node 139 | node *newNode = createNode( level, level, data); 140 | 141 | // Now add the node to the list 142 | node *i = root; 143 | 144 | // Loop down through all levels 145 | for(int l = maxLevel; l >= 0; --l) 146 | { 147 | atomic += 1; 148 | // move forward until we hit a value greater than ours 149 | while( i->next != NULL ) 150 | { 151 | atomic += 1; 152 | if( i->next->data->value() > data->value() ) // insert before i.next 153 | { 154 | break; 155 | } 156 | i = i->next; 157 | } 158 | 159 | // Check if we should add a pointer at this level 160 | if( l <= level ) 161 | { 162 | newNode->next = i->next; 163 | i->next = newNode; 164 | 165 | // Now move the new node pointer one level down: 166 | newNode = newNode->below; 167 | } 168 | 169 | // Always move the i node pointer one level down: 170 | i = i->below; 171 | } 172 | 173 | } 174 | // ----------------------------------------------------------------------------------- 175 | // Find 176 | // ----------------------------------------------------------------------------------- 177 | bool find(double x) 178 | { 179 | node *i = root; 180 | 181 | // Special case: skip list is empty 182 | if( !root ) 183 | { 184 | return false; 185 | } 186 | 187 | // Special case: check root 188 | if( root->data->value() == x) 189 | { 190 | return true; 191 | } 192 | 193 | for(int l = maxLevel; l >= 0; --l) 194 | { 195 | atomic += 1; 196 | // move forward until we hit a value greater than ours 197 | while( i->next != NULL ) 198 | { 199 | atomic += 1; 200 | if( i->next ->data->value() > x ) // x is not found on this level 201 | { 202 | break; 203 | } 204 | else if( i->next->data->value() == x ) // bingo! 205 | { 206 | return true; 207 | } 208 | 209 | i = i->next; 210 | } 211 | 212 | // Always move the i node pointer one level down: 213 | i = i->below; 214 | } 215 | 216 | return false; 217 | } 218 | // ----------------------------------------------------------------------------------- 219 | // REMOVE 220 | // the id is to confirm the correct node, just in case x is not unique 221 | // ----------------------------------------------------------------------------------- 222 | bool remove(double x, int id) 223 | { 224 | node *i = root; 225 | 226 | // Special case: remove root -------------------------------------------------------- 227 | if( root->data->value() == x && root->data->id == id) 228 | { 229 | // Get level 0 of root 230 | for(int l = root->level; l > 0; --l) 231 | { 232 | atomic += 1; 233 | atomic_space --; 234 | //cout << "Level " << l << endl; 235 | i = i->below; 236 | } 237 | 238 | // Check if there are any more nodes 239 | if( !i->next ) // the skip list is empty 240 | { 241 | root = NULL; 242 | maxLevel = 0; 243 | 244 | return true; 245 | } 246 | 247 | // Change value of root to next node 248 | node *n = root; 249 | node *nextNode = i->next; 250 | 251 | for(int l = maxLevel; l >= 0; --l) 252 | { 253 | atomic += 1; 254 | // change the root to the new value 255 | n->data = nextNode->data; 256 | 257 | // update next pointer if the next next exists 258 | if( n->next ) 259 | { 260 | n->next = n->next->next; 261 | } 262 | 263 | // Move down to next level 264 | n = n->below; 265 | } 266 | 267 | return true; 268 | } 269 | 270 | // Normal case: remove after root ----------------------------------------------- 271 | bool found = false; 272 | 273 | for(int l = maxLevel; l >= 0; --l) 274 | { 275 | atomic += 1; 276 | // move forward until we hit a value greater than ours 277 | while( i->next != NULL ) 278 | { 279 | atomic += 1; 280 | // remove this one, confirmed by id 281 | if( i->next->data->value() == x && i->next->data->id == id ) 282 | { 283 | found = true; 284 | atomic_space --; 285 | 286 | // pass through the pointer if exists 287 | if( i->next ) 288 | { 289 | i->next = i->next->next; 290 | } 291 | else 292 | { 293 | i->next = NULL; 294 | } 295 | break; 296 | } 297 | else if( i->next->data->value() > x ) // x is not found on this level 298 | { 299 | break; 300 | } 301 | 302 | i = i->next; 303 | } 304 | 305 | // Always move the i node pointer one level down: 306 | i = i->below; 307 | } 308 | 309 | return found; 310 | } 311 | // ----------------------------------------------------------------------------------- 312 | // POP FROM FRONT 313 | // ----------------------------------------------------------------------------------- 314 | T pop() 315 | { 316 | node *i = root; 317 | 318 | // Store the first item on the list that we want to later return 319 | T result = root->data; 320 | /* 321 | cout << "POP WITH VALUE: " << root->value << " - "; 322 | result.print(); 323 | cout << endl; 324 | */ 325 | 326 | // Check if skip list is empty 327 | if( !root ) 328 | { 329 | cout << "An error has occured: skip list is empty"; 330 | exit(1); 331 | } 332 | 333 | // Get level 0 of root 334 | for(int l = root->level; l > 0; --l) 335 | { 336 | atomic += 1; 337 | 338 | i = i->below; 339 | } 340 | 341 | // Check if there are any more nodes 342 | if( !i->next ) // the skip list is empty 343 | { 344 | root = NULL; 345 | maxLevel = 0; 346 | 347 | return result; 348 | } 349 | 350 | // Change value of root to next node 351 | node *n = root; 352 | node *nextNode = i->next; 353 | 354 | for(int l = maxLevel; l >= 0; --l) 355 | { 356 | atomic += 1; 357 | atomic_space --; 358 | // change the root to the new value 359 | n->data = nextNode->data; 360 | 361 | // update next pointer if the next next exists 362 | if( n->next ) 363 | { 364 | n->next = n->next->next; 365 | } 366 | 367 | // Move down to next level 368 | n = n->below; 369 | 370 | } 371 | 372 | return result; 373 | } 374 | // -------------------------------------------------------------------------------- 375 | // Is Root 376 | // ----------------------------------------------------------------------------------- 377 | bool isRoot(int id) 378 | { 379 | 380 | if( !root ) // there is no root! 381 | { 382 | std::cout << "there is no root!" << std::endl; 383 | return false; 384 | } 385 | return (root->data->id == id); 386 | } 387 | // ----------------------------------------------------------------------------------- 388 | // PRINT ALL 389 | // ----------------------------------------------------------------------------------- 390 | void printAll() 391 | { 392 | std::cout << std::endl << "LIST --------------------------------" << std::endl; 393 | 394 | // Special case: skiplist is empty 395 | if( !root ) 396 | { 397 | std::cout << "----------------------------------" << std::endl; 398 | return; 399 | } 400 | 401 | node i = *root; 402 | 403 | // Get level 0 of root 404 | for(int l = root->level; l > 0; --l) 405 | { 406 | //cout << "Level " << l << " - "; 407 | //i.data.print(); 408 | //cout << endl; 409 | i = *(i.below); 410 | } 411 | //std::cout << "we are on level " << i.level << std::endl; 412 | 413 | // Hack: update root 0 level with maxLevel count, because we don't update this 414 | // when growing root level size 415 | i.height = maxLevel; 416 | 417 | int counter = 0; 418 | bool done = false; 419 | 420 | while(!done) 421 | { 422 | std::cout << counter; 423 | 424 | for(int l = i.height; l >= 0; --l) 425 | { 426 | std::cout << " | "; 427 | } 428 | std::cout << " " << i.data->value() << " - "; 429 | i.data->print(); 430 | 431 | counter ++; 432 | 433 | if( i.next ) 434 | { 435 | node *ii = i.next; 436 | i = *ii; 437 | } 438 | else 439 | { 440 | done = true; 441 | } 442 | } 443 | 444 | std::cout << "-------------------------------------" << std::endl << std::endl; 445 | } 446 | }; 447 | -------------------------------------------------------------------------------- /vgraph.cpp: -------------------------------------------------------------------------------- 1 | #include "CImg.h"// Include CImg library header. 2 | #include 3 | #include "line.h" 4 | #include "point.h" 5 | #include "skiplist.h" 6 | #include 7 | 8 | using namespace cimg_library; 9 | using namespace std; 10 | 11 | const unsigned char WHITE[] = { 255, 255, 255 }; 12 | const unsigned char GREY[] = { 100, 100, 100 }; 13 | const unsigned char BLACK[] = { 0, 0, 0 }; 14 | const unsigned char RED[] = { 255, 0, 0 }; 15 | const unsigned char GREEN[] = { 0, 255, 0 }; 16 | const unsigned char BLUE[] = { 0, 0, 255}; 17 | const int screen_size = 800; 18 | //const int screen_size = 400; 19 | 20 | //------------------------------------------------------------------------------- 21 | // Prototypes 22 | //------------------------------------------------------------------------------- 23 | void vgraph(double order); 24 | double vectorsAngle( int x, int y, int basex, int basey); 25 | double distance( Point * a, Point * b ); 26 | 27 | //------------------------------------------------------------------------------- 28 | // Main procedure 29 | //------------------------------------------------------------------------------- 30 | int main() 31 | { 32 | cout << endl << endl << "Visibility Graph by Dave Coleman -------------------- " << endl << endl; 33 | 34 | for( double order = 1; order < 2; order += 0.5 ) 35 | { 36 | vgraph(order); 37 | } 38 | 39 | return EXIT_SUCCESS; 40 | } 41 | 42 | void vgraph(double order) 43 | { 44 | // Variables ---------------------------------------------------------------- 45 | 46 | // Atomic operation counter 47 | atomic = 0; 48 | double total_atomic_space = 0; 49 | 50 | // Graphics: 51 | bool visual = true; 52 | bool live = true; 53 | 54 | CImg img(screen_size,screen_size,1,3,20); 55 | CImgDisplay disp(img, "Visibility Graph"); // Display the modified image on the screen 56 | 57 | // Line segments: 58 | int size = pow(10.0, order); 59 | int row_col = sqrt(size); 60 | int seg = row_col * row_col; 61 | 62 | // Coordinates: 63 | double width = screen_size / row_col; // size of each grid box 64 | double margin = 0.1 * width; // padding inside each box 65 | double top, bottom, left, right; // coordinates of box with padding 66 | 67 | // Generate space for SEG number of lines 68 | Line * segs[seg]; 69 | 70 | // Track what index we are on 71 | int index = 0; 72 | 73 | // Now generate seg line segments 74 | for(int x = 0; x < row_col; ++x) 75 | { 76 | for(int y = 0; y < row_col; ++y) 77 | { 78 | top = y*width + margin; 79 | bottom = (y+1)*width - margin; 80 | left = x*width + margin; 81 | right = (x+1)*width - margin; 82 | 83 | // Create line segment in box of size width*width 84 | // x1, y1, x2, y2 85 | switch( rand() % 4 ) 86 | { 87 | case 0: // verticle line 88 | segs[index] = new Line( left, top, left, bottom ); 89 | break; 90 | case 1: // horizontal line 91 | segs[index] = new Line( left, top, right, top ); 92 | break; 93 | case 2: // diagonal left to right 94 | segs[index] = new Line( left, top, right, bottom ); 95 | break; 96 | case 3: 97 | segs[index] = new Line( left, bottom, right, top ); 98 | break; 99 | } 100 | 101 | index++; 102 | } 103 | } 104 | 105 | //cout << "SEGS " << seg << " INDEX " << index << endl; 106 | 107 | /* 108 | Line segs[] = 109 | { 110 | Line(280,300,330,120), // 0 first 111 | Line(450,150,280,330), // 1 second 112 | Line(400,150,401,190), // 2 third, later 113 | Line(400,400,450,200), // 3 far right 114 | Line(350,350,350,450), // 4 115 | Line(10,200,100,215), // 5 116 | Line(50,50,50,100), // 6 117 | Line(200,450,300,450) // 7 118 | }; 119 | */ 120 | 121 | // Reusable pointer locations 122 | Line * l; 123 | Point * p; 124 | 125 | int center_id; 126 | bool isPointA; 127 | 128 | // Visit each vertex once and perform the visibility algorithm 129 | for(int outer = 0; outer < 2*seg; ++outer) 130 | { 131 | ++atomic; 132 | atomic_space = 0; 133 | 134 | // First or second number on each line? 135 | center_id = outer / 2; 136 | 137 | // Garbage Collect 138 | if( outer ) 139 | { 140 | delete center; 141 | delete center_line; 142 | } 143 | 144 | //cout << "LINE ID: " << center_id << endl; 145 | if( ! (outer % 2) ) // is even 146 | { 147 | center = new Point( segs[center_id]->a->x, segs[center_id]->a->y ); 148 | isPointA = true; 149 | } 150 | else // is even 151 | { 152 | center = new Point( segs[center_id]->b->x, segs[center_id]->b->y ); 153 | isPointA = false; 154 | } 155 | 156 | // Center Line Calc: 157 | center_line = new Line( center->x, center->y, center->x+1, center->y ); 158 | 159 | // Add pointers to all points back to parent line 160 | center->parentLine = segs[center_id]; 161 | 162 | // Draw sweeper: 163 | //img.draw_line( center->x, center->y, center->x+200, center->y, RED); 164 | if(visual) 165 | img.draw_circle( center->x, center->y, 6, RED); 166 | 167 | /*cout << "LINE ID " << center_id << " "; 168 | if(isPointA) 169 | cout << "A" << endl; 170 | else 171 | cout << "B" << endl; 172 | */ 173 | 174 | // Datastructures: 175 | skiplist angleList; 176 | skiplist edgeList; 177 | 178 | // Algorithm ----------------------------------------------------------------- 179 | 180 | // Draw segments and insert POINTS into skiplist ordered by ANGLE ------------- 181 | for(int i = 0; i < seg; ++i) 182 | { 183 | ++atomic; 184 | l = segs[i]; 185 | 186 | // Add pointers to all points back to parent line 187 | l->a->parentLine = l; 188 | l->b->parentLine = l; 189 | 190 | // Reset visited flags 191 | l->visited = false; 192 | l->visitedStartPoint = false; 193 | 194 | if(visual) 195 | img.draw_line(l->a->x, l->a->y, l->b->x, l->b->y, WHITE); 196 | 197 | if( !(i == center_id && isPointA) ) // point is not line A 198 | { 199 | if(visual) 200 | img.draw_circle(l->a->x, l->a->y, 2, WHITE); 201 | 202 | // Calculate the angle from center line: 203 | l->a->theta = vectorsAngle( l->a->x, l->a->y, center->x, center->y ); 204 | 205 | // Sort the verticies: 206 | angleList.add( l->a); 207 | 208 | //cout << "Added A for line " << i << " theta " << l->a->theta << endl; 209 | //cout << "POINT "; l->a->print(); cout << endl; 210 | } 211 | 212 | if( !(i == center_id && isPointA == false) ) // point is not line B 213 | { 214 | if(visual) 215 | img.draw_circle(l->b->x, l->b->y, 2, WHITE); 216 | 217 | // Calculate the angle from center line: 218 | l->b->theta = vectorsAngle( l->b->x, l->b->y, center->x, center->y ); 219 | 220 | // Sort the verticies: 221 | angleList.add( l->b); 222 | //cout << "Added B for line " << i << " theta " << l->b->theta << endl; 223 | 224 | //cout << "POINT "; l->b->print(); cout << endl; 225 | } 226 | 227 | //cout << endl; 228 | } 229 | 230 | //disp.display(img); 231 | //img.save("result.png"); // save the image 232 | //break; 233 | // Test SkipList 234 | //cout << "Angle List - points ordered CC from base line"; 235 | //angleList.printAll(); 236 | 237 | 238 | // Initialize Edge List Of Lines ----------------------------------------------------- 239 | for(int i = 0; i < seg; ++i) 240 | { 241 | ++atomic; 242 | 243 | l = segs[i]; // get next line to check 244 | 245 | // check if the current line is connected to the center point 246 | if( l->id == ((Line*)center->parentLine)->id ) 247 | { 248 | // one center's line 249 | //cout << "ONE CENTER'S LINE!!!" << endl; 250 | } 251 | else 252 | { 253 | // Check each line and see if it crosses scan line 254 | double xi, yi; 255 | l->center_intercept( xi, yi ); // these are reference parameters 256 | 257 | // Now we know that xi,yi is on center line. 258 | // Next we check if X is between a & b. We know a.x > b.x, thus: 259 | if( l->a->x >= xi && l->b->x <= xi ) 260 | { 261 | // check that xi > center->x 262 | if( xi >= center->x ) 263 | { 264 | 265 | // It does intersect 266 | edgeList.add( l ); 267 | 268 | // Mark as opened, somewhere on line 269 | l->visited = true; 270 | 271 | // Visualize: 272 | if(visual) 273 | img.draw_line(l->a->x, l->a->y, l->b->x, l->b->y, GREEN); 274 | } 275 | } 276 | } 277 | } 278 | 279 | if(live) 280 | disp.display(img); 281 | 282 | //cout << "Edge List:"; 283 | //edgeList.printAll(); 284 | 285 | // Sweep -------------------------------------------------------------- 286 | 287 | //sleep(1); 288 | //usleep(500*1000); 289 | for(int i = 0; i < 2*seg - 1; ++i) 290 | { 291 | ++atomic; 292 | // get max atomic space 293 | if( total_atomic_space < atomic_space ) 294 | total_atomic_space = atomic_space; 295 | 296 | 297 | //cout << "\n\n\n --------------- STARTING NEW SWEEP ------------------ \n\n\n"; 298 | 299 | //cout << "SWEEP VERTEX " << i << endl; 300 | //if( i > 0 ) 301 | // break; 302 | 303 | // take the first vertex in angular order 304 | p = angleList.pop(); 305 | //cout << "Sweep at "; p->print(); 306 | 307 | // Update the center_line to the sweep location and update m,b 308 | center_line->b = p; 309 | center_line->updateCalcs(); 310 | 311 | // Update center point to contain theta between baseline and 312 | // current point, so that our line function can cache 313 | center->theta = p->theta; 314 | 315 | // decide what to do with it 316 | l = (Line*)p->parentLine; // cast it 317 | //cout << "\t"; l->print(); 318 | 319 | // check if the current line is connected to the center point 320 | if( l->id == ((Line*)center->parentLine)->id ) 321 | { 322 | // one center's line 323 | // ignore 324 | } 325 | else if( l->visited ) // remove it from edgeList 326 | { 327 | //cout << "remove" << endl; 328 | 329 | if( ! l->visitedStartPoint ) 330 | { 331 | l->visited = false; // allow this line to be visisted again for its start point 332 | } 333 | 334 | // check if its first in the edge list. if it is, its VISIBLE 335 | if( edgeList.isRoot( l->id ) ) 336 | { 337 | //cout << "Drawing Line" << endl; 338 | 339 | if(visual) 340 | img.draw_line( center->x, center->y, p->x, p->y, BLUE ); 341 | } 342 | 343 | // remove 344 | //cout << "Value: " << l->value() << " " << l->id << endl; 345 | 346 | edgeList.remove( l->value(), l->id ); 347 | 348 | if(visual) 349 | img.draw_line(l->a->x, l->a->y, l->b->x, l->b->y, WHITE); 350 | } 351 | else // add it to edge list 352 | { 353 | //cout << "add" << endl; 354 | l->visited = true; // mark it as having been visited somewhere 355 | l->visitedStartPoint = true; // mark it as having found the first vertex 356 | 357 | // Store distance of line from center 358 | l->dist = distance( p, center ); 359 | 360 | edgeList.add( l ); 361 | 362 | // check if its first in the edge list. if it is, its VISIBLE 363 | if( edgeList.isRoot( l->id ) ) 364 | { 365 | //cout << "Drawing Line" << endl; 366 | if(visual) 367 | img.draw_line( center->x, center->y, p->x, p->y, BLUE ); 368 | } 369 | 370 | if(visual) 371 | img.draw_line(l->a->x, l->a->y, l->b->x, l->b->y, GREEN); 372 | } 373 | 374 | if(visual) 375 | img.draw_circle(p->x, p->y, 5, GREY); 376 | 377 | //debug 378 | //cout << "Edge List:"; 379 | //edgeList.printAll(); 380 | //angleList.printAll(); 381 | //cout << endl << endl; 382 | 383 | if(live) 384 | { 385 | disp.display(img); 386 | //usleep(1*1000); 387 | //sleep(1); 388 | } 389 | } 390 | //cout << "breaking" << endl; 391 | //break; 392 | if(live) 393 | { 394 | //usleep(1*1000); 395 | disp.display(img); 396 | } 397 | 398 | //img.fill(20); 399 | //cout << outer << endl; 400 | } 401 | 402 | if(visual) 403 | { 404 | // Redraw obstacle lines just for fun: 405 | for(int i = 0; i < seg; ++i) 406 | { 407 | l = segs[i]; 408 | 409 | img.draw_line(l->a->x, l->a->y, l->b->x, l->b->y, WHITE); 410 | img.draw_circle(l->a->x, l->a->y, 2, WHITE); 411 | img.draw_circle(l->b->x, l->b->y, 2, WHITE); 412 | } 413 | disp.display(img); 414 | 415 | 416 | img.save("result.png"); // save the image 417 | } 418 | 419 | cout << seg << "," << total_atomic_space << endl; 420 | 421 | if(visual) 422 | { 423 | // Show window until user input: 424 | while (!disp.is_closed()) { 425 | if (disp.is_keyESC() ) 426 | break; 427 | disp.wait(); 428 | } 429 | } 430 | 431 | // Garabage collect 432 | //delete [] segs; 433 | //free(segs); 434 | } 435 | 436 | //------------------------------------------------------------------------------- 437 | // Calculate Angle Btw 2 Vectors 438 | //------------------------------------------------------------------------------- 439 | double vectorsAngle( int x, int y, int basex, int basey) 440 | { 441 | // Convert input point x & y to be vectors relative to base point 442 | double x2 = double(x - basex); 443 | double y2 = double(y - basey); 444 | 445 | // Hard code scan line to point right: 446 | double x1 = sqrt( x2*x2 + y2*y2 ); // make it with ratio? 447 | double y1 = 0.0; 448 | 449 | //cout << "x1: " << x1 << " - y1: " << y1 << endl; 450 | //cout << "x2: " << x2 << " - y2: " << y2 << endl; 451 | 452 | double stuff = ( (x1*x2)+(y1*y2) ) / ( sqrt(x1*x1+y1*y1) * sqrt(x2*x2+y2*y2) ); 453 | //cout << "Stuff: " << stuff << endl; 454 | 455 | // Calculate angle: 456 | double result = acos( stuff ); 457 | //cout << "Result: " << result << endl; 458 | 459 | // Now add PI if below middle line: 460 | if( y >= basey ) 461 | result = 2*M_PI - result; 462 | 463 | //cout << "Result: " << result*180/M_PI << " degrees" << endl; 464 | 465 | return result; 466 | } 467 | //------------------------------------------------------------------------------- 468 | // Distance Btw 2 Points 469 | //------------------------------------------------------------------------------- 470 | double distance( Point * a, Point * b ) 471 | { 472 | return sqrt( pow(b->x - a->x, 2.0) + pow(b->y - a->y,2.0) ); 473 | } 474 | -------------------------------------------------------------------------------- /vgraph.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.vgraph 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | --------------------------------------------------------------------------------