geom

package
v1.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 29, 2024 License: MIT Imports: 4 Imported by: 2

Documentation

Overview

Package mit Typen für grundlegende, geometrische 2D-Operationen.

Das Package geht von einer 2 dimensionalen Ebene aus, in welcher Punkte mittels X- und Y-Koordinaten (beides float64-Werte) bezeichnet werden. Es gibt zwei Datentypen für geometrische Objekte: Point und Rectangle und daneben den Datentyp Matrix, mit welchem linear affine Transformationen beschrieben und auf die Typen Point und Rectangle angewendet werden können.

Point

Ein Punkt ist ein struct mit den Feldern X und Y für die X-, resp. die Y-Koordinate des Punktes. Beide Felder sind exportiert. Nahezu alle Methoden des Types Point haben einen Value-Receiver, d.h. sie verändern die Werte des Receivers nicht. Ich habe mich für den Begriff Point entschieden, obwohl es sich bei dieser Struktur genaugenommen um Vektoren handelt und viele der implementierten Methoden stark an das Rechnen mit Vektoren erinnern.

Erzeugen von Punkten

Über die folgenden zwei Funktionen können Punkte erstellt werden:

NewPoint(x, y float64) (Point)
NewPointIMG(p image.Point) (Point)

Beide Funktionen sind eigentlich überflüssig: dadurch dass die Felder X und Y in Point exportiert sind, können neue Punkte jederzeit über Struct-Literals erzeugt werden (z.B. geom.Point{1.0, 2.0}).

Modifikation von Punkten

Mit den folgenden Methoden werden neue Punkte durch Modifikation bestehender Punkte erzeugt:

Add(q Point) (Point)
AddXY(x, y float64) (Point)
Sub(q Point) (Point)
SubXY(x, y float64) (Point)
Mul(k float64) (Point)
Neg() (Point)
Move(dp Point)           // Pointer receiver! Verschiebt den Punkt selber

Die XY-Varianten der Methoden Add und Sub sind entstanden, da es oft einfacher ist zu schreiben:

p2 = p1.AddXY(1, 2)

als

p2 = p1.Add(geom.Point{1, 2})

Abstände

Zwei Methoden stehen zur Bestimmung des euklidischen Abstandes zwischen zwei Punkten zur Verfügung. Dist2 liefert den Abstand im Quadrat, verzichtet aus Perf.gründen auf das Anwenden der Wurzel.

Distance(q Point) (float64)
Dist2(q Point) (float64)

Checks

Mit Eq werden zwei Punkte auf Identität geprüft. Mit In kann ermittelt werden, ob der Punkt innerhalb des Rechtecks r liegt. Beachte hierzu, wie die Koordinaten des Typs Rectangle zu verstehen sind.

Eq(q Point) (bool)
In(r Rectangle) (bool)

Weitere Berechnungen

Folgende Methoden stehen für weitergehende Berechnungen zur Verfügung:

Interpolate(q Point, t float64) (Point)
Max(q Point) (Point)
Min(q Point) (Point)

Konvertierung

Folgende Methoden stehen zur Konvertierung (im weitesten Sinne) von Punkten zur Verfügung. Mit der Methode Set kann man bspw. die Koordinaten von Punkten via Flag oder Kommandozeile einlesen (Getter-Interface in flags).

AsCoord() (x, y float64)
Int() (image.Point)
String() (string)
Set(s string) (error)   // Pointer receiver!

Rectangle

Der zweite geometrische Type ist Rectangle mit welchem ein rechteckiges Gebiet in einer 2-dimensionalen Ebene definiert werden kann. Der Typ besteht aus zwei (exportierten) Feldern Min und Max, welche die Eckpunkte eines Rechtecks enthaten. Dabei muss beachtet werden, dass immer folgendes gilt: Min.X <= Max.X UND Min.Y <= Max.Y.

Erzeugen von Rechtecken

NewRectangle(x0, y0, x1, y1 float64) (Rectangle)
NewRectangleWH(x, y, w, h float64) (Rectangle)
NewRectangleCWH(mx, my, w, h float64) (Rectangle)
NewRectangleIMG(r image.Rectangle) (Retangle)

Modifikation von Rechtecken

