Sunteți pe pagina 1din 20

Geometrie computațională)

Geometria computațională are nenumărate aplicații în informatică:

 robotică, roboți autonomi, machine vision


 grafică 2D (hărți, GPS, probleme de vizibilitate pe segmente și dreptunghiuri)
 grafică 3D (jocuri)
 modelarea 3D a moleculelor în căutarea de medicamente
Elemente de geometrie analitică
Ecuația dreptei
Ecuația dreptei poate fi exprimată în multe forme:

 este dreapta care trece prin punctele și .

 este dreapta care trece prin punctul și are


pantă . Panta este tangenta unghiului format de dreaptă cu axa Ox.

 (numită în engleză slope + y-intercept) este dreapta care trece prin

punctul și are pantă .

 (numită în engleză x-intercept + y-intercept) este dreapta

care taie axele Ox și Oy în punctele și

Aceste formule se demonstrează prin asemănarea triunghiurilor dreptunghice. Toate se


pot rescrie în forma generală a ecuației dreptei,

De expandat: ecuații parametrice și vectoriale.

Panta unei drepte

Dându-se o dreaptă prin ecuația generală ax + by + c = 0, panta dreptei este . Putem

observa aceasta rescriind ecuația ca , care corespunde formei slope + y-


intercept.

Intersecția a două drepte

Date fiind două drepte, ax + by + c = 0 și dx + ey + f = 0, punctul lor de intersecție se


determină, evident, rezolvând sistemul de ecuații în x și y.
Drepte paralele, perpendiculare

Două drepte sunt paralele când formează unghiuri egale cu orizontala, adică au pante

egale: sau

Două drepte sunt perpendiculare când produsul pantelor este egal cu -

1: sau

Schiță de demonstrație: vezi figura. Fie dreptele și cu pantele și . Din


punctul de intersecție, P, construim punctele Q și R. Remarcăm că Q și R sunt pe aceeași
verticală. Reținem că este negativ. Cum triunghiul PQR este dreptunghic, aplicăm
teorema lui pitagora:

Separarea planului

Evident, expresia ax + by + c va fi zero pentru toate punctele (x, y) de pe dreaptă (în mod
tautologic). Ce este interesant este că expresia are valori pozitive pentru toate punctele de
o parte a dreptei și valori negative pentru toate punctele de cealaltă parte a dreptei.

De care parte? Nu putem spune exact, căci dreapta ax + by + c este confundată cu


dreapta - ax - by - c, care are semnele schimbate. Dar tot ce contează este ca programul
vostru să proceseze consecvent toate dreptele.
Test de orientare

O întrebare frecventă este: dându-se trei puncte A, B, și C, sunt ele (a) date în ordine
trigonometrică sau (b) date în ordine orară sau (c) coliniare?

Putem reformula întrebarea în două feluri echivalente:

 Dându-se A, B și C, segmentul BC cotește, față de segmentul AB, (a) la stânga sau


(b) la dreapta sau (c) nu cotește?
 Dându-se A, B și C, punctul C este, față de segmentul orientat AB, (a) la stânga
sau (b) la dreapta sau (c) pe linie?

Putem răspunde la întrebare muncitorește: calculăm ecuația dreptei AB sub forma ax + by


+ c = 0 și înlocuim coordonatele punctului C în această ecuație. Mai simplu, Pornim de la
ecuația dreptei care trece prin două puncte, trecem totul în partea stângă și
înlocuim x și y cu xC și yC. Obținem:

Putem exprima mai elegant această formulă printr-un determinant:

 Dacă determinantul este pozitiv, punctele sunt date în ordine trigonometrică


(traiectoria ABC cotește la stânga).
 Dacă determinantul este negativ, punctele sunt date în ordine orară (traiectoria
ABC cotește la dreapta).
 Dacă determinantul este zero, punctele sunt coliniare.
Observații privind implementarea

Cazuri particulare

O bună parte din arta implementării unui algoritm de geometrie computațională este
tratarea cazurilor particulare:

 coliniaritate
 intersecții exact la un capăt al segmentului
 pante infinite (pentru drepte verticale)
Uneori puteți elimina cazurile particulare scriind bine formula. Exemplu: două

puncte și sunt coliniare cu originea dacă . Dar această


formulă are cazuri particulare: fracțiile sunt nedefinite când sau sunt 0. Așadar,
implementarea de mai jos este greșită.

if (y1 / x1 == y2 / x2) {
...
}

Putem trata punctele de pe axa Ox printr-un caz particular, sau, mai simplu, putem înlocui
formula cu una echivalentă, dar fără împărțiri:

