Memorizzazione di un'equazione di linea retta

2

Come conservare una linea retta (lunghezza infinita, non un segmento di linea) in modo efficiente?

Questa non è una duplicazione di Come rappresentare una linea geometrica a livello di codice ? , perché la domanda collegata riguarda il 3D e non risponde al problema principale riflesso in questa domanda.

Definizione di una linea retta:

Questa domanda riguarda la struttura dei dati, non l'interfaccia utente. Non mi interessa come viene definita o presentata l'equazione (perché non sto facendo un calcolatore grafico).

In sostanza, una retta è un'equazione (non necessariamente una funzione di x o y ) che, quando viene disegnata su un sistema di coordinate rettangolari, produce una linea infinitamente lunga, di qualsiasi inclinazione (pendenza), a qualsiasi intercettazione (supponendo che l'intervallo in virgola mobile non sia superato).

Pertanto, queste sono tutte equazioni lineari valide:

y = x
y = -2x
y = x + 3
y = 4x + 5
x = 6
y = 7

Stanno tutti per una linea retta, come mostrato in link

Sto provando a creare un tipo (classe o gerarchia di classi) (in Java, se il linguaggio è importante) che può rappresentare una qualsiasi di queste linee rette.

Possibili usi di una linea retta:

  • Utilizzato in un'immagine, come imageline in GD per disegnare una linea che taglia l'immagine (l'asse Y invertito è un problema minore irrilevante a questa domanda). Ad esempio, l'equazione y = x può tagliare un'immagine in diagonale.
  • Memorizzato in un file. La struttura nel file deve essere uguale a quella del codice.
  • Implementa i metodi equals e hashCode che funzionano con linee identiche.
  • Valuta il punto di intersezione di due linee rette.
  • Valuta i punti di intersezione di una linea retta e, per esempio, un'equazione quadratica (dato double a, double b, double c per ax^2 + bx + c = 0 ) o un cerchio (dati Point center e double radius )

La mia domanda

Ho preso in considerazione tre metodi possibili, che verranno elencati come risposta di seguito: link

La mia domanda è, c'è una quarta soluzione? O c'è un modo per minimizzare gli svantaggi di questi metodi?

    
posta SOFe 07.07.2016 - 12:22
fonte

4 risposte

9

Le equazioni possono essere tutte riscritte nella forma:

a*X + b*Y + c = 0

Ciò significa che puoi memorizzare tre doppi a , b e c .

Questo non ha problemi nel rappresentare una pendenza arbitraria. È anche possibile calcolare la pendenza come a / b (o b / a). Due righe sono uguali se esiste k dove a1*k = a2, b1*k=b2, c1*k = c2 .

    
risposta data 07.07.2016 - 13:10
fonte
2

Metodi possibili

Per comodità di espressione, questa classe verrà utilizzata per rappresentare qualsiasi punto reale in un sistema di coordinate in frammenti di codice di seguito:

public class Point{
    public double x, y;

    @Override public boolean equals(Object other){
        if(!(other instanceof Point)) return false;
        Point point = (Point) other;
        return point.x == this.x && point.y == this.y;
    }
}

Metodo 1: pendenza + (Y-) intercetta

Usando il modulo intercetta pendenze, è possibile creare una classe come questa (in Java):

public class Line{
    public double slope;
    public double yIntercept;
}

Questo è un possibile costruttore per creare una linea che passa attraverso due punti dati: (tutte le linee rette hanno punti reali, quindi qualsiasi due punti distintivi può creare una linea retta)

public Line(Point pt0, Point pt1){
    if(pt0.equals(pt1)) throw new IllegalArgumentException("Cannot create straight line from two identical points");
    this.slope = (pt0.y - pt1.y) / (pt0.x - pt1.x);
    this.yIntercept = pt0.y - this.slope * pt0.x;
}

Come la maggior parte dei programmatori può notare istintivamente, esiste una possibile ArithmeticException di divisione per zero alla riga 1 del costruttore. Cosa significa, se pt0 e pt1 non sono uguali? Ciò significa che due punti hanno la stessa coordinata X ma una diversa coordinata Y, cioè deve essere creata una linea verticale (in un sistema di coordinate rettangolari Y-X). Questo rappresenta anche l'equazione x = x0 , dove x0 è una costante (matematica).

Anche se lo controlliamo in modo specifico e impostiamo slope come java.lang.Double.NaN o java.lang.Double.POSITIVE_INFINITY , che dire di yIntercept ? Dovrebbe essere NaN , perché non ci sono soluzioni o soluzioni infinite. (Intercetta Y significa "coordinata Y quando x = 0", che è sempre vero o sempre falso per un'equazione x = x0 )

Una possibile soluzione è quella di rappresentare una linea verticale con una sottoclasse extra (quindi possiamo usare questa sottoclasse nascondendo il costruttore della classe e usando invece un getter% Line.createFromTwoPoints(Point, Point) ):

public class VerticalLine extends Line{
    private double xIntercept;
    public VerticalLine(double x){
        this.slope = Math.POSITIVE_INFINITY;
        this.yIntercept = Math.NaN;
        this.xIntercept = x;
    }
}

Tuttavia, questo metodo è scomodo. Sembra individuare la condizione di una linea verticale, che non è una condizione speciale e non dovrebbe essere separata dal resto delle condizioni. Crea anche un campo extra nella classe VerticalLine. Se lo usiamo in sostituzione di yIntercept , non sembra una buona idea chiamare un campo yIntercept mentre è in effetti xIntercept , o usare un campo chiamato intercept a volte come intercetta Y ma a volte come l'intercetta dell'X. Questo inconveniente diventa significativo quando c'è un gran casino di getter e funzioni di utilità, a volte sovrascrivendo, a volte non sovrascrivendo.

Metodo 2: direzione + (Y-) intercetta

Uguale al Metodo 1, tranne per il fatto che la pendenza viene sostituita dalla sua tangente all'arco. Ciò rende invece la pendenza infinita una direzione java.lang.Math.PI , ma rimane lo stesso problema con le intercettazioni X e Y. Potrebbe anche funzionare più lentamente perché la valutazione dei punti di intersezione potrebbe comportare più chiamate a funzioni trigonometriche.

Metodo 3: forma a due punti

Questo è molto inefficiente.

Memory

Ciò richiede l'archiviazione di quattro doppi, piuttosto che due o tre doppi sopra.

Prestazioni

La struttura di memoria di due linee identiche potrebbe non essere identica. Ciò significa che il metodo equals e il metodo hashCode e anche molti altri metodi potrebbero richiedere più calcoli. Fai riferimento alla sezione "Possibili usi" nel post principale riguardante il contenuto di "molti altri metodi".

    
risposta data 07.07.2016 - 12:23
fonte
1

Un paio di possibilità:

La forma vettoriale dell'equazione per una retta in 2 dimensioni è n.x + s = 0, dove 'n' è un vettore normale (o perpendicolare) alla linea "." è l'operazione del prodotto punto vettoriale, e s è una costante scalare. Questo ti permette di rappresentare linee arbitrarie con due numeri interi e un doppio. (nota che la stessa rappresentazione in 3 dimensioni forma un piano, e così via). Potrebbe essere più comodo usare i doppi per il vettore, tuttavia, e se lo fai, usare un vettore di unità potrebbe avere senso. Se il tuo vettore è un vettore unitario, "s" può essere interpretato come la distanza lungo il vettore normale tra la linea e l'origine.

Una rappresentazione correlata è notare che un vettore unitario può essere rappresentato come un angolo tra il vettore e uno degli assi, in modo da poterlo memorizzare al posto del vettore. Ciò fornisce una rappresentazione di qualsiasi retta arbitraria con 2 doppi.

A seconda dell'applicazione, questi possono o meno essere efficienti, ma dovresti essere in grado di tracciarli con la massima facilità e decidere quale sia il migliore per te.

    
risposta data 08.07.2016 - 17:29
fonte
0

Un singolo bit che dice se la linea è più vicina a orizzontale o verticale. Se più vicino all'orizzontale, pendenza + intercetta Y. Se più vicino alla verticale, inclinazione inversa + intercetta X.

Questo è due doppi, più un po '.

Il test di uguaglianza è banale.

    
risposta data 07.07.2016 - 13:38
fonte

Leggi altre domande sui tag