Add(p Point) (Rectangle)
Sub(p Point) (Rectangle)
Move(dp Point) (Rectangle)    // Pointer-Receiver

Checks und Vergleiche

Empty() (bool)
Eq(s Rectangle) (bool)
In(s Rectangle) (bool)
Overlaps(s Rectangle) (bool)

Grössen und spezielle Punkte

Dx() (float64)
Dy() (float64)
Size() (Point)

Die folgenden Methoden dienen dazu, bestimmte Punkte auf dem Rand des Rechtecks einfacher zu ermitteln. Die Bezeichnungen entsprechen dabei den Angaben auf einem virtuellen Kompass. Bspw. bedeutet 'NW' Nordwest, bezeichnet also den linken oberen Punkt des Rechtecks.

NW() (Point)
N() (Point)
NE() (Point)
W() (Point)
C() (Point)
E() (Point)
SW() (Point)
S() (Point)
SE() (Point)

Weitere Berechnungen

Intersect(s Rectangle) (Rectangle)
Union(s Rectangle) (Rectangle)
Inset(dx, dy float64) (Rectangle)
PosRel(p Point) (fx, fy float64)
RelPos(fx, fy float64) (Point)
SetInside(p Point) (Point)
Canon() (Rectangle)

Konvertierung

AsCoord() (x, y, w, h float64)
Int() (image.Rectangle)
String() (string)
Set(s string) (error)

Matrizen

Der letzte Datentyp in diesem Package ist Matrix, mit welchem eine linear-affine Transformation in 2D dargestellt werden kann. Der Typ ist wiederum ein struct mit den Elementen m_11 bis m_23 einer 3x3 Matrix.

Basis-Matrizen

Identity() (Matrix)
Translate(d Point) (Matrix)
Rotate(a float64) (Matrix)
RotateAbout(rp Point, a float64) (Matrix)
Scale(sx, sy float64) (Matrix)
ScaleAbout(sp Point, sx, sy float64) (Matrix)

Verknüpfungen und Invertierung von Matrizen

Multiply(b Matrix) (Matrix)
Inv() (Matrix)

Transformation von Matrizen

Translate(d Point) (Matrix)
Scale(sx, sy float64) (Matrix)
ScaleAbout(sp Point, sx, sy float64) (Matrix)
Rotate(a float64) (Matrix)
RotateAbout(rp Point, a float64) (Matrix)

Transformation von Punkten und Rechtecken

Transform(p Point) (Point)
TransformRect(r Rectangle) (Rectangle)

Diverse Methoden

String() (string)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CubicSegment

type CubicSegment struct {
	P0, C0, C1, P1 Point
	// contains filtered or unexported fields
}

func (CubicSegment) ArcLength

func (s CubicSegment) ArcLength() float64

func (CubicSegment) ArcTime

func (s CubicSegment) ArcTime(len float64) float64

func (CubicSegment) Dir

func (s CubicSegment) Dir(t float64) Point

func (CubicSegment) End

func (s CubicSegment) End() Point

func (CubicSegment) Point

func (s CubicSegment) Point(t float64) Point

func (CubicSegment) Start

func (s CubicSegment) Start() Point

type LinearSegment

type LinearSegment struct {
	P0, P1 Point
}

func (LinearSegment) ArcLength

func (s LinearSegment) ArcLength() float64

func (LinearSegment) ArcTime

func (s LinearSegment) ArcTime(len float64) float64

func (LinearSegment) Dir

func (s LinearSegment) Dir(t float64) Point

func (LinearSegment) End

func (s LinearSegment) End() Point

func (LinearSegment) Point

func (s LinearSegment) Point(t float64) Point

func (LinearSegment) Start

func (s LinearSegment) Start() Point

type Matrix

type Matrix struct {
	M11, M12, M13 float64
	M21, M22, M23 float64
}

Der Datentyp Matrix enthält die relevanten Felder einer Transformations- Matrix für linear-affine Abbildungen in der Ebene. Mij ist das Element auf der Zeile i, in der Spalte j. Die letzte Zeile der Matrix ist immer [0, 0, 1] und wird daher nicht mitgeführt.

func Identity

func Identity() Matrix

Erzeugt die Einheitsmatrix.

func Rotate

func Rotate(a float64) Matrix