if (y1 * x2 == y2 * x1) {
...
}

De expandat: Funcții ca atan2(), care gestionează și cazuri particulare.

Erori de calcul

În gcc, tipurile float, double și long double au 4, 8 și respectiv 16 octeți. Țineți minte aceste
numere ca să vă puteți face necesarul de memorie.

Indiferent de precizie, în funcție de problemă puteți ajunge la valori ușor diferite pentru
formule teoretic egale, în funcție de ordinea operațiilor. De aceea poate fi mai sănătos să
nu testați egalitatea cu

if (x == y) {
...
}

, ci cu

if (fabs(x - y) < 1e-5) {


...
}

Funcțiile de valoare absolută


sunt fabsf() pentru float, fabs() pentru double și fabsl pentru long double. Încă un motiv să
lucrați în GNU/Linux, nu în Windows: paginile de manual includ toată documentația pentru
GCC.

Operații costisitoare

Țineți minte că adunarea / scăderea, înmulțirea, împărțirea, sqrt, sin / cos, log / exp sunt
funcții tot mai costisitoare. Întrebați-vă mereu cum puteți rescrie o formulă pentru a folosi
operații cât mai de la începutul listei.

Algoritmul lui Bresenham (pentru segmente)

Pentru a exemplifica observațiile de mai sus, vom discuta algoritmul lui Bresenham. El
trasează un segment între doi pixeli (puncte de coordonate întregi) (x1, y1) și (x2, y2). Se
pune, deci, problema enumerării tuturor pixelilor segmentului.

Pentru simplitate, presupunem că segmentul este în primul octant, adică formează un


unghi între 0 și 45° cu orizontala. Celelalte 7 cazuri se tratează similar. Ce este special în
primul octant? După afișarea punctului (x, y), următorul punct afișat va fi fie (x + 1, y), fie
(x + 1, y + 1). Deci algoritmul are de luat o decizie relativ ușoară la fiecare avansare a
lui x.

Algoritmul naiv spune: datorită unghiului, toți pixelii au coordonata x diferită. Iterăm deci de
la x1 la x2 și calculăm coordonata y corectă pe acea coloană. Ea se obține rotunjind
coordonata y teoretică la cel mai apropiat întreg.

for (int x = x1; x <= x2; x++) {


y = (double)(y2 - y1) / (x2 - x1) * (x - x1) + y1;
int yint = round(y);
// afișează pixelul (x, yint)
}

Acest algoritm face împărțiri pe numere reale, care sunt scumpe.

O variantă mai bună precalculează panta și face împărțiri și înmulțiri înainte de bucla
principală, iar în buclă face doar adunări. Ideea este că, de câte ori x crește cu 1, y crește
cu valoarea pantei. Apoi yeste rotunjit la cel mai apropiat inel.

double p = (double)(y2 - y1) / (x2 - x1);


double y = y1;
for (int x = x1; x <= x2; x++) {
int yint = round(y);
// afișează pixelul (x, yint)
y += panta;
}

Pentru următoarea variantă, nu mai reținem coordonata reală y, ci coordonata întreagă și


abaterea dintre cele două, care va fi mereu cuprinsă între -0.5 și 0.5. Nu obținem nicio
îmbunătățire de viteză, dar pregătim terenul pentru ultima variantă, care operează doar pe
variabile întregi.

double p = (double)(y2 - y1) / (x2 - x1);


double abatere = 0.0;
int y = y1;
for (int x = x1; x <= x2; x++) {
// afișează pixelul (x, y)
abatere += panta;
if (abatere > 0.5) {
y++;
abatere -= 1;
}
}

În sfârșit, dorim să înlocuim variabilele reale p și abatere cu variabile întregi. Pentru


acestea, amplificăm toate operațiile pe ele cu x2 - x1. Atunci p devine y2 - y1. Atenție, și
constantele 0.5 și 1 trebuie amplificate! Iar pentru a elimina constanta 0.5, amplificăm
testul de inegalitate cu 2.

int abatere = 0;
int y = y1;
for (int x = x1; x <= x2; x++) {
// afișează pixelul (x, y)
abatere += y2 - y1;
if (2 * abatere > x2 - x1) {
y++;
abatere -= x2 - x1;
}
}
Observăm că acum abaterea va fi mereu cuprinsă între . Pentru maximum de
eficiență, înmulțirea cu 2 poate fi exprimată ca shiftare, iar cantitățile x2 - x1 și y2 - y1 pot fi
precalculate în afara buclei.

1. Arii

