340 likes | 572 Views
Strukture podataka i algoritmi. Elementarne geometrijske metode. (Elementary Geometric Methods). Branimir Sigl. Općenito o geometrijskim algoritmima. rješavaju mnoge probleme iz područja matematike i statistike korišteni za razne druge tipove problema
E N D
Strukture podataka i algoritmi Elementarne geometrijske metode (Elementary Geometric Methods) Branimir Sigl
Općenito o geometrijskim algoritmima • rješavaju mnoge probleme iz područja matematike i statistike • korišteni za razne druge tipove problema • npr. “gerrymandering” - podjela okruga na dijelove sa jednakom populacijom • problemi se lako se vizualiziraju (nedostatak?) • neki problemi su naizgled laki, ali imaju komplicirane algoritme za rješavanje • Presijecanje, zatvorena petlja, odnos točke i poligona
Strukture podataka • točka, linija, poligon class point, class line, class drawing vector <point> points • Polygon ==> set of points • Polygon ==> set of lines • Visual Basic / C++ communication DLL struct vbPoint, vbLine
Strukture podataka class point { public: long x, y; point() : x(-1), y(-1) { } point(vbPoint p): x(p.x), y(p.y) { } point(const point &p): x(p.x), y(p.y) { } point(long coordX, long coordY): x(coordX), y(coordY) { } friendostream& operator <<(ostream& o, const point& p) {return o << "(" << p.x << ", " << p.y << ")"; } operator vbPoint(); point operator =(const point &p); bool operator ==(const point &p) const; bool operator <(const point &p) const; };
Međusobno presijecanje linija • osnovni problem - presjek linija • METODA 1: • pronaći točku presijecanja • provjeriti je li točka između krajnjih točaka linija
Međusobno presijecanje linija (ccw) • METODA 2: • ccw - counterclockwise long intersect::ccw (point p0, point p1, point p2) { p2 p1 p2’ p0 • ako je nagib druge linije veći suprotno kazaljci na satu (ccw) • ako je nagib druge linije manji kao kazaljka na satu (cw)
Međusobno presijecanje linija (ccw) • vrijednosti funkcije ccw: • true suprotno kazaljci (ccw) • false u smjeru kazaljke (cw) • problem: linije mogu biti kolinearne • ako su točke kolinearne, onda ne možemo definirati cw/ccw • 1 1 između 0 i 2 • -1 0 između 1 i 2 • 0 2 između 0 i 1
Međusobno presijecanje linija (ccw) long intersect::ccw (point p0, point p1, point p2) { long dx1, dy1, dx2, dy2; dx1 = p1.x - p0.x; dy1 = p1.y - p0.y; dx2 = p2.x - p0.x; dy2 = p2.y - p0.y; if (dx1 * dy2 > dy1 * dx2) return 1; if (dx1 * dy2 < dy1 * dx2) return -1; if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) return -1; // 0 if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2)) // 1return 1; return 0; // 2 }
Međusobno presijecanje linija (ccw) • Numeričke komplikacije: • Umnošci: long dx1, dx2, dy1, dy2; dx1 * dy2; dy1 * dx2;dx1 * dx2;dy1 * dy2 • umnožak dvije longvarijable je long varijabla - PROBLEM !! • ako je jedan od faktora LONG_MAX tada umnožak nije dobar • problem se pojavljuje kod algoritma ”Odnos točke i poligona” • potrebno je odrediti dovoljno velik broj ?! npr. SHRT_MAX koji ne stvara preljev kod umnoška dva long broja
B C A D Međusobno presijecanje linija (intersect) • algoritam INTERSECT: • ako su točke na suprotnim stranama linije, tada se linije sijeku
B C A D Međusobno presijecanje linija (intersect) • algoritam INTERSECT: • ako su točke na suprotnim stranama linije, tada se linije sijeku
Međusobno presijecanje linija Sedgewick: bool intersect::operator () (line l1, line l2) { return ( ( ccw(l1.p1, l1.p2, l2.p1) * ccw(l1.p1, l1.p2, l2.p2) <= 0 ) && ( ccw(l2.p1, l2.p2, l1.p1) * ccw(l2.p1, l2.p2, l1.p2) <= 0 )) ;
Međusobno presijecanje linija • algoritam nije u potpunosti točan • kada je točka T2 kolinearna sa točkama T0 i T1 rezultat funckije ccw = 0 • Potrebne promjene Sedgewick-ovog algoritma • Dovoljno je da jedna od četiri kombinacije bude jednaka nuli, tada je sigurno da se linije sijeku
Međusobno presijecanje linija (promjene) Nakon izmjena: bool intersect::operator () (line l1, line l2) { c11 = ccw(l1.p1, l1.p2, l2.p1); c12 = ccw(l1.p1, l1.p2, l2.p2); c21 = ccw(l2.p1, l2.p2, l1.p1); c22 = ccw(l2.p1, l2.p2, l1.p2); return (( c11 * c12 < 0 ) && ( c21 * c22 < 0 )) || c11 * c12 * c21 * c22 == 0 ;
Jednostavna zatvorena petlja • PROBLEM: • pronaći put kroz sve točke, bez presijecanja i vratiti se u početnu točku (Simple Closed Path) • točke = gradovi, kuće? • Travelling Salesman Problem - pronalazak najboljeg puta - puno kompliciraniji • rješenje našeg problema: • pronaći “SIDRO” • izračunati kuteve prema ostalim točkama • sortirati niz kuteva
Jednostavna zatvorena petlja sidro (anchor) ?
Jednostavna zatvorena petlja • kut koji je potreban za algoritam : tan-1 dy/dx • korištenje funkcije tan-1 nije isplativo: • dx != 0 • ispitivanje kvadranta • potrebno je pronaći sličnu funkciju • dy / (dx + dy) uz mala poboljšanja • u nekim programskim okruženjima bolje je koristiti trigonometrijske funkcije
Jednostavna zatvorena petlja typedefmultimap <float, point, less<float> > MAPPOINT; typedef MAPPOINT::value_type PATHPAIR; PATHPAIR theta::operator ()( point p2) { long dx, dy, ax, ay; float t; dx = p2.x - p1.x; dy = p2.y - p1.y; ax = abs(dx); ay = abs(dy); t = (ax + ay == 0) ? 0. : (float) dy / (ax + ay); if (dx < 0) t = 2. - t; else if (dy < 0) t = 4. + t; return PATHPAIR(t * 90., p2); }
Jednostavna zatvorena petlja typedefset<point, less<point> > SETPOINT; vector<vbPoint> drawing::calcPath() { SETPOINT tmp; MAPPOINT path; vector<vbPoint> r ; . . . . theta tht(*tmp.begin()); iS = tmp.begin(); while(iS != tmp.end()) { path.insert( tht(*iS) ); iS++; } . . . . return r; }
Jednostavna zatvorena petlja 0° sidro (anchor)
Odnos točke i poligona • PROBLEM: • odrediti je li zadana točka izvan ili unutar poligona? • RJEŠENJE: • povući dovoljno dugačku liniju iz točke u bilo kojem pravcu • prebrojati linije poligona s kojima se sječe • PARAN BROJ sjecišta - točka IZVAN POLIGONA • NEPARAN BROJ sjecišta - točka UNUTAR POLIGONA • izgleda jednostavno? nije baš . . . . .
Odnos točke i poligona • Sjecišta na rubovima • Paralelne linije
Odnos točke i poligona • algoritam: • putujemo po točkama poligona • inkrementiramo brojač svaki put kada testna linija presječe liniju poligona • ako je broj presijecanja paran, točka je IZVAN • ako je broj presijecanja neparan, točka je UNUTAR • ignoriramo točke koje padaju na testnu liniju
Odnos točke i poligona long drawing::inside(point t, vbPoint ap[ARRAYSIZE]) { line lp, lt(t, t); lt.p2.x = MAX_SHRT; // problem u ccw algoritmu . . . . tmp.insert(tmp.begin(), *tmp.rbegin()); // p[0] = p[N] tmp.push_back(tmp[1]); // p[N+1] = p[1] for(i = 1; i <= N; i++) { lp.p1 = tmp[i]; lp.p2 = tmp[i]; if (!intersection(lp, lt);) { lp.p2 = tmp[j]; j = i; if (intersection(lp, lt)) count++; } } return count & 1;
Odnos točke i poligona ( problem 1 ) • Algoritam nije u potpunosti točan • ako točka leži na bridu, da li je unutar / izvan poligona ? • problem sa ignoriranjem točke na testnoj liniji • problem zbog nekontroliranja nulte (n-te) točke • Problem 1: • ako se točka nalazi na bridu poligona, točka je UNUTAR D C T1 Prema Sedgewickovom algoritmu, točka T1 se nalazi unutar poligona, a točka T2 se ne nalazi T2 B A
Odnos točke i poligona ( problem 2 ) • Problem 2: • algoritam pamti vrijednost j koja se ne nalazi na testnoj liniji i slijedeću točku i koja nije na testnoj liniji • Ako se točke p[i] i p[j] nalaze sa suprotnih strana testne linije => counter se povećava za jedan D C = p[j] Prema Sedgewickovom algoritmu, točka T se ne bi nalazila unutar poligona B T A = p[i]
Odnos točke i poligona ( problem 3 ) • Problem 3: • algoritam počinje provjeru sa segmentom p[0]p[1], ali ne provjerava da li se točka p[0] nalazi na testnoj liniji • Točku p[N] algoritam ne tretira jer se nalazi na testnom segmentu ==> potrebno je smanjiti counter za jedan T D = p[0] = p[N] C Prema Sedgewickovom algoritmu, točka T se ne bi nalazila unutar poligona A = p[1]
Odnos točke i poligona ( promjena 1 ) . . . . for(i = 1; i <= N; i++) { lp.p1 = tmp[i]; /*NEW*/ lp.p2 = tmp[i-1]; /*NEW*/ b = intersect(lv, lp); /*NEW*/ if (b) /*NEW*/ return true; lp.p2 = tmp[i]; b = intersect(lp, lt); if (!b) { . . . .
Odnos točke i poligona ( promjena 2 ) . . . . b = intersect(lp, lt); if(b) { count++; /*NEW*/ } else { /*NEW*/ if ( (i!=j+1) && /*NEW*/ (intersect(lt.p1, lt.p2, tmp[j]) * /*NEW*/ intersect(lt.p1, lt.p2, tmp[i]) < 1) ) /*NEW*/ count++; /*NEW*/ } j = i; . . . .
Odnos točke i poligona ( promjena 3 ) . . . . /*NEW*/ if( (j!=N) && /*NEW*/ (intersect(lt.p1, lt.p2, tmp[j]) * /*NEW*/ intersect(lt.p1, lt.p2, tmp[1]) == 1) ) /*NEW*/ count--; return count & 1; }
Odnos točke i poligona sidro(anchor)
Zaključak • podcjenjivanje složenosti geometrijskih algoritama • koriste se u razne druge svrhe • mnogi geometrijski algoritmi ovdje nisu niti spomenuti • jednostavan alat, uvod u složenije algoritme • C++ je dobar za ilustraciju danih algoritama,strukture podataka lako se prikazuju u C++ • tekstovi o C++ često se koriste geometrijskim algoritmima u pokazivanju svojih mogućnosti
LINKOVI: http://condor.informatik.uni-oldenburg.de/ ~stueker/graphic/ http://www.enseignement.polytechnique.fr/profs/ informatique/Jean-Jacques.Levy/00/pc10/a10.html http://www.cs.princeton.edu/courses/archive/ spring02/cs226/lectures/geo.4up.pdf http://www.cee.hw.ac.uk/~alison/ds98/node111.html http://m3.polymtl.ca/ele6813/notes/chap7/chap7.html