Il Bar dell'Ingegneria

Smussiamo i poligoni

« Older   Newer »
 
  Share  
.
  1.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Non sbagli. La funzione dovrebbe poter agire anche su due segmenti qualsiasi, come si fa al cad.

    Poi, nel caso di poligono chiusi dovremmo meglio capire come comportaci coi vertici che non consentono l'inserimento del raccordo (perche troppo corti) e decidere se mantenerli intatto o se eliderli e procedere con lo smussamento dei due vertici contigui (che chiamerebbero in causa i due lati contingui che potrebbero pure essere paralleli) Insomma c'e' molta carne al fuoco.
     
    Top
    .
  2. UncleJack
        +1   -1
     
    .

    User deleted


    Vedo vedo, nel caso di segmenti paralleli ad una certa distanza occorre allora anche definire un altro punto, lungo il primo o lungo il secondo segmento per dare origine al raccordo. E indicare se uno o entrambi segmenti devono anche essere accorciati/allungati e completamente raccordati.

    Se invece (le loro estensioni) hanno un punto in comune si ritorna al caso di dei post precedenti e poi si indica se e quale dei segmenti deve essere allungato/accorciato. Mi pare non molto di più di una serie di scelte condizionate.

    Ma se interpreto la idea di Zax, al suo vettore di coordinate del poligono, vuole associare un altro vettore contenente i vertici da smussare e a quale raggio. In ogni caso mi pare interessante.
     
    Top
    .
  3.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    2,939
    Reputation
    +187

    Status
    Offline
    Io direi: raggio troppo grande? (Va prima chiarito quando questo si verifica, ovviamente), semplicemente non si raccorda.
    Ricordatevi che fa così anche Autocad.

    Invece l'ultimo messaggio di afazio mi ha fatto pensare a due segmenti che non si incontrano in un vertice dato, ma che anche loro hanno il diritto di 'raccordarsi', in un vertice fittizio, da ricavare prima e da raccordare poi......
     
    Top
    .
  4.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    CITAZIONE (zax2013 @ 31/12/2013, 00:16) 
    Io direi: raggio troppo grande? (Va prima chiarito quando questo si verifica, ovviamente), semplicemente non si raccorda.
    Ricordatevi che fa così anche Autocad.

    Invece l'ultimo messaggio di afazio mi ha fatto pensare a due segmenti che non si incontrano in un vertice dato, ma che anche loro hanno il diritto di 'raccordarsi', in un vertice fittizio, da ricavare prima e da raccordare poi......

    No zax.

    Ho fatto una prova in autocad.
    Ho considerato due lati paralleli del poligono chiusi da un segmento trasversale. La distanza tra i due segmenti l'ho fissata pari a 100 mentre il raggio del raccordo è pari a 50

    ygf8

    Ho prima raccordato il segmento a col segmento b ottenendo quanto segue:

    o2mq

    Adesso il residuo del segmento b a seguito raccordo è tale da non consentire lo smusso tra b e c , ma autocad esegue lo stesso lo smusso ricongiungendosi allo smusso precedente.

    Edit: l'affermazione barrata è errata (vedi post a seguire). Il residuo di b a seguito raccordo è appena sufficiente ad eseguire l'altro raccordo.


    6e5v

    Tutto questo equivale alla soppressione del segmento b ed allo smusso tra a e c. Questo è possibile proprio perche il raggio dello smusso è pari alla meta della distnza tra i due lati paralleli.

    Edited by afazio - 31/12/2013, 08:30
     
    Top
    .
  5.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    2,939
    Reputation
    +187

    Status
    Offline
    Mi hanno cambiato autocad e non me ne sono accorto!!!!!

    Comunque, e per stasera chiudo qui, la mia idea, per vertici 'normali' sarebbe quella di trovare il centro del cerchio di raccordo.
    E questo è semplice farlo perchè posso tranquillamente riutilizzare le routine sviluppate per l'offset dei poligoni (quasi un anno fa, ricordi?). Routine che utilizzavano una 'geometria polare' (quindi azimuth, angoli, ecc.) per ricavare i vertici del nuovo poligono in offset.

    Una volta ricavato il centro, e conoscendo il raggio, sempre con geometria polare dovrei riuscire a ricavare tutti i punti che desidero del mio cerchio (unica cosa per adesso poco chiara sarà trovare raggio vettore iniziale e finale, ma ci arriveremo).
     
    Top
    .
  6.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Pensieri nel dormiveglia.

    In effetti il caso che ho illustrato in uno di post precedenti è particolare.
    Infatti, qualunque sia l'inclinazione del segmento b compreso tra i due segmenti paralleli a e c, se il raggio del raccordo è pari a metà della distanza tra i due segmenti a e c, accade che la parte residua del segmento b a seguito raccordo tra a e b è sempre sufficiente a consentire il raccordo anche tra b (residuo) e c. Provare per credere.

    Questo significa che, qualunque sia l'inclinazione del segmento b rispetto ai due paralleli, se il raggio del raccordo è maggiore della metà della distanza tra i due segmenti paralleli ma minore del doppio, è possibile eseguire un solo raccordo.

    In particolare il raggio massimo del raccordo tra uno dei due segmenti ed il segmento b puo' determinarsi come segue:

    siano
    α - il piu piccolo degli angoli formati tra il segmento b e i due segmenti paralleli
    d - la distanza tra i due segmenti paralleli

    La lunghezza del segmento b vale:

    L = d /sen(α)

    il raggio di raccordo massimo vale:

    r = L*tan(α/2) = d*tan(α/2) /sen(α)

    Quest'ultima formula ha carattere generale e puo' essere usata per determinare il massimo raggio di raccordo tra due lati consecutivi di un poligono.

    Edited by afazio - 31/12/2013, 08:40
     
    Top
    .
  7.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Nel caso di generalizzazione della formula è da intendersi:

    L - lunghezza del più piccolo dei lati convergenti al vertice che intendiamo smussare
    α - angolo formato tra i due lati (<pi)

    quindi:

    r = L*tan(α/2) è il raggio di raccordo massimo
     
    Top
    .
  8.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    2,939
    Reputation
    +187

    Status
    Offline
    Comincio.

    Qui si era parlato di offset di un poligono: Offset di un poligono

    Pare non c'entri nulla, ma il codice che consente di eseguire l'offset di un poligono dato, adeguatamente modificato, è la base che serve al nostro scopo.
    Infatti il centro del cerchio di raccordo deve per forza trovarsi nella bisettrice dell'angolo tra i due segmenti consecutivi, e se d era l'entità dell'offset, basta dire che esso vale r, per ottenere praticamente quello che si cerca.

    Con una piccola differenza. Nel caso dell'offset bisognava per forza dare un senso di percorrenza al poligono, in modo da 'indovinare' il lato (se a destra o se a sinistra) verso il quale doveva trovarsi il nuovo vertice.
    Nel caso in specie invece il lato dove 'giace' il centro del cerchio sarà sempre e soltanto quello dove l'angolo tra i due segmenti è inferiore a 180°.

    In quel topic si ricavava la bisettrice dell'angolo tra i segmenti partendo dall'angolo tra i segmenti stessi, a sua volta ricavato dall'azimuth di ogni singolo segmento.

    Ecco uno schema circa l'azimuth:

    png

    Ed ecco l'angolo tra due segmenti:

    png

    Sto procedendo in maniera "istituto per geometri". Afazio in passato ha proposto analoga trattazione, ma operando alla "liceo scientifico". Ovvero origine dell'azimuth coincidente con l'asse X e angolo positivo se antiorario.
    Poco cambia.

    Quindi la prima funzione, quella che, dato un segmento orientato, determina l'azimuth:

    CODICE
    float azimuth_segmento(float x1,float y1,float x2,float y2)
    {
    float azmth;
    float deltax,deltay;
    float pi;

    pi=4*atan(1);

    deltax=x2-x1;
    deltay=y2-y1;

    if (deltay!=0.0) azmth=atan(fabs(deltax)/fabs(deltay));
    else
       {
        if (deltax>0.0) azmth=pi/2; else azmth=3*pi/2;
       }

    if (deltay<0.0 && deltax>0.0) azmth=pi-azmth; /* II  quadrante */
    if (deltay<0.0 && deltax<=0.0) azmth=pi+azmth; /* III quadrante */
    if (deltay>0.0 && deltax<0.0) azmth=2*pi-azmth; /* IV  quadrante */

    return(azmth);
    }


    I dati in ingresso della funzione sono le coordinate x,y rispettivamente del primo e del secondo vertice del segmento. Il resto è normale trigonometria con qualche controllo per avere in restituzione un angolo in radianti compreso tra 0 e 2*pi.greco
     
    Top
    .
  9.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    2,939
    Reputation
    +187

    Status
    Offline
    Prima di procedere oltre, è opportuno verificare come possono combinarsi le cose con gli angoli. Qui una immagine con un paio di schemi:

    png

    Sono segnati gli azimuth (in rosso) di ogni singolo segmento, in verde l'angolo compreso, inteso come sottrazione di ang_seg=azm2-azm1.
    Tra lo schema a sinistra e lo schema a destra l'unica differenza risiede nella inversione tra i due segmenti. Quello che a sinistra è il segmento 1 (dotato dell'azimuth 1) a destra è il segmento 2 (dotato dell'azimuth 2) e viceversa.

    Ora, se l'angolo dobbiamo esprimerlo sempre come azm2-azm1 nel caso di destra avremo un valore negativo dell'angolo.
    Questo fatto non deve affatto preoccuparci.

    Infatti scopo di tutta questa questione altro non è che la determinazione dell'azimtuh della bisettrice dell'angolo tra i due segmenti. Essa vale sempre: azm1+(azm2-azm1)/2 [1].

    Potete vedere che se (azm2-azm1) è negativo, anche nel secondo schema avremo individuato correttamente l'azimuth della bisettrice.
    (In effetti dall'espressione [1] risolvendo si ottiene (azm1+azm2)/2, senza alcuna differenza nell'ordine di scelta dei segmenti).

    I due schemi sopra riportati hanno però un vantaggio, portano già ad un angolo tra i segmenti inferiore ai 180°.

    Vediamo invece cosa accade con la seconda immagine:
    png

    Nello schema di sinistra l'angolo tra i due segmenti è positivo ma superiore a 180°. L'angolo effettivo per poter ricavare correttamente l'azimuth della bisettrice dell'angolo dovrà essere il complementare, ma determinato come ang_seg-2*pi.greco, ovvero avrà segno negativo.
    Questo permetterà di 'sottrarre' l'angolo ad azm1 nonostante la formula solita preveda il segno più (azm1+ang_seg/2).

    Lo schema di destra mostra la situazione con ordine dei segmenti invertiti. L'angolo tra i segmenti sarà negativo, ma superiore a 180°. L'angolo da considerare dovrà essere pari a ang_sez+2*pi.greco, positivo. E quindi così si determinerà correttamente l'azimuth della bisettrice.

    Sembra che i due casi vadano trattati separatamente (angoli positivi e negativi superiori a 180°). Non mi viene in questo momento, ma io ritengo che si possa avere una formula 'magica' che risolva bene entrambe le situazioni.
     
    Top
    .
  10.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Penso che anche per il raccordo dei vertici di un poligono si debba procedere alla preliminare "pulizia" del poligono" togliendo:

    1 - tutti i vertici consecutivi sovrapposti (o tutti i lati di lunghezza nulla)
    2 - i vertici comuni di lati consecutivi allineati
    3 - i lati completamente sovrapposti
    4 - le parti di lato che parzialmente si sovrappongono

    In alternativa dovremmo saper gestire questi casi.

    In sostanza un poligono può essere visto sotto diversi aspetti, uno di questi è quello di dover determinare le caratteristiche geometriche dell'area che racchiude (ed a questo fine tutti quei casi elencati non contribuiscono a formare area o inerzia o a spostare il baricentro), altro potrebbe essere di natura prettamente geometrica/topologica, potrebbe per esempio essere inteso come la traiettoria di una particella che per i fatti suoi decide di tornare indietro sui suoi passi, oppure qualsiasi dei suoi vertici (che elideremmo) potrebbe essere il punto di ancoraggio di altra figura.

    Nel caso dell'offset del poligono abbiamo deciso di procedere con la preventiva pulizia del poligono e successivamente abbiamo dato in pasto il nuovo poligono alla funzione: stessa cosa potremmo decidere di fare qui. In ogni caso, non sappiamo gestire i poligoni intrecciati e quindi occorre un preventivo controllo in tal senso.
     
    Top
    .
  11.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    2,939
    Reputation
    +187

    Status
    Offline
    Non pensi afazio che io non legga quanto egli scrive.
    Semplicemente voglio andare avanti con un caso 'perfetto'. D'altra parte già lo scorso anno sono state sviluppate parecchie routine in grado di 'sistemare' poligoni malcostituiti. L'unica cosa che alla fine non si era riusciti a sistemare era il poligono intrecciato. Ma per il raccordo che ci accingiamo a discutere questo è ininfluente.

    Riprendo il discorso circa la determinazione dell'azimuth della bisettrice dell'angolo tra i due segmenti.
    Nessuna formula magica. L'azimuth della bisettrice è sempre (azm1+amz2)/2.
    Solamente dopo avere calcolato la bisettrice bisognerà controllare se l'angolo (azm2-azm1) è positivo o negativo. Se è positivo non bisogna far nulla, se invece è negativo bisognerà sommare all'azimtuh della bisettrice il valore di pi.greco (e dopo controllare che esso non valga più di 2*pi.greco).

    Avendo l'azimuth della bisettrice (chiamiamola azmb)sarà semplicissimo determinare le coordinate del centro del cerchio di raccordo. Osservate lo schema:

    png

    Se r è il raggio del raccordo, ed alfa_b è l'angolo tra uno dei due segmenti e la bisettrice (facilmente determinabile: azm2-azmb, oppure azm1-azmb, in valore assoluto), il segmento d' vale:

    d'=r/sin(alfa_b)

    Questo consente di definire le coordinate del centro del raccordo a partire dalle coordinate del vertice da smussare.
    Ma prima determiniamo il valore del segmento segnato come t in figura. Esso vale:

    t=r/tan(alfa_b)

    Conoscere il valore di questo segmento ci consente di eseguire un controllo. Ovvero se il valore di t è maggiore della lunghezza di almeno uno solo dei 2 segmenti il raccordo non s'ha da fare!

    In ogni caso, superato questo controllo, le coordinate del centro del raccordo valgono:

    xc=xv+d'*sin(azmb)
    yc=yv+d'*cos(azmb)

    E per adesso mi fermo qui.

    Edited by zax2013 - 3/1/2014, 18:29
     
    Top
    .
  12.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    2,939
    Reputation
    +187

    Status
    Offline
    Continuo. E' chiaro che tutto questa trattazione prima o poi si tradurrà in codice, e non è detto che la strada intrapresa sia la più semplice, e soprattutto sia corretta. Lo scopriremo solamente scrivendo la funzione e vedendo se essa effettivamente funziona.

    Qualsiasi punto della circonferenza di raccordo avrà coordinate:

    xp=xc+r*sin(alfa)
    yp=yc+r*cos(alfa)

    Dove alfa è l'azimuth di un raggio vettore qualsiasi (fatto variare all'interno di un ciclo), tra due azimuth 'estremi'. Gli azimuth estremi sono quelli di tangenza con i segmenti originari.
    Non ci è stato finora necessario, ma ho già indicato un verso di 'percorrenza' all'interno del poligono.
    Osserviamo nuovamente lo schema prima pubblicato. Seguendo la sequenza "prec.-V-succ." sto individuando un 'percorso' orario del mio poligono.
    E da questo verso orario di percorrenza del poligono, visto che le tangenti sono per forza ortogonali ai singoli segmenti possiamo affermare che il primo azimuth 'estremo' (ortogonale al segmento 1) vale: azm1+pi.greco/2, ed il secondo azimuth 'estremo' (ortogonale al segmento 2) vale azm2+3*pi.greco/2.

    Variando l'azimuth del nostro raggio vettore tra questi due otteniamo tutti i punti che vogliamo del nostro raccordo.
    (Dovrò fare qualche altro schema per verificare se questo è sempre vero).

    Una scocciatura lavorando con gli azimuth è quella di dover controllare, ogni volta che si sommano/sottraggono tra loro, che essi siamo sempre compresi tra 0 e 2*pi.greco.
    Io penso di risolvere con una funzione a parte che, dati due azimuth, e indicando se bisogna sommarli o sottrarli, pensi essa stessa ad eseguire i controlli e mi restituisca il valore tra 0 e 2*pi.greco dell'azimuth.

    Una altra alternativa 'ganza', e qui dovremmo sfruttare però la 'sapienza' di UncleJack, sarebbe quella (forse possibile però con il solo C++) di utilizzare l'overloading.
    Ossia creare una classe azimuth, e per quella classe creare un operatore 'speciale' (il segno '+', il segno '-'), che in effetti faccia quello che io mi ripropongo con la funzione.
    Ovvero, io richiamerei nel listato una funzione del genere:

    CODICE
    azm_smm=somma_azimuth(azm1,azm2);


    Con l'overloading, se azm1 ed azm2 sono oggetti di una classe azimuth, scriverei molto più semplicemente:

    CODICE
    azm_smm=azmt1+azmt2;


    Il compilatore sa che per questi 'oggetti' il simbolo '+' non è il solito operatore matematico cui siamo abituati, ma di fatto è una funzione all'interno della classe che svolge una ben precisa operazione (normale somma degli azimuth e successivo controllo che la somma sia compresa tra 0 e 2*pi.greco).
    Insomma, io so che è possibile farlo. Ma non avendolo mai fatto......
     
    Top
    .
  13.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    CITAZIONE (zax2013 @ 3/1/2014, 20:03) 
    Una altra alternativa 'ganza', e qui dovremmo sfruttare però la 'sapienza' di UncleJack, sarebbe quella (forse possibile però con il solo C++) di utilizzare l'overloading.
    Ossia creare una classe azimuth, e per quella classe creare un operatore 'speciale' (il segno '+', il segno '-'), che in effetti faccia quello che io mi ripropongo con la funzione.
    Ovvero, io richiamerei nel listato una funzione del genere:

    CODICE
    azm_smm=somma_azimuth(azm1,azm2);


    Con l'overloading, se azm1 ed azm2 sono oggetti di una classe azimuth, scriverei molto più semplicemente:

    CODICE
    azm_smm=azmt1+azmt2;


    Il compilatore sa che per questi 'oggetti' il simbolo '+' non è il solito operatore matematico cui siamo abituati, ma di fatto è una funzione all'interno della classe che svolge una ben precisa operazione (normale somma degli azimuth e successivo controllo che la somma sia compresa tra 0 e 2*pi.greco).
    Insomma, io so che è possibile farlo. Ma non avendolo mai fatto......

    Questo puo' farsi anche in objectPascal e quindi in lazarus. MA anche io non l'ho mai fatto.
     
    Top
    .
  14.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    2,939
    Reputation
    +187

    Status
    Offline
    Nel week-end qualche prova per vedere se tutto funziona.
    Ovviamente funziona tutto....al 90%.

    Ovvero calcolo dell'azimuth bisettrice: ok.
    Calcolo coordinate centro smusso: ok.

    I problemi sono cominciati con il calcolo dell'azimuth del primo 'raggio' (tangente) dello smusso.
    Risolto, trovando le coordinate della tangente nel primo segmento, così:

    xt=xv+t*sin(azm1)
    yt=yv+t*cos(azm1)

    (dove t è stata ricavata precedentemente - vedi qualche post più su)
    E determinando quindi l'azimuth con la solita funzione dando in pasto coordinate del centro smusso e della tangente così ricavata.
    L'unico problema rimane stabilire se i vari punti dello smusso debbano infine essere ricavati 'girando' in senso orario o anti orario.
    Guardate la seguente figura:

    png

    Quello che accade nel vertice tra i segmenti 2 e 3 sembra identico a quanto accade tra i segmenti 5 e 6.
    In effetti tra 5 e 6, l'azimuth di partenza è quello del segmento C-5, quindi si procede in senso orario.
    Tra 2 e 3, l'azimuth di partenza è del segmento C-2, e poi bisogna però procedere in senso antirorario per definire in singoli punti intermedi.
    Poichè i singoli punti sono 'angolarmente' equidistanti tra loro significa solamente che lo step angolare per ricavarli sarà positivo in un caso e negativo nell'altro.
    Il problema è che non ho ancora capito bene quali siano le condizioni per stabilire senza indugio quali casi siano orari e quali antiorari. Devo mettermi lì a fare qualche ulteriore prova.
     
    Top
    .
  15.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    CITAZIONE (zax2013 @ 7/1/2014, 13:13) 
    Nel week-end qualche prova per vedere se tutto funziona.
    Ovviamente funziona tutto....al 90%.

    Ovvero calcolo dell'azimuth bisettrice: ok.
    Calcolo coordinate centro smusso: ok.

    I problemi sono cominciati con il calcolo dell'azimuth del primo 'raggio' (tangente) dello smusso.
    Risolto, trovando le coordinate della tangente nel primo segmento, così:

    xt=xv+t*sin(azm1)
    yt=yv+t*cos(azm1)

    (dove t è stata ricavata precedentemente - vedi qualche post più su)
    E determinando quindi l'azimuth con la solita funzione dando in pasto coordinate del centro smusso e della tangente così ricavata.
    L'unico problema rimane stabilire se i vari punti dello smusso debbano infine essere ricavati 'girando' in senso orario o anti orario.
    Guardate la seguente figura:

    png

    Quello che accade nel vertice tra i segmenti 2 e 3 sembra identico a quanto accade tra i segmenti 5 e 6.
    In effetti tra 5 e 6, l'azimuth di partenza è quello del segmento C-5, quindi si procede in senso orario.
    Tra 2 e 3, l'azimuth di partenza è del segmento C-2, e poi bisogna però procedere in senso antirorario per definire in singoli punti intermedi.
    Poichè i singoli punti sono 'angolarmente' equidistanti tra loro significa solamente che lo step angolare per ricavarli sarà positivo in un caso e negativo nell'altro.
    Il problema è che non ho ancora capito bene quali siano le condizioni per stabilire senza indugio quali casi siano orari e quali antiorari. Devo mettermi lì a fare qualche ulteriore prova.

    Non ricordo bene, ma avevamo riscontrato lo stesso problema nel caso dell'offset e lo avevamo risolto con segno di qualche cosa.
     
    Top
    .
35 replies since 30/12/2013, 23:17   1417 views
  Share  
.