Noţiunea de arie este una de bază în geometria analitică. Este necesară însă o
prezentare a diferitelor metode de a calcula ariile in contextul prelucrarii
datelor pe calculator.

Aria unui triunghi


În determinarea ariei unui triunghi se poate folosi formula lui Heron:

În formulă, s reprezintă semiperimetrul triunghiului, iar a, b, c lungimile


laturilor triunghiului. Această formulă apare şi într-o altă formă, mult mai
adecvată algoritmilor prin faptul că se evită calcularea lungimii laturilor cu
radical:

În contextul geometriei vectoriale, modulul produsului vectorial a doi vectori o


reprezintă aria paralelogramului cuprins între vectori. Aplicând raţionamentul la
triunghiuri, obţinem relaţia:
Aria unui patrulater
După cum am văzut în cazul unui triunghi, aria unui paralelogram ABCD este
egală cu modulul produsului vectorial al vectorilor reprezentaţi de 2 laturi
neparalele.

Pentru un patrulater oarecare ABCD, putem considera M1, M2, M3, M4 mijloacele
laturilor acestuia. Se poate demonstra că patrulaterul M1M2M3M4 este un
paralelogram cu aria jumătate din aria lui ABCD:
Aria unui poligon
Pentru a calcula aria unui poligon oarecare A1A2A3..An, vom considera un punct
P arbitrar ales în plan. Vom "împărţi" poligonul în triunghiuri de
forma PAiAi+1 (considerăm că A1=An+1) şi vom calcula "aria cu semn" Ti a
fiecărui triunghi (în formula ariei nu vom folosi funcţia de valoare absolută).
Distingem în acest moment două cazuri:
 Poligonul are vârfurile orientate trigonometric. Pentru fiecare latură
"spre dreapta", aria Ti corespunzătoare va fi negativă, iar pentru fiecare
latură "spre stânga", aria Ticorespunzătoare va fi pozitivă.
 Poligonul are vârfurile orientate antitrigonometric. Pentru fiecare latură
"spre dreapta", aria Ti corespunzătoare va fi pozitivă, iar pentru fiecare
latură "spre stânga", aria Ticorespunzătoare va fi negativă.
În ambele cazuri, efectuând suma algebrică a ariilor Ti vom obţine aria
poligonului (deoarece ariile negative vor "anula" zonele corespunzătoare ariilor
pozitive care se află în afara poligonului).
Dacă alegem punctul P(0,0), fiecare arie Ti devine:

Formula finală devine:

Această formulă reprezintă "aria cu semn" a poligonului (o arie pozitivă indică


parcurgerea vârfurilor în ordine trigonometrică, iar o arie negativă,
parcurgerea in ordine antitrigonometrică).
Ecuatiile dreptei
geometrice ce indeplinesc Dreptele ecuatia dreptei. Cu alte cuvinte, ecuatia
unei drepte reprezinta o relatie care este respectata de toate punctele aflate pe
dreapta. Forma generala a ecuatiei unei drepte inste

In cazul in care dreapta nu se afla in plan, fiecare


punct A ( x1 , x2 , x3 ,... Xn ) (pentru n dimensiuni) de pe ea va indeplini
conditiile:

A nu se confunda cu ecuatia planului:

Pentru simplitate, de aici inainte ne vom referi numai la drepte in plan. De


mentionat este faptul ca daca trecem pe y in partea dreapta si impartim prin -
b (consideram un caz general, nu cel nefericit in care b=0), obtinem:

, unde

De asemenea, fiind date doua puncte A(x1, y1) si B(x2, y2), ecuatia dreptei
determinate de ele se poate scrie

Aceasta poate sa nu ne fie de prea mare ajutor, dar facand produsul mezilor cu
extremii si desfacand parantezele vom

obtine , de unde putem


deduce foarte usor cine sunt a, b, c din scrierile precedente.
Se stie ca orice dreapta imparte planul in 2 semiplane: cel cu puncte pentru
care, daca aplicam ecuatia, vom obtine o valoare strict pozitiva, si cel pentru
care vom obtine o valoare strict negativa. De aceea, daca avem o dreapta data
prin 2 puncte A(x1, y1) si B(x2, y2) de pe aceasta, atunci punctul C(x3,
y3) va apartine dreptei AB daca si numai daca
Panta unei drepte
Panta unei drepte se poate defini ca fiind tangenta unghiului facut de dreapta
cu orizontala, mai exact cu orice dreapta paralela cu axa OX. Ea se calculeaza
astfel:

sau

