[ namespace @ 15.05.2010. 12:00 ] @
Imam problem sa razumevanjem sta se tacno trazi u ovom zadatku. Navescu tekst zadatka i neko moje razumevanje sta se trazi.

TEKST ZADATKA
Zadati su tekstualni fajlovi granice.txt i tacke.txt. U fajlu granice.txt se nalaze koordinate cetiri ugla pravougaonika. U fajlu tacke.txt se nalaze tacke zadate svojim koordinatama (x, y) i atributom z. Tacke su nasumicno rasporedjene po celom pravougaoniku.

Definisati strukture na sledeci nacin:
typedef struct strTacka
{
double x;
double y;
double z;
} tipTacka;
i
typedef struct strTackaD
{
double x;
double y;
double z;
double d;
} tipTackaD;

Kreirati jednostruko spregnutu listu L1 struktura tipTacka ucitavanjem tacaka iz fajla tacke.txt.

Napraviti funkciju: tipTackaD* dOkolina (int, int, int, tipTacka*);
koja za zadate vrednosti koordinata (x,y) (pripadaju pravougaoniku zadatom u fajlu granica.txt), i rastojanje d kreira novu listu tacaka L2. Nova lista sadrzi sve tacke iz L1 koje su od zadate tacke udaljene najvise za rastojanje d. Svaka tacka je opisana koordinatama (x, y), i atributima z (visina) i d (rastojanje od zadate tacke).

Realizovati test program.

Za realizaciju ovog zadatka korisno je realizovati i sledece funkcije:
double hipotenuza (double x, double y);
tipTacka* formirajL1(char*);

U ovoj poslednjoj funkciji neko je na papiru prepravio tipTacka* u LCVOR*

KAKO JA OVO SHVATAM
Da bi kreirala listu L1 treba da citam fajl tacke.txt , usput konvertujem stringove u brojeve, brojeve zapisujem u strukture tipTacka i pravim listu ciji su cvorovi ovakvi:
typedef struct cvor
{
tipTacka t;
cvor * sled;
} LCVOR;
To sve treba da bude u funkciji LCVOR* formirajL1 (char*) gde je povratna vrednost funkcije pokazivac na pocetak formirane liste, a ovaj argument bi mogao da bude ime fajla?

Druga lista L2 treba da sadrzi sve tacke iz prve liste L1 koje su od zadate tacke udaljene najvise za d.
Atribut z, nazvan negde i visina je ustvari treca koordinata.
Sve tacke, pa i zadata tacka pripadaju pravougaoniku. Za sve tacke znam koordinate x, y, i z, dok za zadatu tacku znam koordinate x i y, a ne znam z (ali znam da pripada pravougaoniku).


U funkciji tipTackaD* dOkolina (int, int, int, tipTacka*);
tipTackaD* je pokazivac na prvi cvor nove liste L2, tipTacka* je pokazivac na prvi cvor stare liste L1, ova tri int su x i y koordinate zadate tacke i zadato rastojanje.

Prvo bih volela da utvrdim da li sam dobro razumela sta se trazi, pa cu onda da trazim kako se racuna rastojanje izmedju zadate tacke i tacke.

[ Mihajlo Cvetanović @ 15.05.2010. 13:27 ] @
Sve si lepo shvatila. Z koordinatu centra sfere moraš da izračunaš, a onda za svaku datu tačku moraš da izračunaš udaljenost od ovog centra sfere.

Ne znam samo čemu bi služila predložena funkcija hipotenuza, kad ima samo dva parametra. Ono što ti treba je funkcija kojoj daš dve 3D tačke, a ona ti izračuna njihovu udaljenost. I treba ti funkcija koja će da izračuna Z koordinatu tačke ako su joj date X i Y koordinate, i ravan na kojoj se nalazi. A za ovo ti treba funkcija koja će da odredi ravan ako je dat pravougaonik u toj ravni.
[ namespace @ 15.05.2010. 18:08 ] @
Hvala. Ne znam ni ja čemu funkcija hipotenuza. Još mi je čudno i to što su koordinate zadate tačke i zadato rastojanje int a ne double.
Rastojanje između tačke (x1, y1, z1) i tačke (x2, y2, z2) je
sqrt((x1-x2)2+(y1-y1)2+(z1-z2)2)

Ravan je određena sa 3 tačke pa ću uzeti npr A(x1, y2, z3), B(x2, y2, z2) i C(x3, y3, z3):