Erzeugt eine Rotationsmatrix um den Winkel a (im Bogenmass). Drehpunkt ist der Ursprung des Koordinatensystems, Drehrichtung ist im Gegenuhrzeigersinn.

func RotateAbout

func RotateAbout(rp Point, a float64) Matrix

Erzeugt eine Rotationsmatrix um den Winkel a (im Bogenmass) mit Drehpunkt bei rp.

func Scale

func Scale(sx, sy float64) Matrix

Erzeugt eine Skalierungsmatrix mit den Skalierungsfaktoren sx in X-Richtung und sy in Y-Richtung. Zentrum der Skalierung ist der Ursprung des Koordinatensystems.

func ScaleAbout

func ScaleAbout(sp Point, sx, sy float64) Matrix

Erzeugt eine Skalierungsmatrix mit den Skalierungsfaktoren sx in X-Richtung und sy in Y-Richtung. Zentrum der Skalierung ist der Punkt sp.

func Translate

func Translate(d Point) Matrix

Erzeugt eine Translationsmatrix. Die Angaben für die Translation befinden sich als X-, resp. Y-Koordinate im Punkt d .

func (Matrix) AsAff3

func (m Matrix) AsAff3() [6]float64

Im Package golang.org/x/image/math/f64 sind affine Transformationen als Arrays von Float-Werten definiert. Für die Konvertierung in diesen Typ steht die folgende Methode zur Verfügung.

func (Matrix) AsMat3

func (m Matrix) AsMat3() [9]float64

func (Matrix) Inv

func (a Matrix) Inv() Matrix

Invertiert die Matrix a und liefert das Resultat als neue Matrix. Da wir es hier eigentlich nie singulären Matrizen zu tun haben (ausser jemand erstellt bewusst die Nullmatrix oder eine Skalierungsmatrix mit 0 als einem der beiden Faktoren) verzichten wir hier zugunsten der Performance auf einen entsprechenden Test.

func (Matrix) Multiply

func (a Matrix) Multiply(b Matrix) Matrix

Multipliziert die Matrizen a und b (d.h. berechnet a*b) und liefert das Resultat als neue Matrix.

func (Matrix) Rotate

func (m Matrix) Rotate(angle float64) Matrix

Siehe Translate

func (Matrix) RotateAbout

func (m Matrix) RotateAbout(rp Point, a float64) Matrix

Siehe Translate

func (Matrix) Scale

func (m Matrix) Scale(sx, sy float64) Matrix

Siehe Translate

func (Matrix) ScaleAbout

func (m Matrix) ScaleAbout(sp Point, sx, sy float64) Matrix

Siehe Translate

func (Matrix) String

func (m Matrix) String() string

Mit dieser Methode implementiert Matrix schliesslich das 'Stringer' Interface und kann bequem per Printf("%v", m) ausgegeben werden. Beachte, dass dieser String Zeilenumbrüche enthält!

func (Matrix) Transform

func (m Matrix) Transform(p Point) Point

Hier schliesslich spielt die Musik: eine Matrix wird für die Transformation eines Punktes verwendet. Es wird ein neuer Punkt erstellt, aktuell gibt noch keinen Bedarf nach 'in place' Transformation.

func (Matrix) TransformPoint

func (m Matrix) TransformPoint(x, y float64) (float64, float64)

TransformPoint und TransformVector sind zwei Methoden, die aus dem gg-Package übernommen wurden: sie operieren auf Punkte, resp. Vektoren, die als Paar von Float-Werten angegeben werden.

func (Matrix) TransformRect

func (m Matrix) TransformRect(r Rectangle) Rectangle

Will man den zweiten geometrischen Typ (Rectangle) transformieren, dann ist dies die Methode der Wahl.

func (Matrix) TransformVector

func (m Matrix) TransformVector(x, y float64) (float64, float64)

Während TransformPoint eine vollständige Transformation durchführt, wird bei TransformVector die Translation ignoriert.

func (Matrix) Translate

func (m Matrix) Translate(d Point) Matrix

Die Methoden Translate, Rotate, RotateAbout, Scale und ScaleAbout sind Hilfsmethoden, um eine bestehende Matrix m mit einer entsprechenden Transformationsmatrix zu ergänzen.

type Path

type Path struct {
	// contains filtered or unexported fields
}

func NewPath

