/* ======= =============================================================== */ /* STATENS KARTVERK - FYSAK-PC */ /* Fil: gm.c */ /* Ansvarlig: Andreas Røstad */ /* Innhold: Geometrirutiner fysak-pc */ /* ====================================================================== */ #include "stdafx.h" #include #include #include #include "../UT/fyut.h" #include "fygm.h" /* --- Konstanter -- */ #define ACCY 1.0E-6 #define GM_ACCY 1.0E-8 /* --- Makroer -- */ #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) /* AR-890723 CH GM_wtstBue Sjekk om en bue berører et vindu CD ========================================================================== CD Formål: CD Sjekker om en bue berører et vindu. CD wmax CD !--------------! CD ! ...... ! CD .!... .....! CD .... ! !... CD ... ! ! x (p2) CD (p1) x !--------------! CD wmin CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double as i Koordinat i sentrumspunktet CD double ns i CD double radius i Buens radius CD double fi i "Retning" fra sentrum til buens startpunkt. CD double dfi i Vinkel mellom fi og retning sentrum - sluttpkt. CD double wmina i -! CD double wminn i ! Vindu CD double wmaxa i ! CD double wmaxn i -! CD short kryss r 0=ikke skjæring, 1=skjæring eller inni CD CD Bruk: CD kryss = GM_wtstBue(as,ns,radius,fi,dfi,wmina,wminn,wmaxa,wmaxn); ========================================================================== */ SK_EntPnt_GM short GM_wtstBue(double as,double ns,double radius,double fi,double dfi, double wmina,double wminn,double wmaxa,double wmaxn) { double nva,nvn,oha,ohn,as1,ns1,as2,ns2; double r = fabs(radius); /* Omskrevet rektangel */ GM_buebox(as,ns,r,fi,dfi,&nva,&nvn,&oha,&ohn); /* Er hele buen inni? */ if (wmaxn >= ohn && wmaxa >= oha && wminn <= nvn && wmina <= nva){ return 1; } /* Overlapp mellom rektangel og vindu?, må teste videre */ if (wmaxn >= nvn && wmaxa >= nva && wminn <= ohn && wmina <= oha){ /* Min N */ if (GM_sLinBue(as,ns,r,fi,dfi,wmina,wminn,wmaxa,wminn, &as1,&ns1,&as2,&ns2)){ return 1; } /* Min A */ if (GM_sLinBue(as,ns,r,fi,dfi,wmina,wminn,wmina,wmaxn, &as1,&ns1,&as2,&ns2)){ return 1; } /* Max N */ if (GM_sLinBue(as,ns,r,fi,dfi,wmina,wmaxn,wmaxa,wmaxn, &as1,&ns1,&as2,&ns2)){ return 1; } /* Max a */ if (GM_sLinBue(as,ns,r,fi,dfi,wmaxa,wminn,wmaxa,wmaxn, &as1,&ns1,&as2,&ns2)){ return 1; } } return 0; } /* AR-881018 CH GM_wtst Sjekk om en linje berører et vindu CD ========================================================================== CD Formål: CD Sjekker om en linje berører et vindu. CD wmax CD !--------------! CD ! ........!......... CD ....!...... ! p2 CD ......... ! ! CD p1 ! ! CD !--------------! CD wmin CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double p1a i Koordinat i første punkt CD double p1n i CD double p2a i Koordinat i andre punkt CD double p2n i CD double wmina i -! CD double wminn i ! Vindu CD double wmaxa i ! CD double wmaxn i -! CD short kryss r 0=ikke skjæring, 1=skjæring eller inni CD CD Bruk: CD kryss = GM_wtst(pa1,p1n,p2a,p2n,wmina,wminn,wmaxa,wmaxn); ========================================================================== */ SK_EntPnt_GM short GM_wtst(double p1a, double p1n, double p2a, double p2n, double wmina, double wminn, double wmaxa, double wmaxn) { unsigned int visa,visb,heltute,inni,kryss; double sn,sa; visa = 0; if (p1a < wmina) visa |= (unsigned int)0x1; if (p1a > wmaxa) visa |= (unsigned int)0x2; if (p1n < wminn) visa |= (unsigned int)0x4; if (p1n > wmaxn) visa |= (unsigned int)0x8; inni = (unsigned int)(visa == 0); /* Tester videre når første pkt. er utenfor */ if (! inni){ visb = 0; if (p2a < wmina) visb |= (unsigned int)0x1; if (p2a > wmaxa) visb |= (unsigned int)0x2; if (p2n < wminn) visb |= (unsigned int)0x4; if (p2n > wmaxn) visb |= (unsigned int)0x8; inni = (unsigned int)(visb == 0); if (! inni){ /* Når pkt B også er utenfor */ heltute = visa & visb; if (! heltute){ /* Når det er mulig skjæring med vinduet */ /* Min N */ kryss = (unsigned int)GM_shor(p1a,p1n,p2a,p2n, wmina,wminn,wmaxa,wminn,&sa,&sn); if (! kryss){ /* Min A */ kryss = (unsigned int)GM_sver(p1a,p1n,p2a,p2n, wmina,wminn,wmina,wmaxn,&sa,&sn); } if (! kryss){ /* Max N */ kryss = (unsigned int)GM_shor(p1a,p1n,p2a,p2n, wmina,wmaxn,wmaxa,wmaxn,&sa,&sn); } if (! kryss){ /* Max a */ kryss = (unsigned int)GM_sver(p1a,p1n,p2a,p2n, wmaxa,wminn,wmaxa,wmaxn,&sa,&sn); } if (kryss) inni = 1; } } } return (short)inni; } /* PG-030815 CH GM_wtstPunkt Sjekker om et punkt ligger inni - eller i kanten av - vindu CD =============================================================================== CD Formål: CD Sjekker om et punkt ligger inni et vindu - gjerne rotert vindu. CD CD PARAMETERLISTE: CD Navn Type Array i/U Merknad CD ------------------------------------------------------------------------------- CD PktA double i Øst-koordinat for sjekkpunkt CD PktN double i Nord-koordinat for sjekkpunkt CD wa1 double i Øst-koordinat for 1.pkt i vindu CD wn1 double i Nord-koordinat for 1.pkt i vindu CD wa2 double i Øst-koordinat for 2.pkt i vindu CD wn2 double i Nord-koordinat for 2.pkt i vindu CD wa3 double i Øst-koordinat for 3.pkt i vindu CD wn3 double i Nord-koordinat for 3.pkt i vindu CD wa4 double i Øst-koordinat for 4.pkt i vindu CD wn4 double i Nord-koordinat for 4.pkt i vindu CD inni short r Er punktet innenfor vinduet CD CD Bruk: inni = GM_wtstPunkt(PktA, PktN, wa1, wn1, wa2, wn2, wa3, wn3, wa4, wn4); =============================================================================== */ SK_EntPnt_GM short GM_wtstPunkt(double PktA, double PktN, double wa1, double wn1, double wa2, double wn2, double wa3, double wn3, double wa4, double wn4) { double dPolyMaxA,dPolyMaxN,dPolyMinA,dPolyMinN; double maxA = 99999999999.9; // "Uendelig" øst double as,ns; short sAntSkjaer; // Sjekk 1: Ligger punktet utenfor omskrevet rektangel - så ligger det utenfor vinduet dPolyMaxA=max(wa1,wa2); dPolyMaxA=max(dPolyMaxA,wa3); dPolyMaxA=max(dPolyMaxA,wa4); dPolyMaxN=max(wn1,wn2); dPolyMaxN=max(dPolyMaxN,wn3); dPolyMaxN=max(dPolyMaxN,wn4); dPolyMinA=min(wa1,wa2); dPolyMinA=min(dPolyMinA,wa3); dPolyMinA=min(dPolyMinA,wa4); dPolyMinN=min(wn1,wn2); dPolyMinN=min(dPolyMinN,wn3); dPolyMinN=min(dPolyMinN,wn4); if((PktA>dPolyMaxA) || (PktAdPolyMaxN) || (PktN= mini && ma <= maxi){ /* (ma er lik na) */ if (fabs(la-ka) > 0.0001){ /* Beregn skjæringspunktet */ *sa = ma; *sn = kn + ((*sa-ka)*(ln-kn))/(la-ka); mini = min(mn,nn) - ACCY; maxi = max(mn,nn) + ACCY; /* Sjekk om det er skjæring */ kryss = (unsigned int)(*sn >= mini && *sn <= maxi); } } return (short)kryss; } /* AR-881018 CH GM_shor Skjæring mellom horisontal- og skrålinje CD ========================================================================== CD Formål: CD Beregner skjæringspunkt mellom en horisontal linje (M-N) CD og en skrålinje (K-L) CD CD *L CD / CD / CD M*--------*S--------*N CD / CD / CD K* CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double ka i Koordinat i K CD double kn i CD double la i Koordinat i L CD double ln i CD double na i Koordinat i N CD double nn i CD double ma i Koordinat i M CD double mn i CD double *sa u Koordinat i S CD double *sn u CD short kryss r 0=ikke skjæring, 1=skjæring CD CD Bruk: CD kryss = GM_shor(ka,kn,la,ln,na,nn,ma,mn,&sa,&sn); ========================================================================== */ SK_EntPnt_GM short GM_shor(double ka,double kn,double la,double ln,double na,double nn, double ma,double mn,double *sa,double *sn) { unsigned int kryss = 0; double mini,maxi; mini = min(kn,ln); maxi = max(kn,ln); if (mn >= mini && nn <= maxi){ /* (mn er lik nn) */ if (fabs(ln-kn) > 0.0001){ /* Beregn skjæringspunktet */ *sn = mn; *sa = ka + ((*sn-kn)*(la-ka))/(ln-kn); mini = min(ma,na) - ACCY; maxi = max(ma,na) + ACCY; /* Sjekk om det er skjæring */ kryss = (unsigned int)(*sa >= mini && *sa <= maxi); } } return (short)kryss; } /* AR-901209 CH GM_sLinLin Skjæringspunkt mellom 2 linjer CD ========================================================================== CD Formål: CD Beregner skjæringspunkt mellom 2 linjer (M-N) og (K-L) CD CD M* *L CD \ / CD \ / CD *S CD / \ CD / \ CD K* *N CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double ka i Koordinat i K CD double kn i CD double la i Koordinat i L CD double ln i CD double ma i Koordinat i M CD double mn i CD double na i Koordinat i N CD double nn i CD double *sa u Koordinat i S CD double *sn u CD short kryss r 0=ikke skjæring, 1=skjæring CD CD Bruk: CD kryss = GM_sLinLin(ka,kn,la,ln,ma,mn,na,nn,&sa,&sn); ========================================================================== */ SK_EntPnt_GM short GM_sLinLin(double ka,double kn,double la,double ln,double ma,double mn, double na,double nn,double *sa,double *sn) { double det,detinv,s,t; double alk = la - ka; double nlk = ln - kn; double anm = na - ma; double nnm = nn - mn; double amk = ma - ka; double nmk = mn - kn; /* Sorterer først ut åpenbare tilfeller der det ikke er skjæring */ if (max(ka,la) < min(ma,na)) return 0; if (min(ka,la) > max(ma,na)) return 0; if (max(kn,ln) < min(mn,nn)) return 0; if (min(kn,ln) > max(mn,nn)) return 0; det = anm * nlk - nnm * alk; /* Parallelle linjer */ if (fabs(det) < ACCY) return 0; detinv = 1.0 / det; s = (anm*nmk - nnm*amk) * detinv; t = (alk*nmk - nlk*amk) * detinv; if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0) return 0; *sa = ka + alk*s; *sn = kn + nlk*s; return 1; #ifdef UTGAAR /* * Beregner skjæring mellom to uendelige vektorer. * Sjekker etterpå om skjæringspunktet ligger på linjebitene. */ if (GM_sVektVekt(ka,kn,la,ln,ma,mn,na,nn,sa,sn)){ if (*sn <= max(kn,ln)+ACCY && *sn >= min(kn,ln)-ACCY && *sa <= max(ka,la)+ACCY && *sa >= min(ka,la)-ACCY && *sn <= max(mn,nn)+ACCY && *sn >= min(mn,nn)-ACCY && *sa <= max(ma,na)+ACCY && *sa >= min(ma,na)-ACCY) { return 1; /* Skjæring funnet ==> returnerer */ } } return 0; /* Ingen skjæring funnet ==> returnerer */ #endif } /* AR-901209 CH GM_Overlapp Overlapp mellom 2 linjer CD ========================================================================== CD Formål: CD Sjekker om to linjer overlapper hverandre helt eller delevis. CD CD M* CD \ CD \ CD \ *K CD \ \ CD \ \ CD *N\ CD \ CD \ CD *L CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double ka i Koordinat i K CD double kn i CD double la i Koordinat i L CD double ln i CD double ma i Koordinat i M CD double mn i CD double na i Koordinat i N CD double nn i CD double *sa u Koordinat i S CD double *sn u CD short overlapp r 0=ikke overlapp CD 1=tangerer (likt endepunkt) CD 2=delevis overlapp CD 3=linjene er like CD Bruk: CD kryss = GM_Overlapp(ka,kn,la,ln,ma,mn,na,nn); ========================================================================== */ SK_EntPnt_GM short GM_Overlapp(double ka,double kn,double la,double ln,double ma,double mn,double na,double nn) { // Sorterer først ut åpenbare tilfeller der det ikke er skjæring if (max(ka,la) < min(ma,na)) return 0; if (min(ka,la) > max(ma,na)) return 0; if (max(kn,ln) < min(mn,nn)) return 0; if (min(kn,ln) > max(mn,nn)) return 0; // Linjene er like if (fabs((min(ka,la) - min(ma,na))) < GM_ACCY && fabs((max(ka,la) - max(ma,na))) < GM_ACCY && fabs((min(kn,ln) - min(mn,nn))) < GM_ACCY && fabs((max(kn,ln) - max(mn,nn))) < GM_ACCY) { return 3; } // Linjene tangerer i enden if ((fabs(ka-ma) max(ma,na)) return 0; //if (max(kn,ln) < min(mn,nn)) return 0; //if (min(kn,ln) > max(mn,nn)) return 0; det = anm * nlk - nnm * alk; /* Parallelle linjer */ if (fabs(det) < ACCY) return 0; detinv = 1.0 / det; s = (anm*nmk - nnm*amk) * detinv; t = (alk*nmk - nlk*amk) * detinv; //if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0) return 0; *sa = ka + alk*s; *sn = kn + nlk*s; return 1; #ifdef UTGAAR double pa1,pb1,pc1,pa2,pb2,pc2; /* * Beregner skjæring mellom to uendelige vektorer. */ if (GM_bepa(ka,kn,la,ln,&pa1,&pb1,&pc1)) { if (GM_bepa(ma,mn,na,nn,&pa2,&pb2,&pc2)) { if (GM_cint(pa1,pb1,pc1,pa2,pb2,pc2,sa,sn)) { return 1; /* Skjæring funnet ==> returnerer */ } } } return 0; /* Ingen skjæring funnet ==> returnerer */ #endif } /* AR-890722 CH GM_sLinBue Skjæring mellom linje og bue CD ========================================================================== CD Formål: CD Beregner skjæringspunkt mellom en linje (K-L) og en bue. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double sa i Koordinat i buens sentrum. CD double sn i CD double radius i Buens radius. CD double fi i Retning fra sentrum til buens startpunkt CD double dfi i Vinkel mellom retning til buens startpunkt og sluttpunkt CD double ka i Koordinat i K. CD double kn i CD double la i Koordinat i L. CD double ln i CD double *a1 u Koordinat i skjæringspunkt 1 CD double *n1 u CD double *a2 u Koordinat i skjæringspunkt 2 CD double *n2 u CD short kryss r Antall skjæringspunkter (0, 1 eller 2) CD CD Bruk: CD kryss = GM_sLinBue(sa,sn,radius,fi,dfi,ka,kn,la,ln,&a1,&n1,&a2,&n2); ========================================================================== */ SK_EntPnt_GM short GM_sLinBue(double sa,double sn,double radius,double fi,double dfi, double ka,double kn,double la,double ln, double *a1,double *n1,double *a2,double *n2) { short kryss; double mina,minn,maxa,maxn; /* Beregn først skjæring mellom uendelig vektor og hele sirkelen */ kryss = GM_sVektSirk(sa,sn,radius,ka,kn,la,ln,a1,n1,a2,n2); /* Sjekk om punktene ligger på linjen */ if (kryss > 0){ minn = min(kn,ln) - ACCY; mina = min(ka,la) - ACCY; maxn = max(kn,ln) + ACCY; maxa = max(ka,la) + ACCY; if (kryss == 2){ if (! (*a2 <= maxa && *a2 >= mina && *n2 <= maxn && *n2 >= minn)){ kryss = 1; /* Utenfor linjen */ } } if (! (*a1 <= maxa && *a1 >= mina && *n1 <= maxn && *n1 >= minn)){ /* Utenfor linjen */ if (kryss == 2){ /* Flytt ned forrige skjæringspunkt */ kryss = 1; *a1 = *a2; *n1 = *n2; } else{ kryss = 0; /* Ikke noe skjæringspunkt */ } } } /* Sjekk om punktene ligger på buen */ if (kryss > 0){ if (kryss == 2){ if ( ! GM_TestPktBue(sa,sn,fi,dfi,*a2,*n2)){ kryss = 1; /* Utenfor buen */ } } if ( ! GM_TestPktBue(sa,sn,fi,dfi,*a1,*n1)){ if (kryss == 2){ /* Flytt ned forrige skjæringspunkt */ kryss = 1; *a1 = *a2; *n1 = *n2; } else{ kryss = 0; /* Ikke noe skjæringspunkt */ } } } return kryss; } /* AR-901209 CH GM_sVektSirk Skjæring mellom uendelig linje og sirkel CD ========================================================================== CD Formål: CD Beregner skjæringspunkt mellom en uendelig linje (K-L) og en sirkel. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double sa i Koordinat i sirkelens sentrum. CD double sn i CD double radius i Sirkelens radius. CD double ka i Koordinat i K. CD double kn i CD double la i Koordinat i L. CD double ln i CD double *a1 u Koordinat i skjæringspunkt 1 CD double *n1 u CD double *a2 u Koordinat i skjæringspunkt 2 CD double *n2 u CD short kryss r Antall skjæringspunkter (0, 1 eller 2) CD CD Bruk: CD kryss = GM_sVektSirk(sa,sn,radius,ka,kn,la,ln,&a1,&n1,&a2,&n2); ========================================================================== */ SK_EntPnt_GM short GM_sVektSirk(double sa,double sn,double radius, double ka,double kn,double la,double ln, double *a1,double *n1,double *a2,double *n2) { short kryss = 0; double f,g,root,fsq,gsq,fgsq,xj0,yj0,fygx,fxgy,t,fginv,t1,t2; /* Beregn skjæring mellom uendelig vektor og sirkelen */ /* Parametre for K-L */ f = la - ka; g = ln - kn; /* Beregn skjæring */ fsq = f * f; gsq = g * g; fgsq = fsq + gsq; if (fgsq > ACCY){ /* Linjen er ok */ xj0 = sa - ka; yj0 = sn - kn; fygx = f*yj0 - g*xj0; root = radius*radius*fgsq - fygx*fygx; if (root > -ACCY){ /* Linjen berører sirkelen */ fxgy = f*xj0 + g*yj0; if (root < ACCY){ /* Linjen tangerer sirkelen */ kryss = 1; t = fxgy / fgsq; *a1 = ka + f*t; *n1 = kn + g*t; } else{ /* Linjen skjærer sirkelen */ kryss = 2; root = sqrt(root); fginv = 1.0 / fgsq; t1 = (fxgy - root) * fginv; t2 = (fxgy + root) * fginv; *a1 = ka + f*t1; *n1 = kn + g*t1; *a2 = ka + f*t2; *n2 = kn + g*t2; } } } return kryss; } /* AR-901209 CH GM_sBueBue Skjæringspunkt mellom 2 buer CD ========================================================================== CD Formål: CD Beregner skjæringspunkt mellom 2 buer. CD NB! Retningen oppgis i radianer, med retning 0 i øst-aksen, og med positiv CD omløpsretning mot urviseren. Alle vinkler er i området 0 - 2PI. CD Metode: Se Bowyer and Woodwark: AProgrammer's Geometry, side 27-28. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double sa1 i Koordinat i buens sentrum. CD double sn1 i CD double radius1 i Buens radius. CD double fi1 i Retning fra sentrum til buens startpunkt CD double dfi1 i Vinkel mellom retning til buens startpunkt og sluttpunkt CD double sa2 i Koordinat i buens sentrum. CD double sn2 i CD double radius2 i Buens radius. CD double fi2 i Retning fra sentrum til buens startpunkt CD double dfi2 i Vinkel mellom retning til buens startpunkt og sluttpunkt CD double *a1 u Koordinat i skjæringspunkt 1 CD double *n1 u CD double *a2 u Koordinat i skjæringspunkt 2 CD double *n2 u CD short kryss r Antall skjæringspunkter (0, 1 eller 2) CD CD Bruk: CD kryss = GM_sBueBue(as1,ns1,fi1,dfi1,as2,ns2,fi2,dfi2,&a1,&n1,&a2,&n2); ========================================================================== */ SK_EntPnt_GM short GM_sBueBue(double as1,double ns1,double radius1,double fi1,double dfi1, double as2,double ns2,double radius2,double fi2,double dfi2, double *a1,double *n1,double *a2,double *n2) { short kryss; /* * Beregner først skjæring mellom to sirkler. * Sjekker etterpå om skjæringspunktene ligger på buene. */ kryss = GM_sSirkSirk(as1,ns1,radius1,as2,ns2,radius2,a1,n1,a2,n2); /* Sjekk om punktene ligger inne på de aktuelle buene */ if (kryss > 0){ /* Sjekk om skjæringspunkt 2 ligger på bue 1 */ if (kryss == 2){ if ( ! GM_TestPktBue(as1,ns1,fi1,dfi1,*a2,*n2)){ kryss = 1; /* Utenfor buen */ } /* Sjekk om skjæringspunkt 2 også ligger på bue 2 */ if (kryss == 2){ if ( ! GM_TestPktBue(as2,ns2,fi2,dfi2,*a2,*n2)){ kryss = 1; /* Utenfor buen */ } } } /* Sjekk om skjæringspunkt 1 ligger på bue 1 */ if ( ! GM_TestPktBue(as1,ns1,fi1,dfi1,*a1,*n1)){ if (kryss == 2){ /* Flytt ned forrige skjæringspunkt */ kryss = 1; *a1 = *a2; *n1 = *n2; } else { kryss = 0; /* Ikke noe skjæringspunkt */ } } if (kryss > 0){ /* Sjekk om skjæringspunkt 1 også ligger på bue 2 */ if ( ! GM_TestPktBue(as2,ns2,fi2,dfi2,*a1,*n1)){ if (kryss == 2){ /* Flytt ned forrige skjæringspunkt */ kryss = 1; *a1 = *a2; *n1 = *n2; } else{ kryss = 0; /* Ikke noe skjæringspunkt */ } } } } return kryss; } /* AR-901209 CH GM_sSirkSirk Skjæringspunkt mellom 2 sirkler CD ========================================================================== CD Formål: CD Beregner skjæringspunkt mellom 2 sirkler. CD Metode: Se Bowyer and Woodwark: AProgrammer's Geometry, side 27-28. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double sa1 i Koordinat i sirklens sentrum. CD double sn1 i CD double radius1 i Sirklens radius. CD double sa2 i Koordinat i sirklens sentrum. CD double sn2 i CD double radius2 i Sirklens radius. CD double *a1 u Koordinat i skjæringspunkt 1 CD double *n1 u CD double *a2 u Koordinat i skjæringspunkt 2 CD double *n2 u CD short kryss r Antall skjæringspunkter (0, 1 eller 2) CD CD Bruk: CD kryss = GM_sSirkSirk(as1,ns1,as2,ns2,&a1,&n1,&a2,&n2); ========================================================================== */ SK_EntPnt_GM short GM_sSirkSirk(double as1,double ns1,double radius1, double as2,double ns2,double radius2, double *a1,double *n1,double *a2,double *n2) { double r1sq,r2sq,a21,n21,distsq,dstinv,sumrsq,root,a,n,afac,nfac; double scl,delrsq; short kryss = 0; /* * Beregner skjæring mellom to sirkler. */ r1sq = radius1 * radius1; r2sq = radius2 * radius2; a21 = as2 - as1; n21 = ns2 - ns1; /* Beregn kvadrert lengden L-K */ distsq = a21*a21 + n21*n21; if (distsq > ACCY){ /* Ikke sammenfallende punkt */ delrsq = r2sq - r1sq; sumrsq = r1sq + r2sq; root = 2.0*sumrsq*distsq - distsq*distsq - delrsq*delrsq; if (root > -ACCY){ /* Sirklene skjærer */ dstinv = 0.5 / distsq; scl = 0.5 - delrsq*dstinv; a = as1 + a21*scl; n = ns1 + n21*scl; if (root < ACCY){ /* 1 tangeringspunkt */ *a1 = a; *n1 = n; kryss = 1; } else{ /* 2 skjæringspunkter */ root = dstinv * sqrt(root); afac = a21 * root; nfac = n21 * root; *a1 = a - nfac; *n1 = n + afac; *a2 = a + nfac; *n2 = n - afac; kryss = 2; } } } return kryss; } /* AR-890904 JAØ-1999-02-03 CH GM_fotp Fotpunkt på linje fra punkt CD ========================================================================== CD Formål: CD Beregner fotpunktet på linjen 1-2 fra punktet P. CD CD *P CD ! CD ! CD 1*--------*---------*2 CD F CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double a1 i Koordinat i 1 CD double n1 i CD double a2 i Koordinat i 2 CD double n2 i CD double ap i Koordinat i P CD double np i CD double *af u Koordinat i fotpunktet CD double *nf u CD short kryss r 0=ikke beregnet (brukes ikke) CD 1=beregnet, men punktet er utenfor linjen CD 2=bregnet, ok CD CD Bruk: CD kryss = GM_fotp(a1,n1,a2,n2,ap,np,&af,&nf); ========================================================================== */ SK_EntPnt_GM short GM_fotp(double a1,double n1,double a2,double n2,double ap,double np, double *af,double *nf) { //double pa1,pb1,pc1,pa2,pb2,pc2; double ap1,np1,ap2,np2,retning,a1u,n1u,a2u,n2u; short beregnet = 0; if (fabs(a2-a1) < ACCY) { /* Punkt 1 og 2 er sammenfallende */ if (fabs(n2-n1) < ACCY) { *af = a1; *nf = n1; /* Vertikal linje */ } else { *af = a1; *nf = np; } /* Sjekk at fotpunktet er på linjen */ //if ( (*nf <= max(n1,n2)+ACCY) && (*nf >= min(n1,n2)-ACCY) ) { if ( (*nf <= max(n1,n2)) && (*nf >= min(n1,n2)) ) { beregnet = 2; } else { beregnet = 1; } /* Horisontal linje */ } else if (fabs(n2-n1) < ACCY) { *af = ap; *nf = n1; /* Sjekk at fotpunktet er på linjen */ //if ( (*af <= max(a1,a2)+ACCY) && (*af >= min(a1,a2)-ACCY) ) { if ( (*af <= max(a1,a2)) && (*af >= min(a1,a2)) ) { beregnet = 2; } else { beregnet = 1; } } /* ---------- Skrå linje */ if ( ! beregnet) { //JAØ-20001205 Prøver ny metode å beregne fotpunkt, pga avrundingsproblemer ved små verdier. retning = GM_RetnGon(a1,n1,a2,n2); //Utvider linjene "uendelig" for å være sikker på å få kryssing a1u = a1; a2u = a2; n1u = n1; n2u = n2; GM_PolRettv(&a1u,&n1u,retning+200.0,100000000); GM_PolRettv(&a2u,&n2u,retning,100000000); ap1 = ap; ap2 = ap; np1 = np; np2 = np; GM_PolRettv(&ap1,&np1,retning+100.0,100000000); GM_PolRettv(&ap2,&np2,retning-100.0,100000000); GM_sLinLin(a1u,n1u,a2u,n2u,ap1,np1,ap2,np2,af,nf); //Da gikk det bedre! //JAØ-20001205 Fjernet gammel måte å beregne fotpunkt, pga avrundingsproblemer ved små verdier. /* // Parametre for 1-2 if (GM_bepa(a1,n1,a2,n2,&pa1,&pb1,&pc1)){ // Parametre for P-F pa2=pb1; pb2=-pa1; pc2=pa1*np-pb1*ap; // Fotpunktet GM_cint(pa1,pb1,pc1,pa2,pb2,pc2,af,nf); } */ /* Sjekk at fotpunktet er på linjen */ //if (*nf <= (max(n1,n2)+ACCY) && *nf >= (min(n1,n2)-ACCY) && // *af <= (max(a1,a2)+ACCY) && *af >= (min(a1,a2)-ACCY)){ if (*nf <= (max(n1,n2)) && *nf >= (min(n1,n2)) && *af <= (max(a1,a2)) && *af >= (min(a1,a2))){ beregnet = 2; /* På linjen */ } else { beregnet = 1; /* Utenfor linjen */ } } return beregnet; } /* IR-2011-05-05 CH GM_fotp Fotpunkt på line frå punkt CD ========================================================================== CD Formål: CD Bereknar fotpunktet på lina 1-2 frå punktet P (i 2D). CD (Ein kan bruke same metoden i 3D, ved å ta med z-koordinatane i tillegg.) CD Sjå http://paulbourke.net/geometry/sphereline for dokumentasjon. CD CD *P CD ! CD ! CD 1*--------*---------*2 CD F CD CD Parametrar: CD Type Namn I/U Forklaring CD -------------------------------------------------------------------------- CD double a1 i Koordinat i 1 CD double n1 i CD double a2 i Koordinat i 2 CD double n2 i CD double ap i Koordinat i P CD double np i CD double *af u Koordinat i fotpunktet CD double *nf u CD short kryss r 0=ikkje berekna (blir ikkje brukt) CD 1=berekna, men punktet er utanfor lina CD 2=berekna, ok CD CD Bruk: CD kryss = GM_fotp(a1,n1,a2,n2,ap,np,&af,&nf); ========================================================================== */ // SK_EntPnt_GM short GM_fotp_ny(double a1,double n1,double a2,double n2,double ap,double np, // double *af,double *nf) SK_EntPnt_GM short GM_fotp_ny(double a1, double n1, double a2, double n2, double ap, double np, double *af, double *nf) { double da12, dn12, da1p, dn1p, teljar, nemnar, u; short godfot; da12 = a2 - a1; dn12 = n2 - n1; da1p = ap - a1; dn1p = np - n1; teljar = da1p * da12 + dn1p * dn12; nemnar = da12 * da12 + dn12 * dn12; if (nemnar == 0) // lina 1-2 er nullvektor { *af = a1; *nf = n1; godfot = 2; } else { u = teljar / nemnar; *af = a1 + u * da12; *nf = n1 + u * dn12; if ( (u >= 0) && (u <= 1)) { godfot = 2; } else { godfot = 1; } } return godfot; } #ifdef TEST { //double pa1,pb1,pc1,pa2,pb2,pc2; double retning; double ap1=ap; double np1=np; short beregnet = 0; double dn=fabs(n2-n1); double da=fabs(a2-a1); if (da < ACCY) { /* Punkt 1 og 2 er sammenfallende */ if (dn < ACCY) { *af = a1; *nf = n1; /* Vertikal linje */ } else { *af = a1; *nf = np; } /* Sjekk at fotpunktet er på linjen */ if ( (*nf <= max(n1,n2)+ACCY) && (*nf >= min(n1,n2)-ACCY) ) { beregnet = 2; } else { beregnet = 1; } /* Horisontal linje */ } else if (dn < ACCY) { *af = ap; *nf = n1; /* Sjekk at fotpunktet er på linjen */ if ( (*af <= max(a1,a2)+ACCY) && (*af >= min(a1,a2)-ACCY) ) { beregnet = 2; } else { beregnet = 1; } } /* ---------- Skrå linje */ if ( ! beregnet) { // AR 2000-12-10 // Forslag til ny metode for fotpunktberegning. Endrer ikke de opprinnelige punktene, // og det blir da mulig å gi korrekt tilbakemelding om punktet ligger inne på den gitte linjen. retning = GM_RetnGon(a1,n1,a2,n2); GM_PolRettv(&ap1, &np1, retning+100.0, max(da,dn)); GM_sVektVekt(a1,n1,a2,n2,ap,np,ap1,np1,af,nf); /* Sjekk at fotpunktet er på linjen */ if (*nf <= (max(n1,n2)+ACCY) && *nf >= (min(n1,n2)-ACCY) && *af <= (max(a1,a2)+ACCY) && *af >= (min(a1,a2)-ACCY)){ beregnet = 2; /* På linjen */ } else { beregnet = 1; /* Utenfor linjen */ } } return beregnet; } #endif /* AR-991012 CH GM_Parallell Parallellforskyver linje CD ========================================================================== CD Formål: CD Parallellforskyver linjen K-L gitt avstand normalt til siden. CD CD CD L1 L L1 CD *- - - - * - - - - * CD ! CD ! ! ! CD ! CD ! ! ! CD ! CD ! ! ! CD ! CD *- - - - * - - - - * CD K1 K K1 CD CD CD avstand < 0 avstand > 0 CD CD CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double ka i Koordinat i K CD double kn i CD double la i Koordinat i L CD double ln i CD double avstand i Forskyving (>0 = til høyre(K2-L2), <0 = til venstre(K1-L1)) CD double *ka1 u Koordinat i K1 CD double *kn1 u CD double *la1 u Koordinat i L1 CD double *ln1 u CD bool status s r UT_FALSE = ikke beregnet (K og L har like koordinater) CD UT_TRUE = bregnet, ok CD CD Bruk: CD status = GM_Parallell(ka,kn,la,ln,avstand,&ka1,&kn1,&la1,&ln1); ========================================================================== */ SK_EntPnt_GM short GM_Parallell(double ka,double kn,double la,double ln,double avstand, double *ka1,double *kn1,double *la1,double *ln1) { double fi, da, dn; /* Punkt 1 og 2 er sammenfallende, klarer ikke å beregne */ if (fabs(ka-la) < ACCY && fabs(kn-ln) < ACCY) { *ka1 = ka; *kn1 = kn; *la1 = la; *ln1 = ln; return UT_FALSE; } /* Ingen forskyving */ if (fabs(avstand) <= ACCY) { *ka1 = ka; *kn1 = kn; *la1 = la; *ln1 = ln; return UT_TRUE; } /* Beregner retninger fra K til L */ fi = GM_retning(ka,kn,la,ln); /* Forskyvingsretning */ if ( avstand < ACCY ) { /* Forskyving til venstre */ fi += PI/2; } else { /* Forskyving til høyre */ fi -= PI/2; } /* Beregner nye koordinater */ avstand = fabs (avstand); da = avstand * cos(fi); dn = avstand * sin(fi); *ka1 = ka + da; *kn1 = kn + dn; *la1 = la + da; *ln1 = ln + dn; return UT_TRUE; } /* AR-890723 CH GM_KonvBue Omregning til intern bue-angivelse CD ========================================================================== CD Formål: CD Omregning til intern bue-angivelse med sirkelsentrum, radius og retning CD til buens start samt delta for sluttpunktet. CD NB! Retningen oppgis i radianer, med retning 0 i øst-aksen, og med positiv CD omløpsretning mot urviseren. Alle vinkler er i området 0 - 2PI. CD Metode: Se Bowyer and Woodwark: AProgrammer's Geometry, CD side 27-28 og 35-36. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double a1 i Koordinat i P1 CD double n1 i CD double a2 i Koordinat i P2 CD double n2 i CD double radius i Buens radius (med fortegn) CD short storbue i Storbue (1=storbue, 0=ikke storbue) CD double *as u Koordinat i sentrumspunktet CD double *ns u CD double *fi u "Retning" sentrum - punkt 1. CD double *dfi u Vinkel mellom fi og retning sentrum - punkt 2. CD short beregnet r 0=kan ikke beregne, 1=bregnet ok. CD CD Bruk: CD ok = GM_KonvBue(a1,n1,a2,n2,radius,storbue,&as,&ns,&fi,&dfi); ========================================================================== */ SK_EntPnt_GM short GM_KonvBue(double a1,double n1,double a2,double n2,double radius, short storbue,double *as,double *ns,double *fi,double *dfi) { double rsq,a21,n21,distsq,dstinv,sumrsq,root,a,n,afac,nfac,fi2,f1; short beregnet = 0; rsq = radius * radius; a21 = a2 - a1; n21 = n2 - n1; /* Beregn kvadrert lengden L-K */ distsq = a21*a21 + n21*n21; if (distsq > ACCY) { /* Ikke sammenfallende punkt */ sumrsq = rsq + rsq; root = 2.0*sumrsq*distsq - distsq*distsq; if (root > -ACCY) { /* Sirklene skjærer eller tangerer */ beregnet = 1; dstinv = 0.5 / distsq; a = a21 * 0.5 + a1; n = n21 * 0.5 + n1; if (root > ACCY) { /* 2 skjæringspunkter */ root = dstinv * sqrt(root); afac = a21 * root; nfac = n21 * root; if ((radius < 0.0 && storbue == 0) || (radius > 0.0 && storbue == 1) ) { *as = a - nfac; /* Bruker 1. skjæringspunkt */ *ns = n + afac; } else { *as = a + nfac; /* Bruker 2. skjæringspunkt */ *ns = n - afac; } } else { /* Tangering */ *as = a; *ns = n; } /* Beregn retninger fra sentrum til start og sluttpunkt */ *fi = GM_retning(*as,*ns,a1,n1); /* S - K */ f1 = *fi; fi2 = GM_retning(*as,*ns,a2,n2); /* S - L */ /* Beregner retningsavvik */ if (radius < 0.0) { if (fi2 < f1) fi2 += (PI*2.0); } else { if (f1 < fi2) f1 += (PI*2.0); } *dfi = fi2 - f1; } } return beregnet; } /* AR-890723 CH GM_KonvBuep Omregning til intern bue-angivelse CD ========================================================================== CD Formål: CD Omregning til intern bue-angivelse med sirkelsentrum, radius og retning CD til buens start samt delta for sluttpunktet. CD NB! Retningen oppgis i radianer, med retning 0 i øst-aksen, og med positiv CD omløpsretning mot urviseren. Alle vinkler er i området 0 - 2PI. CD Metode: Se Bowyer and Woodwark: AProgrammer's Geometry, CD side 27-28 og 35-36. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double a1 i Koordinat i P1 (startpunkt) CD double n1 i CD double a2 i Koordinat i P2 (punkt på buen) CD double n2 i CD double a3 i Koordinat i P3 (sluttpunkt) CD double n3 i CD double *as u Koordinat i sentrumspunktet CD double *ns u CD double *radius u Buens radius CD double *fi u "Retning" sentrum - punkt 1. CD double *dfi u Vinkel mellom fi og retning sentrum - punkt 3. CD short beregnet r 0=kan ikke beregne, 1=bregnet ok. CD CD Bruk: CD ok = GM_KonvBuep(a1,n1,a2,n2,a3,n3,&as,&ns,&radius,&fi,&dfi); ========================================================================== */ SK_EntPnt_GM short GM_KonvBuep(double a1,double n1,double a2,double n2,double a3,double n3, double *as,double *ns,double *radius,double *fi,double *dfi) { double ap,np,fi2,fi3,dfi2,dfi3; double pa1,pb1,pc1,pa2,pb2,pc2,pa3,pb3,pc3; short beregnet = 0; /* Parametre for linjen 1 - 3 */ if(GM_bepa(a1,n1,a3,n3,&pa1,&pb1,&pc1)){ /* Midtpunktet mellom 1 og 3 */ ap = a1 + (a3-a1) / 2.0; np = n1 + (n3-n1) / 2.0; /* Parametre for midtlinjen mellom 1 og 3 */ pa3=pb1; pb3=-pa1; pc3=pa1*np-pb1*ap; /* Parametre for linjen 1 - 2 */ if(GM_bepa(a1,n1,a2,n2,&pa1,&pb1,&pc1)){ /* Midtpunktet mellom 1 og 2 */ ap = a1 + (a2-a1) / 2.0; np = n1 + (n2-n1) / 2.0; /* Parametre for midtlinjen mellom 1 og 2 */ pa2=pb1; pb2=-pa1; pc2=pa1*np-pb1*ap; /* Sentrum er skjæringspunktet mellom de to linjene */ if (GM_cint(pa3,pb3,pc3,pa2,pb2,pc2,as,ns)){ *radius = sqrt((*as-a1)*(*as-a1) + (*ns-n1)*(*ns-n1)); /* Beregn retninger fra sentrum til start og sluttpunkt */ *fi = GM_retning(*as,*ns,a1,n1); /* S - P1 */ fi2 = GM_retning(*as,*ns,a2,n2); /* S - P2 */ fi3 = GM_retning(*as,*ns,a3,n3); /* S - P3 */ /* Beregner retningsavvik */ dfi2 = fi2 - *fi; dfi3 = fi3 - *fi; /* Positiv delta ? */ if (dfi2 < 0.0) dfi2 += (PI*2.0); if (dfi3 < 0.0) dfi3 += (PI*2.0); if (dfi2 <= dfi3){ *dfi = dfi3; } else{ /* Negativ delta */ if (dfi3 > 0.0) dfi3 -= (PI*2.0); *dfi = dfi3; } beregnet = 1; } } } return beregnet; } /* AR-911029 CH GM_KonvSirkel Omregning til intern bue-angivelse CD ========================================================================== CD Formål: CD Omregning til intern bue-angivelse med sirkelsentrum, radius og retning CD til buens start samt delta for sluttpunktet. CD NB! Retningen oppgis i radianer, med retning 0 i øst-aksen, og med positiv CD omløpsretning mot urviseren. Alle vinkler er i området 0 - 2PI. CD Metode: Se Bowyer and Woodwark: AProgrammer's Geometry, CD side 27-28 og 35-36. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double *as iu Koordinat i sentrumspunktet CD double *ns iu CD double *radius iu Buens radius CD double *fi u "Startretning" sentrum - punkt 1. CD double *dfi u "Åpningsvinkel" (2PI). CD short ist r 1 = OK, 0 = ikke beregnet. CD CD Bruk: CD ist = GM_KonvSirkel(&as,&ns,&radius,&fi,&dfi); ========================================================================== */ SK_EntPnt_GM short GM_KonvSirkel(double *fi,double *dfi) { *fi = 0.0; *dfi = 2.0 * PI; return 1; } /* AR-911029 CH GM_KonvSirkelp Omregning til intern bue-angivelse CD ========================================================================== CD Formål: CD Omregning til intern bue-angivelse med sirkelsentrum, radius og retning CD til buens start samt delta for sluttpunktet. CD NB! Retningen oppgis i radianer, med retning 0 i øst-aksen, og med positiv CD omløpsretning mot urviseren. Alle vinkler er i området 0 - 2PI. CD Metode: Se Bowyer and Woodwark: AProgrammer's Geometry, CD side 27-28 og 35-36. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double a1 i Koordinat i P1 (punkt på buen) CD double n1 i CD double a2 i Koordinat i P2 (punkt på buen) CD double n2 i CD double a3 i Koordinat i P3 (punkt på buen) CD double n3 i CD double *as u Koordinat i sentrumspunktet CD double *ns u CD double *radius u Buens radius CD double *fi u "Retning" sentrum - start av buen (0) CD double *dfi u Åpningsvinkel (2*PI) CD short beregnet r 1 = OK; 0 = kan ikke beregne. CD CD Bruk: CD ist = GM_KonvSirkelp(a1,n1,a2,n2,a3,n3,&as,&ns,&radius,&fi,&dfi); ========================================================================== */ SK_EntPnt_GM short GM_KonvSirkelp(double a1,double n1,double a2,double n2,double a3,double n3, double *as,double *ns,double *radius,double *fi,double *dfi) { double ap,np; double pa1,pb1,pc1,pa2,pb2,pc2,pa3,pb3,pc3; short beregnet = 0; /* Parametre for linjen 1 - 3 */ if(GM_bepa(a1,n1,a3,n3,&pa1,&pb1,&pc1)){ /* Midtpunktet mellom 1 og 3 */ ap = a1 + (a3-a1)/2.0; np = n1 + (n3-n1)/2.0; /* Parametre for midtlinjen mellom 1 og 3 */ pa3=pb1; pb3=-pa1; pc3=pa1*np-pb1*ap; /* Parametre for linjen 1 - 2 */ if(GM_bepa(a1,n1,a2,n2,&pa1,&pb1,&pc1)){ /* Midtpunktet mellom 1 og 2 */ ap = a1 + (a2-a1)/2.0; np = n1 + (n2-n1)/2.0; /* Parametre for midtlinjen mellom 1 og 2 */ pa2=pb1; pb2=-pa1; pc2=pa1*np-pb1*ap; /* Sentrum er skjæringspunktet mellom de to linjene */ if (GM_cint(pa3,pb3,pc3,pa2,pb2,pc2,as,ns)){ *radius = sqrt((*as-a1)*(*as-a1) + (*ns-n1)*(*ns-n1)); /* Beregn retninger fra sentrum til start og sluttpunkt */ *fi = GM_retning(*as,*ns,a1,n1); *dfi = 2.0 * PI; beregnet = 1; } } } return beregnet; } /* AR-881018 CH GM_bepa Linjeparametre CD ========================================================================== CD Formål: CD Beregner parametrene for linjen gjennom 1 og 2. CD Ligningen for linjen er: (AX+BY+C=0). CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double a1 i Koordinat i 1 CD double n1 i CD double a2 i Koordinat i 2 CD double n2 i CD double *pa u Parametre for linjen CD double *pb u CD double *pc u CD short ist r 1=beregnet, 0=ikke beregnet (1 og 2 er samme punkt) CD CD Bruk: CD ist = GM_bepa(a1,n1,a2,n2,&pa,&pb,&pc); ========================================================================== */ SK_EntPnt_GM short GM_bepa(double a1, double n1, double a2, double n2, double *pa, double *pb, double *pc) { double ndif,adif,rinv,atmp,ntmp,dmn,dmx,div; adif = a2-a1; atmp = fabs(adif); ndif = n2-n1; ntmp = fabs(ndif); if(atmp > ACCY || ntmp > ACCY) { dmx = max(atmp,ntmp); dmn = min(atmp,ntmp); div = dmn / dmx; rinv = 1.0 / (dmx * sqrt(1.0+div*div)); *pa = -ndif*rinv; *pb = adif*rinv; //*pc = (a1*n2 - a2*n1) * rinv; { double d1 = a1*n2; double d2 = a2*n1; double d3 = d1 - d2; *pc = d3 * rinv; } // -56430.600006104 return (1); } else { *pa = *pb = *pc = 0.0; return (0); } } /* AR-940522 CH GM_bepa3 3D-Linjeparametre CD ========================================================================== CD Formål: CD Beregner 3D parametrene for linjen gjennom 1 og 2. CD Ligningen for linjen er: (AX+BY+C=0). CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double a1 i Koordinat i 1 CD double n1 i CD double h1 i CD double a2 i Koordinat i 2 CD double n2 i CD double h2 i CD double *pf u Parametre for linjen CD double *pg u CD double *ph u CD short ist r 1=beregnet, 0=ikke beregnet (1 og 2 er samme punkt) CD CD Bruk: CD ist = GM_bepa3(a1,n1,h1,a2,n2,h2,&pa,&pb,&pc); ========================================================================== */ SK_EntPnt_GM short GM_bepa3(double a1, double n1, double h1, double a2, double n2, double h2, double *pf, double *pg, double *ph) { double ndif,adif,hdif,rsq,rinv; ndif = n2-n1; adif = a2-a1; hdif = h2-h1; rsq = ndif*ndif + adif*adif + hdif*hdif; if(rsq > ACCY){ rinv = 1.0 / sqrt(rsq); *pf = adif * rinv; *pg = ndif * rinv; *ph = hdif * rinv; return (1); } else{ *pf = *pg = *ph = 0.0; return (0); } } /* AR-890717 CH GM_cint Skjæring mellom to linjer CD ========================================================================== CD Formål: CD Beregner kryssingspunktet mellom to linjer. CD Linjene er gitt på implisitt form. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double pa1 i Parametre for linje 1 CD double pb1 i CD double pc1 i CD double pa2 i Parametre for linje 2 CD double pb2 i CD double pc2 i CD double *as u Koordinat i skjæringspunktet CD double *ns u CD short kryss r 1=beregnet, 0=ikke beregnet (pralelle linjer) CD CD Bruk: CD kryss = GM_cint(pa1,pb1,pc1,pa2,pb2,pc2,&as,&ns); ========================================================================== */ SK_EntPnt_GM short GM_cint(double pa1, double pb1, double pc1, double pa2, double pb2, double pc2, double *as, double *ns) { double det,dinv; /* Beregner skjæringspunktet mellom linjene på implicit form */ det = pa1*pb2 - pa2*pb1; if (fabs(det) > ACCY){ dinv = 1.0/det; *as = (pb1*pc2 - pb2*pc1) * dinv; *ns = (pa2*pc1 - pa1*pc2) * dinv; return(1); } else{ *ns = *as = 0.0; return(0); } } /* JEK-920514 CH GM_Vinkel Beregner vinkel mellom to retninger CD ================================================================== CD Formål: CD Beregner positiv vinkel mellom to retninger fi1 og fi2. CD CD PARAMETERLISTE: CD Navn Type Array i/U Merknad CD ------------------------------------------------------------------ CD fi1 double i Retningsvinkel 1 CD fi2 double i retningsvinkel 2 CD vinkel double r Positiv vinkel i rad. mellom fi1 og fi2 CD Alltid i området 0 - 2PI. CD CD Bruk : vinkel = GM_Vinkel(fi1,fi2); ================================================================== */ SK_EntPnt_GM double GM_Vinkel(double fi1, double fi2) { return GM_RedVinkel(fi2 - fi1); } /* JEK-920514 CH GM_RedVinkel Beregner en retn.vinkel i omr. 0-2*PI CD ================================================================== CD Formål: CD Redusere en retningsvinkel til å ligge i området 0 - 2*PI. CD CD PARAMETERLISTE: CD Navn Type Array i/U Merknad CD ------------------------------------------------------------------ CD fi double i Retningsvinkel CD vinkel double r Redusert vinkel CD CD Bruk: red_vinkel = GM_RedVinkel(fi); ================================================================== */ SK_EntPnt_GM double GM_RedVinkel(double dFi) { double topi = 2.0*PI; double vinkel = dFi; while ( vinkel < 0.0 || vinkel > topi ) { if ( vinkel < 0.0 ) { vinkel += topi; } if ( vinkel > topi ) { vinkel -= topi; } } return vinkel; } /* AR-901021 CH GM_retning Retning mellom to punkt CD ========================================================================== CD Formål: CD Beregner retning fra et punkt til et annet (K-L). CD (Rutinen er spesiellt beregnet for å beregne retningsvinkler for buer.) CD NB! Retningen oppgis i radianer, med retning 0 i øst-aksen, og med positiv CD omløpsretning mot urviseren. CD CD *L CD / CD / CD / CD K* CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double ak i Koordinat i K. CD double nk i CD double al i Koordinat i L. CD double nl i CD double retning r Retning K-L. CD CD Bruk: CD retning = GM_retning(ak,nk,al,nl); ========================================================================== */ SK_EntPnt_GM double GM_retning(double ak,double nk,double al,double nl) { double retning; double da = al - ak; double dn = nl - nk; // Beregner retning if (fabs(da) < ACCY && fabs(dn) < ACCY) { retning = 0.0; } else { retning = atan2(dn,da); } // Juster til positiv retningen if (retning < 0.0) { retning += PI * 2.0; } return retning; } /* GL-910709 CH GM_RetnGon Beregner retningsvinkel mellom 2 punkt CD ========================================================================== CD Bruk : r = GM_RetnGon(a1,n1,a2,n2) CD ========================================================================== */ SK_EntPnt_GM double GM_RetnGon(double a1 , double n1, double a2, double n2) { double r; double da = a2 - a1; double dn = n2 - n1; /* Beregner retning */ if (fabs(da) < ACCY && fabs(dn) < ACCY) { r = 0.0; } else { r = atan2(da,dn); } r = Rad2Gon(r); if (r < 0.0) r += 400.0; return r; } /* GL-910709 CH GM_RettvPol Beregner polare koord.(retnvinkel og avstand) CD ========================================================================== CD Bruk : GM_RettvPol(a1,n1,a2,n2,&gon,&avst) CD ========================================================================== */ SK_EntPnt_GM void GM_RettvPol(double a1 , double n1, double a2, double n2, double *gon, double *avst) { *gon =GM_RetnGon(a1,n1,a2,n2); *avst=sqrt((a2-a1)*(a2-a1)+(n2-n1)*(n2-n1)); } /* CH GM_Areal Beregner areal av polygon CD ========================================================================== CD Formål: CD Beregner areal av polygon. CD Forutsetter at polygonet er lukket. (Første og siste punkt er like.) CD CD PARAMETERLISTE: CD Navn Type I/U Merknad CD -------------------------------------------------------------------------- CD pA *double i Øst-koordinater CD pN *double i Nord-koordinater CD sNko short i Antall koordinater CD dAreal double r Areal m^2 CD CD Bruk: areal = GM_Areal ( pA, pN, sAnt ); ========================================================================== */ SK_EntPnt_GM double GM_Areal(double *pA, double *pN, short sAnt) { double dAreal = 0.0; double a_forrige,n_forrige; short s = 1; if (sAnt > 2) { a_forrige = *pA; n_forrige = *pN; for ( ; s ((2.0*PI)-ACCY)) { *nva = as - r; *nvn = ns - r; *oha = as + r; *ohn = ns + r; return; // ==> } // ----- Andre buer // Starter med omskrevet boks for endepunktene a1 = as + r*cos(fi); n1 = ns + r*sin(fi); a2 = as + r*cos(fi+dfi); n2 = ns + r*sin(fi+dfi); *nva = min(a1,a2); *nvn = min(n1,n2); *oha = max(a1,a2); *ohn = max(n1,n2); // For hver akse (fra sentrumspunktet) som krysses utvides omskrevet boks radius = fabs(radius); if (GM_TestPktBue(as, ns, fi, dfi, as+radius, ns)) *oha = as+radius; if (GM_TestPktBue(as, ns, fi, dfi, as-radius, ns)) *nva = as-radius; if (GM_TestPktBue(as, ns, fi, dfi, as, ns+radius)) *ohn = ns+radius; if (GM_TestPktBue(as, ns, fi, dfi, as, ns-radius)) *nvn = ns-radius; } /* Gammel versjon double r2; double r = fabs(radius); double a1,n1,a2,n2; // ----- Hel sirkel if (fabs(dfi) > ((2.0*PI)-ACCY)) { *nva = as - r; *nvn = ns - r; *oha = as + r; *ohn = ns + r; return; // ==> } // ----- Andre buer a1 = as + r*cos(fi); n1 = ns + r*sin(fi); a2 = as + r*cos(fi+dfi); n2 = ns + r*sin(fi+dfi); // Beregn sorterte retninger if (dfi < 0.0){ r2 = fi; fi += dfi; } else{ r2 = fi + dfi; } // Sørg for at alle vinkler ligger i området 0 - 2*PI while (fi < 0.0){ // fi fi += (2.0*PI); } while (fi > (2.0*PI)){ fi -= (2.0*PI); } while (r2 < 0.0){ // r2 r2 += (2.0*PI); } while (r2 > (2.0*PI)){ r2 -= (2.0*PI); } // Beregner omskreven firkant for buen // Start i 1. kvadrant if (fi >= 0.0 && fi < PI/2.0){ // Slutt i 1. kvadrant if (r2 >= 0.0 && r2 < PI/2.0){ *nva = min(a1,a2); *nvn = min(n1,n2); *oha = max(a1,a2); *ohn = max(n1,n2); // Slutt i 2. kvadrant } else if (r2 >= PI/2.0L && r2 < PI){ *nva = min(a1,a2); *nvn = min(n1,n2); *oha = max(a1,a2); *ohn = ns + r; // Slutt i 3. kvadrant } else if (r2 >=PI && r2 < PI*3.0L/2.0L){ *nva = as - r; *nvn = min(n1,n2); *oha = max(a1,a2); *ohn = ns + r; // Slutt i 4. kvadrant } else{ *nva = as - r; *nvn = ns - r; *oha = max(a1,a2); *ohn = ns + r; } // Start i 2. kvadrant } else if (fi >= PI/2.0L && fi < PI){ // Slutt i 1. kvadrant if (r2 >= 0.0 && r2 < PI/2.0){ *nva = as - r; *nvn = ns - r; *oha = as + r; *ohn = max(n1,n2); // Slutt i 2. kvadrant } else if (r2 >= PI/2.0L && r2 < PI){ *nva = min(a1,a2); *nvn = min(n1,n2); *oha = max(a1,a2); *ohn = max(n1,n2); // Slutt i 3. kvadrant } else if (r2 >=PI && r2 < PI*3.0L/2.0L){ *nva = as - r; *nvn = min(n1,n2); *oha = max(a1,a2); *ohn = max(n1,n2); // Slutt i 4. kvadrant } else{ *nva = as - r; *nvn = ns - r; *oha = max(a1,a2); *ohn = max(n1,n2); } // Start i 3. kvadrant } else if (fi >=PI && fi < PI*3.0L/2.0L){ // Slutt i 1. kvadrant if (r2 >= 0.0 && r2 < PI/2.0){ *nva = min(a1,a2); *nvn = ns - r; *oha = as + r; *ohn = max(n1,n2); // Slutt i 2. kvadrant } else if (r2 >= PI/2.0L && r2 < PI){ *nva = min(a1,a2); *nvn = ns - r; *oha = as + r; *ohn = ns + r; // Slutt i 3. kvadrant } else if (r2 >=PI && r2 < PI*3.0L/2.0L){ *nva = min(a1,a2); *nvn = min(n1,n2); *oha = max(a1,a2); *ohn = max(n1,n2); } else{ // Slutt i 4. kvadrant *nva = min(a1,a2); *nvn = ns - r; *oha = max(a1,a2); *ohn = max(n1,n2); } // Start i 4. kvadrant } else { // Slutt i 1. kvadrant if (r2 >= 0.0 && r2 < PI/2.0) { *nva = min(a1,a2); *nvn = min(n1,n2); *oha = as + r; *ohn = max(n1,n2); // Slutt i 2. kvadrant } else if (r2 >= PI/2.0L && r2 < PI) { *nva = min(a1,a2); *nvn = min(n1,n2); *oha = as + r; *ohn = ns + r; // Slutt i 3. kvadrant } else if (r2 >=PI && r2 < PI*3.0L/2.0L) { *nva = as - r; *nvn = min(n1,n2); *oha = as + r; *ohn = ns + r; // Slutt i 4. kvadrant } else { *nva = min(a1,a2); *nvn = min(n1,n2); *oha = max(a1,a2); *ohn = max(n1,n2); } } } */ // ++---------------------------------------------------------------------- // FILE: Arc.cpp - Implementation for class QdiArc // ++---------------------------------------------------------------------- // For å finne minste omsluttende rektangel til en bue må en først finne sentrum //til buen. Koden for å gjøre dette fantes allerede i geometryutility.dll, men for å //unngå gjensidige avhengigheter mellom modellen og geometryutility.dll, kopierte jeg //og skrev om koden her. // //Etter at sentrum er funnet, finner jeg hvor mange akser som buen skjærer. For hver akse //buen skjærer, hentes en ekstremalverdi fra minste omsluttende rektangel til en //SIRKEL som har sentrum samme sted som buen. // //Buen kan skjære 0, en, to, tre eller fire akser. // // | // | // --|- // / | \ - // 1 | \ - // ----------2---|------- // | | // | 3/ // | // // //På eksempelfiguren ovenfor skjæres 2 akser (y-aksen en gang og x-aksen en gang. //Her vil minste omsluttende rektangel hente LLX fra 1, LLY fra 3, URX fra sirkel //og URY fra sirkel. (Med sirkel menes sirkelens senter +/- radius eller minste omsluttende //rektangel til en sirkel med samme senter og radius) // /* void QdiArc::computeBbox( QdiRectangle *pRectangle ) { //Regner først ut senter av sirkelen bool bMajor = isMajor(); QdiPosition *pStart= dynamic_cast (getStartPosition()->clone()); QdiPosition *pEnd= dynamic_cast (getEndPosition()->clone()); double dRadius= getRadius(); double dMin= 0.0009; QdiPosition2D center1, center2, trueCenter; double dH = 0; double dRadi1= dRadius; double dRadi2= dRadius; double dX= pEnd->getX()- pStart->getX(); double dY= pEnd->getY()- pStart->getY(); double dDist= sqrt((dX*dX) + (dY*dY)); double dInterX1= (((dRadi1*dRadi1) - (dRadi2*dRadi2))/(dDist*2)) + (dDist/2); double dInterX1Abs= fabs(dInterX1); if ( fabs(dInterX1Abs-fabs(dRadi1)) < dMin ) dH= 0.0; // Only one intersection point. else dH= sqrt( fabs((dRadi1*dRadi1)- (dInterX1*dInterX1)) ); double dAspectX= dX/dDist; double dAspectY= dY/dDist; center1.setX(pStart->getX() + (dAspectX*dInterX1) + (dAspectY*dH)); center1.setY(pStart->getY() + (dAspectY*dInterX1) - (dAspectX*dH)); center2.setX(pStart->getX() + (dAspectX*dInterX1) - (dAspectY*dH)); center2.setY(pStart->getY() + (dAspectY*dInterX1) + (dAspectX*dH)); if (!bMajor) { if ( dRadi1>= 0 ) { trueCenter.setX(center1.getX()); trueCenter.setY(center1.getY()); } else if ( dRadi1< 0) { trueCenter.setX(center2.getX()); trueCenter.setY(center2.getY()); } } // Use the "big/major arc" center else { if ( dRadi1< 0 ) { trueCenter.setX(center1.getX()); trueCenter.setY(center1.getY()); } else if ( dRadi1>= 0) { trueCenter.setX(center2.getX()); trueCenter.setY(center2.getY()); } } // Regner ut hvor mange akser som krysses // 1 startPos // 2 trueCenter // 3 endPos int nStartQuadrant = 0; int nEndQuadrant = 0; double dMostLeft; double dMostRight; double dHighest; double dLowest; // Finner ekstremalverdiene. dMostLeft = pStart->getX(); if (dMostLeft > pEnd->getX()) { dMostLeft = pEnd->getX(); } dMostRight = pStart->getX(); if (dMostRight < pEnd->getX()) { dMostRight = pEnd->getX(); } dHighest = pStart->getY(); if (dHighest < pEnd->getY()) { dHighest = pEnd->getY(); } dLowest = pStart->getY(); if (dLowest > pEnd->getY()) { dLowest = pEnd->getY(); } // Om radius er negativ, byttes start og sluttpunkt if (dRadius < 0) { QdiPosition2D midlPos; midlPos.setX(pStart->getX()); midlPos.setY(pStart->getY()); pStart->setX(pEnd->getX()); pStart->setY(pEnd->getY()); pEnd->setX(midlPos.getX()); pEnd->setY(midlPos.getY()); } // Finner hvor mange akser som krysses og hvilke kvadranter punktene ligger i if (pStart->getX() > trueCenter.getX()) { if (pStart->getY() > trueCenter.getY()) { // Kvadrant 4 nStartQuadrant = 4; } else { // Kvadrant 1 nStartQuadrant = 1; } } else { if (pStart->getY() > trueCenter.getY()) { // Kvadrant 3 nStartQuadrant = 3; } else { // Kvadrant 2 nStartQuadrant = 2; } } if (pEnd->getX() > trueCenter.getX()) { if (pEnd->getY() > trueCenter.getY()) { // Kvadrant 4 nEndQuadrant = 4; } else { // Kvadrant 1 nEndQuadrant = 1; } } else { if (pEnd->getY() > trueCenter.getY()) { // Kvadrant 3 nEndQuadrant = 3; } else { // Kvadrant 2 nEndQuadrant = 2; } } int nQuadrants = 0; if (nStartQuadrant > nEndQuadrant) { nQuadrants = 4 + (nEndQuadrant - nStartQuadrant); } else { nQuadrants = nEndQuadrant - nStartQuadrant; } if (bMajor) { // Hvis bMajor er sant, så går buen over 4 kvadranter om start og endepunkt er // i samme kvadrant. if (nQuadrants == 0) { nQuadrants = 4; } } // Lager først en bounding box av en sirkel. QdiPosition2D* llPos = new QdiPosition2D; QdiPosition2D* urPos = new QdiPosition2D; llPos->setX(trueCenter.getX() - abs(dRadius)); llPos->setY(trueCenter.getY() - abs(dRadius)); urPos->setX(trueCenter.getX() + abs(dRadius)); urPos->setY(trueCenter.getY() + abs(dRadius)); if (nQuadrants == 4) { } else if (nQuadrants == 3) { if (nStartQuadrant == 1) { urPos->setX(dMostRight); } else if (nStartQuadrant == 2) { llPos->setY(dLowest); } else if (nStartQuadrant == 3) { llPos->setX(dMostLeft); } else if (nStartQuadrant == 4) { urPos->setY(dHighest); } } else if (nQuadrants == 2) { if (nStartQuadrant == 1) { urPos->setX(dMostRight); urPos->setY(dHighest); } else if (nStartQuadrant == 2) { llPos->setY(dLowest); urPos->setX(dMostRight); } else if (nStartQuadrant == 3) { llPos->setX(dMostLeft); llPos->setY(dLowest); } else if (nStartQuadrant == 4) { llPos->setX(dMostLeft); urPos->setY(dHighest); } } else if (nQuadrants == 1) { if (nStartQuadrant == 1) { urPos->setX(dMostRight); urPos->setY(dHighest); llPos->setX(dMostLeft); } else if (nStartQuadrant == 2) { llPos->setY(dLowest); urPos->setX(dMostRight); urPos->setY(dHighest); } else if (nStartQuadrant == 3) { llPos->setX(dMostLeft); llPos->setY(dLowest); urPos->setX(dMostRight); } else if (nStartQuadrant == 4) { llPos->setX(dMostLeft); urPos->setY(dHighest); llPos->setY(dLowest); } } else if (nQuadrants == 0) { urPos->setX(dMostRight); urPos->setY(dHighest); llPos->setX(dMostLeft); llPos->setY(dLowest); } //pRectangle->setLowerLeft(llPos); pRectangle->expand( llPos ); //pRectangle->setUpperRight(urPos); pRectangle->expand( urPos ); delete pStart; delete pEnd; return; } // Get implicitly defined startPosition //const QdiPosition* QdiArc::getStartPosition() const { return NULL; } // Dummy // Get implicitly defined endPosition //const QdiPosition* QdiArc::getEndPosition() const { return NULL; } // Dummy // -------------------------- End of file --------------------------------- */ /* AR-890903 CH GM_NormVindu Normaliser vindusangivelse CD ========================================================================== CD Formål: CD Bytter om koordinatene slik at vindusangivelsen blir riktig. CD Sjekker også at vinduet har lengde > 0.0001 i både øst og nord retning. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double *nva iu Avgrensing av vinduet CD double *nvn iu CD double *oha iu CD double *ohn iu CD short ist r status: 1 = Vinduet er OK CD 0 = Vinduet er feil definert. CD (Lengde 0.0 i en retning.) CD CD Bruk: CD ist = GM_NormVindu(&nva,&nvn,&oha,&ohn); ========================================================================== */ SK_EntPnt_GM short GM_NormVindu(double *nva,double *nvn,double *oha,double *ohn) { double temp; if (*nva > *oha){ /* Eventuell ombytting av hjørnekoordinater */ temp = *nva; *nva = *oha; *oha = temp; } if (*nvn > *ohn){ temp = *nvn; *nvn = *ohn; *ohn = temp; } /* Sjekk at lengden av vinduet er > 0.0 i begge retninger */ return (short)((*oha-*nva) > ACCY && (*ohn - *nvn) > ACCY); } /* AR-890903 CH GM_TestPktBue Sjekk om punkt ligger i sektor gitt av bue CD ========================================================================== CD Formål: CD Sjekk om punkt ligger i sektor gitt av bue. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double as i Koordinat i sirkelsenter CD double ns i CD double fi i "Retning" sentrum - buens startpunkt. CD double dfi i Vinkel mellom fi og retning buens sluttpunkt CD double a i Koordinat som skal testes CD double n i CD short ok r 1=ligger i buens sektor, 0=ikke i buens sektor CD CD Bruk: CD ok = GM_TestPktBue(as,ns,fi,dfi,a,n); ========================================================================== */ SK_EntPnt_GM short GM_TestPktBue(double as,double ns,double fi,double dfi, double a,double n) { double fi1,d; short ok = 1; // Sjekk om punktene ligger på buen fi1 = GM_retning(as,ns,a,n); d = fi1 - fi; if (dfi < 0.0){ if (d > 0.0) d -= (PI * 2.0); //if (d < dfi) ok = 0; /* Utenfor buen */ if ((d+GM_ACCY) < dfi) ok = 0; /* Utenfor buen */ } else{ if (d < 0.0) d += (PI * 2.0); //if (d > dfi) ok = 0; /* Utenfor buen */ if ((d-GM_ACCY) > dfi) ok = 0; /* Utenfor buen */ } return ok; } /* AR-890903 CH GM_PktBue Beregner vinkel til punkt i sektor gitt av bue CD ========================================================================== CD Formål: CD Beregner vinkel til punkt som ligger i sektor gitt av bue. CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double as i Koordinat i sirkelsenter CD double ns i CD double fi i "Retning" sentrum - buens startpunkt. CD double dfi i Vinkel mellom fi og retning buens sluttpunkt CD double a i Punkt som skal testes CD double n i CD double *dfiPkt u Vinkel mellom fi og retning til testpunktet CD short ok r 1=ligger i buens sektor, 0=ikke i buens sektor CD CD Bruk: CD ok = GM_PktBue(as,ns,fi,dfi,a,n,&dfiPkt); ========================================================================== */ SK_EntPnt_GM short GM_PktBue(double as,double ns,double fi,double dfi, double a,double n,double *dfiPkt) { double fi1; short ok = 1; //UT_FPRINTF(stderr,"\r\n I GM_PktBue: ns=%.12g, as=%.12g, fi=%.12g, dfi=%.12g",ns,as,fi,dfi); //UT_FPRINTF(stderr,"\n I GM_PktBue: n=%.12g, a=%.12g",n,a); // Sjekk om punktene ligger på buen fi1 = GM_retning(as,ns,a,n); //UT_FPRINTF(stderr,"\n I GM_PktBue: fi1=%.12g",fi1); *dfiPkt = fi1 - fi; // Spesialtilfelle for å handtere problemer når vinkelen blir tilnærmet 0.0 if (fabs(*dfiPkt) < GM_ACCY) { *dfiPkt = 0.0; return 1; // ==> } if (dfi < 0.0){ if (*dfiPkt > 0.0) *dfiPkt -= (PI * 2.0); if ((*dfiPkt+GM_ACCY) < dfi) ok = 0; /* Utenfor buen */ } else { if (*dfiPkt < 0.0) *dfiPkt += (PI * 2.0); if ((*dfiPkt-GM_ACCY) > dfi) ok = 0; /* Utenfor buen */ } return ok; } /* JEK-920520 CH GM_Avstand Beregner avstand mellom to punkt CD ================================================================== CD Formål: CD Beregner avstand mellom to punkt. CD CD PARAMETERLISTE: CD Navn Type Array i/U Merknad CD ------------------------------------------------------------------ CD a1 double i Øst-koordinat for startpunkt CD n1 double i Nord-koordinat for startpunkt CD a2 double i Øst-koordinat for endepunkt CD n2 double i Nord-koordinat for endepunkt CD avstand double r Avstand mellom punktene CD CD Bruk: avstand = GM_Avstand ( a1, n1, a2, n2 ); ================================================================== */ SK_EntPnt_GM double GM_Avstand(double a1, double n1, double a2, double n2 ) { double a,n; a = a2 - a1; n = n2 - n1; return sqrt( a*a + n*n ); } /* TOU/AR-080521 CH GM_Avstand Beregner kvadrert avstand mellom to punkt CD ================================================================== CD Formål: CD Beregner kvadrert avstand mellom to punkt. CD CD PARAMETERLISTE: CD Navn Type Array i/U Merknad CD ------------------------------------------------------------------ CD a1 double i Øst-koordinat for startpunkt CD n1 double i Nord-koordinat for startpunkt CD a2 double i Øst-koordinat for endepunkt CD n2 double i Nord-koordinat for endepunkt CD avstand2 double r Kvadrert avstand mellom punktene CD CD Bruk: avstand2 = GM_Avstand2 ( a1, n1, a2, n2 ); ================================================================== */ SK_EntPnt_GM double GM_Avstand2(double a1, double n1, double a2, double n2 ) { double a,n; a = a2 - a1; n = n2 - n1; return ( a*a + n*n ); } /* JEK-920520 CH GM_BueTangent Retnv. for tangent til punkt på bue CD ================================================================== CD Formål: CD Beregner retningsvinkel til tangent til punkt på en sirkelbue. CD CD PARAMETERLISTE: CD Navn Type I/U Merknad CD ----------------------------------------------------------------- CD as double i Øst-koordinat for sirkelsentrum CD an double i Nord-koordinat for sirkelsentrum CD fi double i Retningsvinkel til start bue CD dfi double i Retn.endring i radianer. CD + = mot klokka, - =med klokka CD radius double i radius med fortegn CD + = med klokka, - = mot klokka CD a double i Øst-koordinat for tangeringspunkt CD n double i Nord-koordinat for tangeringspunkt CD *buetan double u Retning i radianer(0-2PI) for buetangent CD ist short r status: 1 = Beregning ok CD 0 = Punkt ikke på buesegment CD NB! Tangent beregnes uansett! CD CD Bruk: ist = GM_BueTangent(as,ns,fi,dfi,radius,a,s,&buetan); ================================================================== */ SK_EntPnt_GM short GM_BueTangent ( double as, double ns, double fi, double dfi, double radius, double a, double n, double *buetan) { short ist; ist = 0; if ( GM_TestPktBue ( as, ns, fi, dfi, a, n ) ) { if ( (fabs(radius) - GM_Avstand (as,ns,a,n)) < 0.01 ) ist=1; } if ( dfi > 0.0 ){ /* Mot klokka */ *buetan = GM_RedVinkel ( GM_retning(as,ns,a,n) + PI/2 ); } else { /* Med klokka */ *buetan = GM_RedVinkel ( GM_retning(as,ns,a,n) - PI/2 ); } return ist; } /* LS-900607 AR-921001 CH GM_BueTilKorder Tilnærm ein sirkelboge med korder CD ========================================================================= CD Formål: CD Tilnærm ein sirkelboge med korder. CD CD PARAMETERLISTE: CD Type Navn I/U Merknad CD ------------------------------------------------------------------ CD double as i Øst-koordinat for sirkelsentrum CD double an i Nord-koordinat for sirkelsentrum CD double r i Radius i sirkelen CD double fi i Retningsvinkel til start bue CD double dfi i Retn.endring i radianer. CD + = mot klokka, - =med klokka CD double delta i Vinkeltoleranse (max vinkel mellom korder i radianer) CD short mpu i Max tal på punkt i a_arr og n_arr CD double *a_arr u Knekkpunkt før, mellom og etter kordene CD double *n_arr u CD short npu r Tal på punkt i a_arr og n_arr CD CD Bruk: CD npu = GM_BueTilKorder(as,ns,r,fi,dfi,delta,mpu,a_arr,n_arr); CD ========================================================================= */ SK_EntPnt_GM short GM_BueTilKorder (double as,double ns,double r,double fi,double dfi, double delta,short mpu,double *a_arr,double *n_arr) { double intdel; short nk,npu; r = fabs(r); /* Bestem presisjon (tal på korder) */ if (dfi < 0.0) delta = -delta; modf (dfi/delta, &intdel); nk = (short)(UT_RoundDS(intdel) + 1); if (nk >= mpu) { /* For mange korder - reduser kravet */ nk = (short)(mpu - 1); delta = dfi/(double)nk; } npu = (short)(nk + 1); /* Startpunktet */ *a_arr = as + r*cos(fi); *n_arr = ns + r*sin(fi); /* Sluttpunkt */ *(a_arr+nk) = as + r*cos(fi+dfi); *(n_arr+nk) = ns + r*sin(fi+dfi); /* Korde-løkke */ for (nk--,a_arr++,n_arr++,fi+=delta; nk; nk--,a_arr++,n_arr++,fi+=delta) { *a_arr = as + r*cos(fi); *n_arr = ns + r*sin(fi); } return npu; } /* LS-900607 AR-921001 CH GM_PktTilOktagon Beregner en åttekant rundt gitt punkt. CD ========================================================================= CD Formål: CD Beregner en åttekant med gitt areal rundt gitt punkt. CD CD PARAMETERLISTE: CD Type Navn I/U Merknad CD ------------------------------------------------------------------ CD double dAs i Øst-koordinat for sentrum CD double dNns i Nord-koordinat for sentrum CD double dAreal i Ønsket areal CD double *a_arr u Hjørnepunkt (Må ha plass til 8 punkt.) CD double *n_arr u CD CD Bruk: CD GM_PktTilOktagon(dAs,dNs,dAreal,a_arr,n_arr); CD ========================================================================= */ SK_EntPnt_GM void GM_PktTilOktagon (double dAs,double dNs,double dAreal,double *a_arr,double *n_arr) { double dS,dS2,dX; double d2Rot = sqrt(2.0); // 1 2 // +------------+ - - - - - // / \ | // / \ dX // / \ | // / \ _ // 8+ +3 // | | // | | // | + | dS // | s | // | | // 7+ +4 _ // \ / // \ / // \ / // \ / // +------------+ // 6 5 // Beregner sidelengde mm. dS = sqrt( dAreal / ( (2.0 * d2Rot) + 2.0)); dS2 = dS / 2.0; dX = dS2 * d2Rot; // Beregner koordineter // 1 *a_arr++ = dAs - dS2; *n_arr++ = dNs + dS2 + dX; // 2 *a_arr++ = dAs + dS2; *n_arr++ = dNs + dS2 + dX; // 3 *a_arr++ = dAs + dS2 + dX; *n_arr++ = dNs + dS2; // 4 *a_arr++ = dAs + dS2 + dX; *n_arr++ = dNs - dS2; // 5 *a_arr++ = dAs + dS2; *n_arr++ = dNs - dS2 - dX; // 6 *a_arr++ = dAs - dS2; *n_arr++ = dNs - dS2 - dX; // 7 *a_arr++ = dAs - dS2 - dX; *n_arr++ = dNs - dS2; // 8 *a_arr = dAs - dS2 - dX; *n_arr = dNs + dS2; } /* AR:2008-08-12 CH GM_TynnDared CD ========================================================================== CD Formål: CD Tynning med pilhøyde og maks avstand. CD Samme som SiTynnDared, men noe forenklet: CD - Koordinatene kommer inn i NØ buffer. CD - Handterer ikke høyde CD - Tar ikke hensyn til knutepunkt CD CD Parametre: CD Type Navn I/U Forklaring CD -------------------------------------------------------------------------- CD double dMaxAvst i Max distanse mellom punkta CD double dMaxPil i Max pilhøyde CD long *nko iu Antall koordinater CD double *pA iu Øst-koordinater CD double *pN iu Nord-koordinater CD bool bBeregnet r Status. CD Bruk: CD bBeregnet = GM_TynnDared(dMaxAvst,dPilhoyde,&nko,pA,pN); ========================================================================== */ SK_EntPnt_GM void GM_TynnDared(double dMaxAvst,double dMaxPil,long *nko, double *pA,double *pN) { long lTeller,lStorPnr=0; bool bNyttFastpunktFunnet; double a,n,a1,n1,a2,n2,ap,np,da,dn,dAvst2; double pa,pb,pc; double dPil,dStorPil; long lLagre = 2; // Peker for lagring av punkt (første ledig) long lForste = 1; // Starten av aktuelt segment long lSiste; // Siste punkt i segmentet double dMaxAvst2 = dMaxAvst * dMaxAvst; double dPil2 = dMaxPil * dMaxPil; bool bBeregnet = true; // Ta kopi av opprinnelige koordinater double *pdAust = (double*) malloc((sizeof(double))*(*nko)); UT_memcpy(pdAust, (sizeof(double))*(*nko), pA, (sizeof(double))*(*nko)); double *pdNord = (double*) malloc((sizeof(double))*(*nko)); UT_memcpy(pdNord, (sizeof(double))*(*nko), pN, (sizeof(double))*(*nko)); // UT_FPRINTF(stderr,"\n\nTynner: %s",LC_GetGi(1)); while (lForste < *nko) { // Sjekk ett segment. Segmentet avsluttes når: // - pilhøyden overskrider gitt verdi // (Det punktet som hadde størst pilhøyde blir neste fastpunkt) // - lengden overskrider gitt verdi //LC_GetTK(lForste,&a1,&n1); a1 = *(pA+lForste-1); n1 = *(pN+lForste-1); // UT_FPRINTF(stderr,"\n%hd a: %.1f n: %.1f",lForste,a1,n1); bNyttFastpunktFunnet = false; for (lSiste=lForste+1; !bNyttFastpunktFunnet && lSiste<=*nko; lSiste++) { // UT_FPRINTF(stderr,"\n\nSegment %hd - %hd",lForste,siste); //LC_GetTK(lSiste,&a2,&n2); a2 = *(pA+lSiste-1); n2 = *(pN+lSiste-1); // UT_FPRINTF(stderr,"\n%hd a: %.1f n: %.1f",lSiste,a2,n2); // Beregn største pilhøyde dStorPil = 0.0; for (lTeller=lForste+1; lTeller dStorPil) { lStorPnr = lTeller; dStorPil = dPil; } } // Max pilhøyde er overskredet, nytt fastpunkt er funnet // UT_FPRINTF(stderr,"\nMax pilhøyde %hd : %.4f",sStorPnr,dStorPil); if (dStorPil > dMaxPil) { //LC_GetTK(lStorPnr,&ap,&np); ap = *(pA+lStorPnr-1); np = *(pN+lStorPnr-1); //LC_PutTK(lLagre,ap,np); *(pA+lLagre-1) = ap; *(pN+lLagre-1) = np; // UT_FPRINTF(stderr,"\nLagres som punkt nr %hd",lagre); lLagre++; lForste = lStorPnr; bNyttFastpunktFunnet = true; } // Sjekk om max avstand er overskredet if ( ! bNyttFastpunktFunnet) { da = a2 - a1; dn = n2 - n1; dAvst2 = da*da + dn*dn; // UT_FPRINTF(stderr,"\nAvst %hd %hd : %.4f",forste,siste,sqrt(dAvst2)); if (dAvst2 > dMaxAvst2) { if (lSiste == lForste+1) { //LC_PutTK(lLagre,a2,n2); *(pA+lLagre-1) = a2; *(pN+lLagre-1) = n2; // UT_FPRINTF(stderr,"\nMax avst. overskredet, lagres som punkt nr %hd",lagre); lLagre++; lForste = lSiste; bNyttFastpunktFunnet = true; } else { //LC_GetTK(lSiste-1,&ap,&np); ap = *(pA+lSiste-1-1); np = *(pN+lSiste-1-1); //LC_PutTK(lLagre,ap,np); *(pA+lLagre-1) = ap; *(pN+lLagre-1) = np; // UT_FPRINTF(stderr,"\nMax avst. overskredet, lagres som punkt nr %hd",lagre); lLagre++; lForste = lSiste-1; bNyttFastpunktFunnet = true; } } // Siste punkt i gruppen er alltid fastpunkt if (lSiste == *nko) { // Sjekk at koordinatene er forskjellige fra forrige punkt if (lLagre > 1) { //LC_GetTK((short)(lLagre-1),&a,&n); a = *(pA+lLagre-1-1); n = *(pN+lLagre-1-1); if (fabs(a2-a) < ACCY && fabs(n2-n) < ACCY) { // Samme koordinater som forrige punkt, kutt ut dette lLagre--; } } //LC_PutTK(lLagre,a2,n2); *(pA+lLagre-1) = a2; *(pN+lLagre-1) = n2; // UT_FPRINTF(stderr,"\nSiste pkt., lagres som punkt nr %hd",lagre); lLagre++; lForste = lSiste; bNyttFastpunktFunnet = true; } } } } // ----- Sjekk at gruppen ikke har klappet sammen til en kort liten strek if (lLagre <= 3) { // Har 2 koordinater etter tynning, // legg tilbake opprinnelige koordinater bBeregnet = false; UT_memcpy(pA, (sizeof(double))*(*nko), pdAust, (sizeof(double))*(*nko)); UT_memcpy(pN, (sizeof(double))*(*nko), pdNord, (sizeof(double))*(*nko)); } else if (lLagre == 4) { // Har 3 koordinater etter tynning, og // avstand fra første til siste punkt er mindre enn pilhøyden da = (*(pA+lLagre-2)) - (*(pA)); dn = (*(pN+lLagre-2)) - (*(pN)); if ((da*da + dn*dn) < dPil2) { // Gruppen har blitt feil, legg tilbake opprinnelige koordinater bBeregnet = false; UT_memcpy(pA, (sizeof(double))*(*nko), pdAust, (sizeof(double))*(*nko)); UT_memcpy(pN, (sizeof(double))*(*nko), pdNord, (sizeof(double))*(*nko)); } } free(pdAust); free(pdNord); // Legg ut antall koordinater i resultatet if (bBeregnet) *nko = lLagre-1; } /* CH GM_BeregnHjelpepunkt CD ============================================================== CD Formål: CD Beskriv funksjonaliteten her ... CD CD CD CD *3 *2 CD / / CD n1* / CD / / CD / CD / n2* / CD / CD / n3* / CD / CD / / CD / CD / / CD / CD / / CD *1 CD CD Parameterliste: CD Type Navn I/U Merknad CD ------------------------------------------------------------- CD double dA1 i Koordinater punkt 1 CD double dN1 i CD double dA2 i Koordinater punkt 2 CD double dN2 i CD double dA3 i Koordinater punkt 3 CD double dN3 i CD double dEnhet i Enhet som styrer avrunding og beregning CD short sMaxAntPkt i Max antall punkt i pdAustArr og pdNordArr CD double *pdAustArr u Peker til array som mottar beregnede koordinater( n1 -nx CD double *pdNordArr u Peker til array som mottar beregnede koordinater CD short sAntPkt u Antall punkt beregnet CD bool bBeregnet r Status: true = beregnet OK CD false = ikke beregnet. (ikke nok plass i resultat-array, og andre feil?) CD CD Bruk: CD bStatus = GM_BeregnHjelpepunkt(dA1,dN1,dA2,dN2,dA3,dN3,dEnhet,sMaxAntPkt,&dAustArr,&pdNordArr,&sAntPkt); CD ============================================================== */ /* bool GM_BeregnHjelpepunkt(double dA1,double dN1,double dA2,double dN2,double dA3,double dN3,double dEnhet, short sMaxAntPkt,double *pdAustArr,double *pdNordArr,short *psAntPkt) { // Beskriv algoritme som brukes her ... // (Eventuelt med henvisning til bok med detaljbeskrivelse) bool bStatus = true; // Legg inn funksjonaliteten her ... return bStatus; } */