[ namespace @ 17.05.2010. 16:16 ] @
Evo da stavim program koji sam uradila.

Code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

typedef struct strTacka
{
    double x;
    double y;
    double z;
} tipTacka;

typedef struct cvor
{
    tipTacka t;
    cvor * sled;
} LCVOR;

typedef struct strTackaD
{
    double x;
    double y;
    double z;
    double d;
} tipTackaD;

typedef struct cvorn
{
    tipTackaD t;
    cvorn * sled;
} LCVORN;

tipTacka string2brojevi (char s[])
{
    tipTacka N;
    char brx[20], bry[20], brz[20] ;
            
    int    i=0;
    int    j=0;

    while(s[i]!=' ' ) 
    {
        brx[j]=s[i];
        i++;
        j++;
    }
        
    brx[j]='\0';
    N.x=atof(brx);    

    i++;
    j=0;
    while(s[i]!=' ' ) 
    {
        bry[j]=s[i];
        i++;
        j++;
    }
    bry[j]='\0';
    N.y=atof(bry);
            
    i++;
    j=0;
    while(s[i]!='\n' ) 
    {
        brz[j]=s[i];
        i++;
        j++;
    }
    brz[j]='\0';
    N.z=atof(brz);

    return N;
}

double rastojanje2tacke (tipTacka T1, tipTacka T2)
{
    return sqrt ( (T1.x-T2.x)*(T1.x-T2.x)+(T1.y-T2.y)*(T1.y-T2.y)+(T1.z-T2.z)*(T1.z-T2.z) );
}

double z_zadato (tipTacka A, tipTacka B, tipTacka C, double Xz, double Yz)
{
    double a, b, c, d, e, f, g, h;
    double p1, p2, p3;
    a=Xz-A.x;
    b=Yz-A.y;
    c=B.x-A.x;
    d=B.y-A.y;
    e=B.z-A.z;
    f=C.x-A.x;
    g=C.y-A.y;
    h=C.z-A.z;
    p1=c*h-e*f;
    p2=d*h-e*g;
    p3=c*g-d*f;
    return (A.z+(b*p1-a*p2)/p3);
}
    


LCVOR* na_pocetak (LCVOR* lst, tipTacka b)
{
    LCVOR* novi;
    novi=(LCVOR*)malloc(sizeof(LCVOR));
    novi->t=b;
    novi->sled=lst;
    return novi;
}

LCVORN* na_pocetakn (LCVORN* lst, tipTackaD b)
{
    LCVORN* novi;
    novi=(LCVORN*)malloc(sizeof(LCVORN));
    novi->t=b;
    novi->sled=lst;
    return novi;
}

void pisi(LCVOR* lst)
{
    while(lst!=NULL)
    {
        printf(" %f %f %f ", lst->t.x, lst->t.y, lst->t.z);
        lst=lst->sled;
    }
}

void pisin(LCVORN* lst)
{
    while(lst!=NULL)
    {
        printf(" %f %f %f %f", lst->t.x, lst->t.y, lst->t.z, lst->t.d);
        lst=lst->sled;
    }
}


LCVOR* formirajL1 ( )
{
    char red[80],ime_dat[80];
    LCVOR* prvi=NULL; 
    tipTacka N;
    FILE *fp;
    
    printf("Ime datoteke koju cu da citam: ");
    gets(ime_dat);
    fp=fopen(ime_dat,"r");

    while (fgets(red, 80, fp)!=NULL)
    {
        printf("%s\n", red);
        N=string2brojevi (red);
        prvi=na_pocetak(prvi, N);
    }

    fclose(fp);

    return prvi;
}