func NewPath() *Path

func (*Path) ArcLength

func (p *Path) ArcLength() float64

func (*Path) ArcTime

func (p *Path) ArcTime(len float64) float64

func (*Path) BezierTo

func (p *Path) BezierTo(c0, c1, p1 Point)

func (*Path) Close

func (p *Path) Close()

func (*Path) Dir

func (p *Path) Dir(t float64) Point

func (*Path) DirNorm

func (p *Path) DirNorm(t float64) Point

func (*Path) End

func (p *Path) End() Point

func (*Path) IsCyclic

func (p *Path) IsCyclic() bool

func (*Path) LineTo

func (p *Path) LineTo(p1 Point)

func (*Path) MoveTo

func (p *Path) MoveTo(p0 Point)

func (*Path) Node

func (p *Path) Node(i int) Point

func (*Path) Nodes

func (p *Path) Nodes() int

func (*Path) Point

func (p *Path) Point(t float64) Point

func (*Path) PointNorm

func (p *Path) PointNorm(t float64) Point

func (*Path) Segment

func (p *Path) Segment(i int) Segment

func (*Path) Segments

func (p *Path) Segments() int

func (*Path) Start

func (p *Path) Start() Point

type Point

type Point struct {
	X, Y float64
}

Der Datentyp Point ist für Koordinaten in einem Koordinatensystem mit Fliesskommawerten gedacht. Dass der Typ Point und nicht Coord oder Vector heisst, hat eher historische Gründe.

func NewPoint

func NewPoint(x, y float64) Point

Erstellt einen neuen Punkt mit den angebenen X- und Y-Koordianten.

func NewPointIMG

func NewPointIMG(p image.Point) Point

Erstellt einen neuen Punkt aus den Koordianten des angegebenen Punktes aus dem image-Paket.

func (Point) Abs

func (p Point) Abs() float64

func (Point) Add

func (p Point) Add(q Point) Point

Addiert die jeweiligen X- und Y-Koordianten der Punkte p und q.

func (Point) AddXY

func (p Point) AddXY(x, y float64) Point

func (Point) Angle

func (p Point) Angle() float64

func (Point) AsCoord

func (p Point) AsCoord() (x, y float64)

Liefert die X- und Y-Koordinate als einzelne Werte zurück. Gut zu verwenden in Funktionen, welche die Koordinaten als separate Werte erwarten.

func (Point) Dist2

func (p Point) Dist2(q Point) float64

Berechnet den quadrierten Abstand zwischen den Punkten p und q. Siehe auch den kommentar bei Distance.

func (Point) Distance

func (p Point) Distance(q Point) float64

Berechnet den euklidischen Abstand zwischen den Punkten p und q. Will man nur Abstände vergleichen, ist es oft effizienter, die Methode Dist2 zu verwenden, welche den quadrierten Abstand ermittelt (also ohne Quadratwurzel) und damit schneller ist.

func (Point) Div

func (p Point) Div(k float64) Point

Dividiert die Koordinaten des Punktes p durch den Wert k. Eliminiert, kann durch Mul abgedeckt werden!

func (Point) Eq

func (p Point) Eq(q Point) bool

Prüft, ob p und q exakt die gleichen Koordinaten haben. Ev. sollte hier auch ein Zahlenvergleich mit eps gemacht werden.

func (Point) Fixed

func (p Point) Fixed() fixed.Point26_6

Konvertiert den Punkt in einen Datentyp aus dem fixed-Package.

func (Point) In

func (p Point) In(r Rectangle) bool

Prüft, ob der Punkt p im Rechteck r liegt.

func (Point) Int

func (p Point) Int() image.Point

Konvertiert den Punkt in einen Datentyp aus dem image-Package.

func (Point) Interpolate

func (p Point) Interpolate(q Point, t float64) Point

Berechnet einen neuen Punkt, der linear zwischen p und q liegt. Es gilt:

  • t=0.0: das Resultat ist p
  • t=1.0: das Resultat ist q

t kann auch ausserhalb des Intervalls [0,1] liegen. In diesem Fall erhalten wir Punkte, welche nicht auf der Strecke zwischen p und q liegen aber auf der Geraden durch p und q.

func (Point) Max

func (p Point) Max(q Point) Point