In a doua ecuatie a si b reprezinta coeficientii ecuatiei dreptei respective

Proprietati:
• Doua drepte care au pantele egale sunt ori paralele ori confundate.
• Doua drepte care au produsul pantelor egal cu -1 sunt perpendiculare.
Distanta dintre un punct si o dreapta
Pentru a calcula distanta care ne trebuie noua vom calcula panta
dreptei d1 notata cu m1. Acum vrem sa construim o dreapta d2 perpendiculara
pe dreapta d1 care trece prin punctul A. Stim ca m1*m2=-1 si de aici aflam
usor m2 (panta dreptei d2). In acest moment avem panta dreptei d2 si un punct
care ii apartine. Avand aceste 2 informatii putem sa calculam usor ecuatia ei si
punctul de intersectie cu dreapta d1 (Vezi capitolul Drepte). Distanta dintre
dreapta si punct va fi egala cu distanta dintre punct si punctul de intersectie al
celor 2 drepte.
De asemenea exista si o formula pt a determina distanta de la un punct la o
dreapta: considerand punctul A(x0,y0) si dreapta d:ax+by+c=0, vom avea :

Distanta dintre un punct si un segment


Sa presupunem un punct A(x1,y1) si un segment determinat de
punctele B(x2,y2) si C(x3,y3) si vrem sa aflam distanta dintre punct si
segment.
D=min(dist(A,B),dist(A,C)) in cazul in care perpendiculara din punctul A pe
dreapta BC nu cade in interiorul segmentului BC, altfel distanta va fi egala cu
distanta dintre punctul A si dreapta BC, lucru care l-am tratat mai sus.
Se citeste un numar natuural n si apoi in intervale inchise cu limitele
numere intregi.
a) Calculati si afisati numarul maxim de intervale care se
intersecteaza.
b) Determinati numarul maxim de intervale disjuncte si afisati-le.
Exemplu:
6
13
46
57
26
3 10
8 10
a) 4 (intervalele care se intersecteaza sunt [4,6], [5,7], [3,10] si [2,6]
b) [1,3] [4,6] [8,10] 3

#include<fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");

struct interval {int a,b;};

void citire(interval &x)


{
fin>>x.a>>x.b;
}

void afisare(interval x)
{
fout<<"["<<x.a<<","<<x.b<<"] ";
}

void ordonarea(int n, interval x[100])


{
int i,gata;
interval aux;
do
{
gata=1;
for(i=1;i<n;i++)
if(x[i].a>x[i+1].a)
{
aux=x[i];
x[i]=x[i+1];
x[i+1]=aux;
gata=0;
}
}
while(!gata);
}

void ordonareb(int n, interval x[100])


{
int i,gata;
interval aux;
do
{
gata=1;
for(i=1;i<n;i++)
if(x[i].b>x[i+1].b)
{
aux=x[i];
x[i]=x[i+1];
x[i+1]=aux;
gata=0;
}
}
while(!gata);
}

int main()
{
int n,i,max1=0,max2=0,k,ls,p;
interval x[100];
fin>>n;
for(i=1;i<=n;i++) citire(x[i]);
ordonarea(n,x);
k=1;
ls=x[1].b;
i=2;
while(i<=n)
{ if(x[i].a<=ls)
{
k++;
if(x[i].b<ls) ls=x[i].b;
}
else
{
if(k>max1) max1=k;
k=1;
p=i;
while(x[i-1].b>=x[p].a && i>=1) i--;
ls=x[i].b;
}
i++;
}
if(k>max1) max1=k;
fout<<max1;
fout<<endl;

ordonareb(n,x);
max2=1;
afisare(x[1]);
ls=x[1].b;
for(i=2;i<=n;i++)
if(x[i].a>ls)
{ max2++;
afisare(x[i]);
ls=x[i].b;
}
fout<<max2;
fin.close();
fout.close();
return 0;}
Descriere:

Fie într-un sistem cartezian de coordonate un punct p de coordonate (x, y). Deplasarea de
coordonate de-a lungul axei Ox cu o valoare dată a implică o modificare a coordonatelor punctului
conform formulelor:

În cazul deplasării de-a lungul axei Oy cu valoarea b, transformarea de coordonate va fi dată de


sistemul:

Modificarea „combinată” a coordonatelor cu a după axa Ox şi b după Oy va fi dată de sistemul:

Program
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#include <dos.h>

struct point{float x; float y;} a[100];


int c,i,n,h,j;
float dx,dy;

void initiere_rg()

{
int gdriver = DETECT, gmode, errorcode;
initgraph(&gdriver, &gmode, "");
}

void generate_points(int n)
{ randomize();
for (i=0;i<n;i++)
{ a[i].x=20+60*random(10); a[i].y=20+40*random(10); }
}

void sistem_coordonate(int color)


{ setcolor(color);
line(0,470,640,470); line(630,465,640,470); line(640,470,630,475);
line(5,480,5,0); line(0,10,5,0); line(5,0,10,10);
}

void draw_point(int x,int y, int color)


{ setcolor(color); setfillstyle(1,color); fillellipse(x,480-y,2,2); }

void draw_set (int n, int color)


{ int j;
for (j=0; j<n; j++) draw_point(a[j].x, a[j].y, color);
}

int main(void)
{
cout <<"numarul de puncte: " ; cin >>n;
cout << "deplasare X: "; cin >>dx;
cout << "deplasare Y: "; cin >>dy;

initiere_rg();
sistem_coordonate(3);
generate_points(n);
draw_set(n,15);

/* deplasarea */
if (dx>0) h=1; else h=-1;
for (j=0; j<abs(dx); j++)
{
draw_set(n,0);
for (i=0;i<n;i++) {a[i].x=a[i].x+h;
a[i].y=a[i].y+(dy/dx)*h;
}
draw_set(n,15); delay(100);
}
getch();
closegraph();
return 0;
}

Exemplul 1:

Să se scrie un program, care să determine coordonatele punctului de intersecţie al dreptelor


d1, d2, descrise de punctele: d1: (x1, y1) şi (x2, y2) ; d2: (x3, y3) şi (x4, y4)

Structuri de date. Fiecare punct va fi descris de un articol:

type point=record x,y: real; end;

fiecare dreaptă, de meta articolul:

type line=record p1,p2: point; A,B,C : real; end;

unde p1, p2 reprezintă punctele, care determină dreapta, iar A, B, C – coeficienţii ecuaţiei generale a
dreptei.

Introducerea şi afişarea datelor: datele se introduc din fişierul text date.in, cu următoarea structură:

x1 y1
x2 y2
x3 y3
x4 y4

fişierul conţine patru linii. Fiecare linie conţine coordonatele unui punct, separate prin spaţiu, în
ordinea x, y. Linia i a fişierului conţine descrierea punctului cu indicele i.

Afişarea va fi executată la ecran.


Programul:

type point=record x,y: real; end;


line =record p1,p2:point; a,b,c:real; end;
var f : text;
d1, d2 : line;
intersectie : point;
begin
{citirea datelor}
assign(f,'date.in'); reset (f);
readln(f, d1.p1.x, d1.p1.y);
readln(f, d1.p2.x, d1.p2.y);
readln(f, d2.p1.x, d2.p1.y);
readln(f, d2.p2.x, d2.p2.y);
{calcularea coeficientilor ecuatiilor generale ale dreptelor}
d1.a:=d1.p2.y - d1.p1.y;
d1.b:=d1.p1.x - d1.p2.x;
d1.c:=d1.p2.x*d1.p1.y - d1.p1.x*d1.p2.y;
d2.a:=d2.p2.y - d2.p1.y;
d2.b:=d2.p1.x - d2.p2.x;
d2.c:=d2.p2.x*d2.p1.y - d2.p1.x*d2.p2.y;
{determinarea intersectiei}
{dreptele coincid}
if (d1.a*d2.b = d2.a*d1.b) and (d1.a*d2.c = d2.a*d1.c) then
writeln ('Dreptele coincid') else
{dreptele paralele}
if (d1.a*d2.b = d2.a*d1.b) and (d1.a*d2.c <> d2.a*d1.c) then
writeln ('Dreptele paralele') else
{dreptele se intersecteaza}
begin
if d1.a = 0 then
begin intersectie.y:= -d1.c/d1.b;
intersectie.x:= -(d2.b*intersectie.y + d2.c) / d2.a;
end
else
begin intersectie.y:= (d1.c*d2.a - d2.c*d1.a)/(d2.b*d1.a-d1.b*d2.a);
intersectie.x:= -(d1.b*intersectie.y + d1.c)/d1.a;
end;
writeln(intersectie.x:0:3, ' ', intersectie.y:0:3);
end;
readln;
end.

Pentru setul de date:

0 3
3 0
0 0
3 3

Rezultatul afişat este: 1.500 1.500

Pentru setul de date

0 3
3 0
1 2
2 1

Rezultatul afişat este: Dreptele coincid


03
30
05
50

Rezultatul afişat este: Dreptele paralele

S-ar putea să vă placă și