LCVORN* dOkolina (double Xz, double Yz, double dz, LCVOR* prvis)
{
    tipTacka A, B, C, Tz, Ttek;
    tipTackaD D;
    LCVORN* prvin=NULL;
    double zz, d;
    char red[80];
    FILE* fp;
//cita tacke koje odredjuju ravan    
    fp=fopen("granice.txt", "r"); 
    fgets(red, 80, fp);
    A=string2brojevi (red);
    printf(" %f %f %f", A.x,  A.y,  A.z);
    fgets(red, 80, fp);
    B=string2brojevi (red);
    printf(" %f %f %f", B.x,  B.y,  B.z);
    fgets(red, 80, fp);
    C=string2brojevi (red);
    printf(" %f %f %f", C.x,  C.y,  C.z);
    fclose(fp);
//racuna z koordinatu zadate tacke    
    zz=z_zadato(A, B, C, Xz, Yz);
    printf("zz=%f", zz);
//formira zadatu tacku Tz
    Tz.x=Xz;
    Tz.y=Yz;
    Tz.z=zz;

//citanje tacke iz stare liste L1 i racunanje njenog rastojanja od zadate tacke
// ako je to rastojanje <= zadato rastojanje tacka se ubacuje u novu listu L2
    while(prvis)
    {
        Ttek=prvis->t;
        d=rastojanje2tacke(Tz, Ttek);
        if(d<=dz)
        {    
            D.x=Ttek.x; D.y=Ttek.y; D.z=Ttek.z; D.d=d;
            //ubaci D u novu listu
            prvin=na_pocetakn (prvin, D);
        }

        prvis=prvis->sled;
    }

    return prvin;
}

int main()
{
    
    LCVOR* glava=NULL;
    LCVORN* glavan;
        
    glava=formirajL1();
    printf("\nispis liste  iz glavnog programa:");
    pisi(glava);

    glavan=dOkolina(3, 2, 2, glava);//zadata tacka 3,2 zadata okolina dz=2
    printf("\nNOVA LISTA:\n");
    pisin(glavan);


    return 0;
}




Imam jedno pitanje a odnosi se na konverziju stringova u brojeve prilikom citanja stringova iz txt datoteke (radim u funkciji tipTacka string2brojevi (char s[])). Zamislila sam da su mi tacke u tekstualnoj datoteci po tri broja u jednom redu. Datoteka mora da izgleda ovako (primer za 3 tacke):
broj11 prazno mesto broj12 prazno mesto broj13 enter
broj21 prazno mesto broj22 prazno mesto broj23 enter
broj31 prazno mesto broj32 prazno mesto broj33 enter

a ne moze ovako:
broj11 prazno mesto broj12 prazno mesto broj13 enter
broj21 prazno mesto broj22 prazno mesto broj23 enter
broj31 prazno mesto broj32 prazno mesto broj33

Znaci moram da imam i u poslednjem redu datoteke unet enter (novi red). To mi je nekako glupo pa da pitam da li moze da se nekako drugacije napise funkcija string2brojevi pa da radi i za taj slucaj? Mozda je problem i tamo gde radim while (fgets(red, 80, fp)!=NULL)?



[ X Files @ 17.05.2010. 17:05 ] @
Postoji vise nacina da resis taj problem.

Recimo, mozes pojednostaviti proces pretvaranja stringova u double-ove. Primer:
Code (c):

/* int i=0; */
while( !feof( pDatoteka ) /*&& ( i<=MAX_BROJ_LINIJA ) */ )
{
        fscanf( pDatoteka, "%lf%lf%lf", &x, &y, &z );
        printf( "%lf\t%lf\t%lf\n", x, y, z );
        /* ++i; */
}
 

Dakle, kraj datoteke se ispituje sa feof, a citanje linije uz ISTOVREMENU konverziju u double se radi sa fscanf.

Svakako pogledaj ovu poruku, mozda dobijes neku ideju:
http://www.elitesecurity.org/p2219727


Ako zelis da zadrzis svoj kod, problem je u ovoj liniji (ako sam dobro shvatio):
while(s[ i ]!='\n' )
...jer ti ces uvek imati "\n" sem u poslednjem redu, gde je pre "\n" dosao kraj datoteke "EOF".

Pretpostavljam da je u tom slucaju pametnije uporedjivati "i" i duzinu stringa "strlen(s)":
NETESTIRANO: "while( i<=strlen( s ) )" // proveriti da li treba manje jednako ili manje
...pre nego traziti "\n". Da ne pominjem da pre "\n" cesto ide i "\r", a tada stvarno ne zna kako se ponasa atof() funkcija.


Takodje, razmotri eliminisanje magicnih brojeva, konkretno broja 80 (nema veze sa ovim problemom, ali ima sa stilom):
Code:

// ...
    while (fgets(red, 80, fp)!=NULL)
// ...
    char red[80],ime_dat[80];
// ...

... i uvedi neki define:
Code:

#define DUZINA_LINIJE 80
// ...
    while (fgets(red, DUZINA_LINIJE, fp)!=NULL)
// ...
    char red[DUZINA_LINIJE],ime_dat[DUZINA_LINIJE];
// ...

ili jos bolje, standardni:
Code:

// ...
    while (fgets(red, MAX_PATH, fp)!=NULL)
// ...
    char red[MAX_PATH],ime_dat[MAX_PATH];
// ...


Kulturnije je i lici na 'pravi' C kod :)

[Ovu poruku je menjao X Files dana 17.05.2010. u 18:17 GMT+1]
[ X Files @ 17.05.2010. 21:00 ] @
Uzgred, nigde ne proveravas povratnu vrednost fopen(), tj. da li je otvaranje datoteke uspelo. To uvek treba predvideti.
[ namespace @ 17.05.2010. 23:32 ] @
Prepravila moju funkciju string2brojevi pomocu while( i<=strlen( s ) )
Ubacila preskakanje praznog reda: if (strcmp(red, "\n")==0) continue; pa moze da ima i praznih redova u sredini i na kraju fajla tacke.txt
Ubacila #define MAX_PATH 80
Imam jos nekih takvih brojeva kao npr. stavila sam da je 20 duzina jednog broja u datoteci
Ubacila proveru da li je uspelo otvaranje datoteke


Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define MAX_PATH 80

typedef struct strTacka
{
    double x;
    double y;
    double z;
} tipTacka;

typedef struct cvor
{
    tipTacka t;
    cvor * sled;
} LCVOR;

typedef struct strTackaD
{
    double x;
    double y;
    double z;
    double d;
} tipTackaD;

typedef struct cvorn
{
    tipTackaD t;
    cvorn * sled;
} LCVORN;

tipTacka string2brojevi (char s[])
{
    tipTacka N;
    char brx[20], bry[20], brz[20] ;
            
    int    i=0;
    int    j=0;

    while(s[i]!=' ' ) 
    {
        brx[j]=s[i];
        i++;
        j++;
    }
        
    brx[j]='\0';
    N.x=atof(brx);    

    i++;
    j=0;
    while(s[i]!=' ' ) 
    {
        bry[j]=s[i];
        i++;
        j++;
    }
    bry[j]='\0';
    N.y=atof(bry);
            
    i++;
    j=0; 
    while( i<=strlen( s ) )
    {
        brz[j]=s[i];
        i++;
        j++;
    }
    brz[j]='\0';
    N.z=atof(brz);

    return N;
}

double rastojanje2tacke (tipTacka T1, tipTacka T2)
{
    return sqrt ( (T1.x-T2.x)*(T1.x-T2.x)+(T1.y-T2.y)*(T1.y-T2.y)+(T1.z-T2.z)*(T1.z-T2.z) );
}

double z_zadato (tipTacka A, tipTacka B, tipTacka C, double Xz, double Yz)
{
    double a, b, c, d, e, f, g, h;
    double p1, p2, p3;
    a=Xz-A.x;
    b=Yz-A.y;
    c=B.x-A.x;
    d=B.y-A.y;
    e=B.z-A.z;
    f=C.x-A.x;
    g=C.y-A.y;
    h=C.z-A.z;
    p1=c*h-e*f;
    p2=d*h-e*g;
    p3=c*g-d*f;
    return (A.z+(b*p1-a*p2)/p3);
}
    

LCVOR* na_pocetak (LCVOR* lst, tipTacka b)
{
    LCVOR* novi;
    novi=(LCVOR*)malloc(sizeof(LCVOR));
    novi->t=b;
    novi->sled=lst;
    return novi;
}

LCVORN* na_pocetakn (LCVORN* lst, tipTackaD b)
{
    LCVORN* novi;
    novi=(LCVORN*)malloc(sizeof(LCVORN));
    novi->t=b;
    novi->sled=lst;
    return novi;
}

void pisi(LCVOR* lst)
{
    while(lst!=NULL)
    {
        printf(" %f %f %f ", lst->t.x, lst->t.y, lst->t.z);
        lst=lst->sled;
    }
}

void pisin(LCVORN* lst)
{
    while(lst!=NULL)
    {
        printf(" %f %f %f %f", lst->t.x, lst->t.y, lst->t.z, lst->t.d);
        lst=lst->sled;
    }
}


LCVOR* formirajL1 ( )
{
    char red[MAX_PATH],ime_dat[MAX_PATH];
    LCVOR* prvi=NULL; 
    tipTacka N;
    FILE *fp;
    
    printf("Ime datoteke koju cu da citam: ");
    gets(ime_dat);
    fp=fopen(ime_dat,"r");
    if(fp==NULL)//provera da li postoji datoteka 
    {
        printf( "Datoteka %s se ne moze otvoriti!\n", ime_dat );
        exit(1);
    }    


    while (fgets(red, MAX_PATH, fp)!=NULL)
    {
        if (strcmp(red, "\n")==0) continue; //preskoci ako je prazan red
        //printf("%s\n", red);
        N=string2brojevi (red);
        prvi=na_pocetak(prvi, N);
    }

    fclose(fp);

    return prvi;
}

LCVORN* dOkolina (double Xz, double Yz, double dz, LCVOR* prvis)
{
    tipTacka A, B, C, Tz, Ttek;
    tipTackaD D;
    LCVORN* prvin=NULL;
    double zz, d;
    char red[MAX_PATH];
    FILE* fp;
//cita tacke koje odredjuju ravan    
    fp=fopen("granice.txt", "r"); 
    if(fp==NULL)//provera da li postoji datoteka 
    {
        printf( "Datoteka granice.txt se ne moze otvoriti!\n");
        exit(1);
    }  
    fgets(red, MAX_PATH, fp);
    A=string2brojevi (red);    //printf(" %f %f %f", A.x,  A.y,  A.z);
    fgets(red, MAX_PATH, fp);
    B=string2brojevi (red);//    printf(" %f %f %f", B.x,  B.y,  B.z);
    fgets(red, MAX_PATH, fp);
    C=string2brojevi (red);    //printf(" %f %f %f", C.x,  C.y,  C.z);
    fclose(fp);
//racuna z koordinatu zadate tacke    
    zz=z_zadato(A, B, C, Xz, Yz);
    printf("zz=%f", zz);
//formira zadatu tacku Tz
    Tz.x=Xz;
    Tz.y=Yz;
    Tz.z=zz;

//citanje tacke iz stare liste L1 i racunanje njenog rastojanja od zadate tacke
// ako je to rastojanje <= zadato rastojanje tacka se ubacuje u novu listu L2
    while(prvis)
    {
        Ttek=prvis->t;
        d=rastojanje2tacke(Tz, Ttek);
        if(d<=dz)
        {    
            D.x=Ttek.x; D.y=Ttek.y; D.z=Ttek.z; D.d=d;
            //ubaci D u novu listu
            prvin=na_pocetakn (prvin, D);
        }

        prvis=prvis->sled;
    }

    return prvin;
}

int main()
{
    
    LCVOR* glava=NULL;
    LCVORN* glavan=NULL;
        
    glava=formirajL1();
    printf("\nispis liste  iz glavnog programa:");
    pisi(glava);

    glavan=dOkolina(3, 2, 2, glava);//zadata tacka 3,2 zadata okolina dz=2
    printf("\nNOVA LISTA:\n");
    pisin(glavan);


    return 0;
}


[ X Files @ 18.05.2010. 12:29 ] @
Citat:
Ubacila #define MAX_PATH 80

Ovu liniju slobodno izbaci, jer je MAX_PATH definisan vec u nekom od headera, tako da bi kompajliranje trebalo da prodje. MAX_PATH je veci od 80, ali svejedno ti to odgovara jer se radi o liniji u fajlu.

A ako bas hoces precizno (da define bude bad tvoj jedinstven identifikator), daj mu neko svoje ime, npr:
#define MAX_DUZINA_LINIJE 80
... i naravno, to popravi svuda po kodu.
[ namespace @ 18.05.2010. 16:07 ] @
Pretpostavila sam da je taj MAX_PATH maksimalna putanja tj. najduže ime fajla sve sa putanjom pa sam probala bez #define MAX_PATH 80 i nije mi prošlo.

Sad sam pokušala da ubacim razne header-e i upalilo je sa windows.h.
I to je tako u Visual Studiu 6, a u starom Borland C-u ne moze ni tako.

Najsigurnije mi je ono sa #define MAX_DUZINA_LINIJE 80 posto ne znam kako se tacno koristi MAX_ PATH.
[ X Files @ 18.05.2010. 16:19 ] @
Vise se i ne secam gde je taj MAX_PATH, valjda u "windef.h". A znam da je negde prolazilo _MAX_PATH :)

Svejedno, napravi svoj define i to je to.