Vergleicht die X- sowie die Y-Werte der Punkte p und q und retourniert einen neuen Punkt mit den jeweils grösseren Werten.

func (Point) Min

func (p Point) Min(q Point) Point

Vergleicht die X- sowie die Y-Werte der Punkte p und q und retourniert einen neuen Punkt mit den jeweils kleineren Werten.

func (*Point) Move

func (p *Point) Move(dp Point)

Move verschiebt einen Punkt um die X- und Y-Werte des Punktes dp. Diese Verschiebung wirkt sich auf das Objekt selber aus!

func (Point) Mul

func (p Point) Mul(k float64) Point

Streckt die Koordinaten des Punktes p um den Faktor k.

func (Point) Neg

func (p Point) Neg() Point

func (Point) Normalize

func (p Point) Normalize() Point

func (*Point) Set

func (p *Point) Set(s string) error

Damit können Punkte (resp. die Koordinaten dazu) auch über ein Textfile oder die Kommandozeile eingelesen werden. Mit String zusammen implementiert Point somit das Getter-Interface aus flag.

func (Point) String

func (p Point) String() string

Gibt die Koordinaten des Punktes in der Form '(x; y)' zurück. Implementiert das Stringer-Interface.

func (Point) Sub

func (p Point) Sub(q Point) Point

Subtrahiert vom Punkt q die jeweiligen X- und Y-Koordinaten des Punktes q.

func (Point) SubXY

func (p Point) SubXY(x, y float64) Point

type QuadraSegment

type QuadraSegment struct {
	P0, C0, P1 Point
	// contains filtered or unexported fields
}

type Rectangle

type Rectangle struct {
	Min, Max Point
}

Datentype für Rechtecke in einem 2-dimensionalen Feld. Gespeichert werden die zwei Eckpunkte: Min für den Punkt links oben (d.h. mit den kleineren Werten für die x-, resp. y-Koordinate) und Max für den gegenüberliegenen Punkt. Die Felder Min und Max sind exportiert. Ein veränderndes Programm muss darauf achten, dass die Bedingung (Min.X <= Max.X UND Min.Y <= Max.Y) eingehalten wird!

func NewRectangle

func NewRectangle(x0, y0, x1, y1 float64) Rectangle

Neues Rechteck mit den einzelnen Koordinaten für die Eckpunkte mit den kleinsten (Min) und grössten Werten (Max).

func NewRectangleCWH

func NewRectangleCWH(mx, my, w, h float64) Rectangle

Neues Rechteck mit den Koordinaten des Mittelpunktes, der Breite und der Höhe.

func NewRectangleIMG

func NewRectangleIMG(r image.Rectangle) Rectangle

Erstellt ein neues Rechteck aus dem Datentyp Rectangle des image-Paketes.

func NewRectangleWH

func NewRectangleWH(x, y, w, h float64) Rectangle

Neues Rechteck mit den Koordinaten des Eckpunktes mit den kleinsten Werten, der Breite (d.h. Ausdehung in x-Richtung) und der Höhe (Ausdehung in y-Richtung).

func Rect

func Rect(x0, y0, x1, y1 float64) Rectangle

func (Rectangle) Add

func (r Rectangle) Add(p Point) Rectangle

Add verschiebt das Rechteck r um die Koordinaten des Punktes p.

func (Rectangle) AsCoord

func (r Rectangle) AsCoord() (x, y, w, h float64)

Liefert X- und Y-Koordinaten des Eckpunktes mit den kleinsten Koordinaten sowie die Breite und Höhe als eigenständige Werte.

func (Rectangle) C

func (r Rectangle) C() Point

func (Rectangle) Canon

func (r Rectangle) Canon() Rectangle

Kanonisiert das Rechteck r. Das heisst, dass im resultierenden Rechteck die Koordinaten des Punktes Min auf jeden Fall kleiner sind als die Koord. des Punktes Max.

func (Rectangle) Center

func (r Rectangle) Center() Point

Liefert den Mittelpunkt des Rechteckes.

func (Rectangle) Dx

func (r Rectangle) Dx() float64

Liefert die Breite (Ausdehung in X-Richtung) des Rechteckes.

func (Rectangle) Dy

func (r Rectangle) Dy() float64

Liefert die Höhe (Ausdehung in Y-Richtung) des Rechteckes.

func (Rectangle) E

func (r Rectangle) E() Point

func (Rectangle) Empty

func (r Rectangle) Empty() bool

Prüft, ob das Rechteck leer ist. Im Fall, dass Min > Max ist, gilt das Rechteck als leer.

func (Rectangle) Eq

func (r Rectangle) Eq(s Rectangle) bool

Prüft, ob zwei Rechteck gleich sind, dh. die exakt gleichen Koordinaten haben.

func (Rectangle) In

func (r Rectangle) In(s Rectangle) bool

Prüft, ob sich das Rechteck r vollständig im Rechteck s befindet.

func (Rectangle) Inset

func (r Rectangle) Inset(dx, dy float64) Rectangle

Verschiebt die Ränder von r um d nach Innen und retourniert dieses neü Rechteck. d kann negativ sein, in diesem Fall wird das Rechteck vergrössert

func (Rectangle) Int

func (r Rectangle) Int() image.Rectangle

Konvertiert das Rechteck in den Datentyp image.Rectangle aus der Standard- Library von Go.

func (Rectangle) Intersect

func (r Rectangle) Intersect(s Rectangle) Rectangle

Berechnet ein neues Rechteck, welches der Schnitt der Rechtecke r und s ist. Das Resultat kann leer sein, falls sich r und s nicht überlappen.

func (*Rectangle) Move

func (r *Rectangle) Move(dp Point)

Verschiebt das Rechteck r um die Koordinaten aus dem Punkt dp. Die Verschiebung wirkt sich direkt das Objekt aus.

func (Rectangle) N

func (r Rectangle) N() Point

func (Rectangle) NE

func (r Rectangle) NE() Point

func (Rectangle) NW

func (r Rectangle) NW() Point

func (Rectangle) Overlaps

func (r Rectangle) Overlaps(s Rectangle) bool

Prüft, ob sich die Rechtecke r und s überlappen.

func (Rectangle) PosRel

func (r Rectangle) PosRel(p Point) (float64, float64)

Liefert die relativen Positionsdaten des Punktes p gegenüber dem Rechteck r Also falls p=r.Min, dann wird (0.0, 0.0) retourniert; falls p=r.Max, wird (1.0, 1.0) retourniert, etc.

func (Rectangle) RelPos

func (r Rectangle) RelPos(fx, fy float64) Point

Erstellt einen Punkt, dessen Koordianten relativ zum Rechteck r über die Grössen fx und fx bestimmt werden. Falls bspw. fx=1.0 und fy=0.0 sind, wird (r.Max.X, r.Min.Y) retourniert.

func (Rectangle) S

func (r Rectangle) S() Point

func (Rectangle) SE

func (r Rectangle) SE() Point

func (Rectangle) SW

func (r Rectangle) SW() Point

func (*Rectangle) Set

func (r *Rectangle) Set(s string) error

func (Rectangle) SetInside

func (r Rectangle) SetInside(p Point) Point

Retourniert ausgehend vom Punkt p einen neuen Punkt, der sich garantiert im Rechteck r befindet.

func (Rectangle) Size

func (r Rectangle) Size() Point

func (Rectangle) String

func (r Rectangle) String() string

Produziert einen String mit den Eckkoordinaten des Rechtecks.

func (Rectangle) Sub

func (r Rectangle) Sub(p Point) Rectangle

Sub subtrahiert von allen Koordinaten des Rechtecks r die Werte vom Punkt p.

func (Rectangle) Union

func (r Rectangle) Union(s Rectangle) Rectangle

Berechnet die Vereinigung der Rechtecke r und s. Das Resultat ist das kleinste Rechteck, in welchem sowohl r als auch s vollständig enthalten sind.

func (Rectangle) W

func (r Rectangle) W() Point

func (Rectangle) X0

func (r Rectangle) X0() float64

func (Rectangle) X1

func (r Rectangle) X1() float64

func (Rectangle) Y0

func (r Rectangle) Y0() float64

func (Rectangle) Y1

func (r Rectangle) Y1() float64

type Segment

type Segment interface {
	Start() Point
	End() Point
	Point(t float64) Point
	Dir(t float64) Point
	ArcLength() float64
	ArcTime(len float64) float64
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL