summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2019-03-13 19:16:12 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2019-03-13 19:16:12 (GMT)
commit913c2ffec66a261d7cea357c21cdcda60132c0a5 (patch)
tree50834dfff8ea8a4494f981b6559bbfa604ee7707
parent87a95ec0329c9fd676ed4a5d9d10247eb245a4ec (diff)
downloadtk-913c2ffec66a261d7cea357c21cdcda60132c0a5.zip
tk-913c2ffec66a261d7cea357c21cdcda60132c0a5.tar.gz
tk-913c2ffec66a261d7cea357c21cdcda60132c0a5.tar.bz2
Document. Factor out basic rotation function.
-rw-r--r--doc/CrtItemType.343
-rw-r--r--doc/canvas.n38
-rw-r--r--generic/tkCanvArc.c32
-rw-r--r--generic/tkCanvBmap.c13
-rw-r--r--generic/tkCanvImg.c13
-rw-r--r--generic/tkCanvLine.c19
-rw-r--r--generic/tkCanvPoly.c6
-rw-r--r--generic/tkCanvText.c7
-rw-r--r--generic/tkCanvUtil.c38
-rw-r--r--generic/tkCanvWind.c7
-rw-r--r--generic/tkInt.h3
-rw-r--r--generic/tkRectOval.c29
12 files changed, 153 insertions, 95 deletions
diff --git a/doc/CrtItemType.3 b/doc/CrtItemType.3
index f9198f3..1bfb20f 100644
--- a/doc/CrtItemType.3
+++ b/doc/CrtItemType.3
@@ -83,6 +83,9 @@ typedef struct Tk_ItemType {
Tk_ItemInsertProc *\fIinsertProc\fR;
Tk_ItemDCharsProc *\fIdCharsProc\fR;
Tk_ItemType *\fInextPtr\fR;
+.VS "8.7, TIP164"
+ Tk_ItemRotateProc *\fIrotateProc\fR;
+.VE "8.7, TIP164"
} \fBTk_ItemType\fR;
.CE
.PP
@@ -549,6 +552,46 @@ and \fIdeltaX\fR and \fIdeltaY\fR give the amounts that should be
added to each x and y coordinate within the item.
The type manager should adjust the item's coordinates and
update the bounding box in the item's header.
+.SS ROTATEPROC
+.VS "8.7, TIP164"
+.PP
+\fItypePtr\->rotateProc\fR is invoked by Tk to rotate a canvas item
+during the \fBrotate\fR widget command.
+The procedure must match the following prototype:
+.PP
+.CS
+typedef void \fBTk_ItemRotateProc\fR(
+ Tk_Canvas \fIcanvas\fR,
+ Tk_Item *\fIitemPtr\fR,
+ double \fIoriginX\fR,
+ double \fIoriginY\fR,
+ double \fIangleRad\fR);
+.CE
+.PP
+The \fIcanvas\fR and \fIitemPtr\fR arguments have the usual meaning.
+\fIoriginX\fR and \fIoriginY\fR specify an origin relative to which
+the item is to be rotated, and \fIangleRad\fR gives the anticlockwise
+rotation to be applied in radians.
+The item should adjust the coordinates of its control points so that where
+they used to have coordinates \fIx\fR and \fIy\fR, they will have new
+coordinates \fIx\(fm\fR and \fIy\(fm\fR, where
+.PP
+.CS
+\fIrelX\fR = \fIx\fR - \fIoriginX\fR
+\fIrelY\fR = \fIy\fR - \fIoriginY\fR
+\fIx\(fm\fR = \fIoriginX\fR + \fIrelX\fR \(mu cos(\fIangleRad\fR) + \fIrelY\fR \(mu sin(\fIangleRad\fR)
+\fIy\(fm\fR = \fIoriginY\fR \(mi \fIrelX\fR \(mu sin(\fIangleRad\fR) + \fIrelY\fR \(mu cos(\fIangleRad\fR)
+.CE
+.PP
+The control points for an item are not necessarily the coordinates provided to
+the item when it is created (or via the \fItypePtr\->coordProc\fR), but could
+instead be derived from them.
+\fIrotateProc\fR must also update the bounding box in the item's header.
+.PP
+Item types do not need to provide a \fItypePtr\->rotateProc\fR. If the
+\fItypePtr\->rotateProc\fR is NULL, the \fItypePtr\->coordProc\fR will be
+used instead to retrieve and update the list of coordinates.
+.VE "8.7, TIP164"
.SS INDEXPROC
.PP
\fItypePtr\->indexProc\fR is invoked by Tk to translate a string
diff --git a/doc/canvas.n b/doc/canvas.n
index fa7843d..bcd4991 100644
--- a/doc/canvas.n
+++ b/doc/canvas.n
@@ -220,8 +220,12 @@ for scrolling.
Canvases do not support scaling or rotation of the canvas coordinate
system relative to the window coordinate system.
.PP
-Individual items may be moved or scaled using widget commands
-described below, but they may not be rotated.
+Individual items may be moved, scaled
+.VS "8.7, TIP164"
+or rotated
+.VE "8.7, TIP164"
+using widget commands
+described below.
.PP
Note that the default origin of the canvas's visible area is
coincident with the origin for the whole window as that makes bindings
@@ -674,13 +678,12 @@ mapped.
This command returns an empty string.
.TP
\fIpathName \fBimove \fItagOrId index x y\fR
-.VS 8.6
+.
This command causes the \fIindex\fR'th coordinate of each of the items
indicated by \fItagOrId\fR to be relocated to the location (\fIx\fR,\fIy\fR).
Each item interprets \fIindex\fR independently according to the rules
described in \fBINDICES\fR above. Out of the standard set of items, only line
and polygon items may have their coordinates relocated this way.
-.VE 8.6
.TP
\fIpathName \fBindex \fItagOrId index\fR
.
@@ -766,7 +769,7 @@ each point associated with the item.
This command returns an empty string.
.TP
\fIpathName \fBmoveto \fItagOrId xPos yPos\fR
-.VS 8.6
+.
Move the items given by \fItagOrId\fR in the canvas coordinate
space so that the first coordinate pair of the bottommost item with
tag \fItagOrId\fR is located at
@@ -775,7 +778,6 @@ the empty string, in which case the corresponding coordinate
will be unchanged. All items matching
\fItagOrId\fR remain in the same positions relative to each other.
This command returns an empty string.
-.VE 8.6
.TP
\fIpathName \fBpostscript \fR?\fIoption value option value ...\fR?
.
@@ -961,7 +963,7 @@ determined by the \fBraise\fR command and \fBlower\fR command, not the
.RE
.TP
\fIpathName \fBrchars \fItagOrId first last string\fR
-.VS 8.6
+.
This command causes the text or coordinates between \fIfirst\fR and \fIlast\fR
for each of the items indicated by \fItagOrId\fR to be replaced by
\fIstring\fR. Each item interprets \fIfirst\fR and \fIlast\fR independently
@@ -970,7 +972,24 @@ set of items, text items support this operation by altering their text as
directed, and line and polygon items support this operation by altering their
coordinate list (in which case \fIstring\fR should be a list of coordinates to
use as a replacement). The other items ignore this operation.
-.VE 8.6
+.TP
+\fIpathName \fBrotate \fItagOrId xOrigin yOrigin angle\fR
+.VS "8.7, TIP164"
+Rotate the coordinates of all of the items given by \fItagOrId\fR in canvas
+coordinate space.
+\fIXOrigin\fR and \fIyOrigin\fR identify the origin for the rotation
+operation and \fIangle\fR identifies the amount to rotate the coordinates
+anticlockwise, in degrees. (Negative values rotate clockwise.)
+This command returns an empty string.
+.RS
+.PP
+Implementation note: not all item types work well with rotations. In
+particular, the \fBarc\fR, \fBoval\fR and \fBrectangle\fR types are very
+unlikely to work as you expect. Several other item types only have a single
+coordinate; this command can move that anchor point, but will not rotate the
+item about that anchor point.
+.RE
+.VE "8.7, TIP164"
.TP
\fIpathName \fBscale \fItagOrId xOrigin yOrigin xScale yScale\fR
.
@@ -1834,13 +1853,12 @@ The following standard options are supported by text items:
The following extra options are supported for text items:
.TP
\fB\-angle \fIrotationDegrees\fR
-.VS 8.6
+.
\fIRotationDegrees\fR tells how many degrees to rotate the text anticlockwise
about the positioning point for the text; it may have any floating-point value
from 0.0 to 360.0. For example, if \fIrotationDegrees\fR is \fB90\fR, then the
text will be drawn vertically from bottom to top.
This option defaults to \fB0.0\fR.
-.VE 8.6
.TP
\fB\-font \fIfontName\fR
Specifies the font to use for the text item.
diff --git a/generic/tkCanvArc.c b/generic/tkCanvArc.c
index ca9ef34..3741829 100644
--- a/generic/tkCanvArc.c
+++ b/generic/tkCanvArc.c
@@ -1520,23 +1520,21 @@ RotateArc(
double angleRad)
{
ArcItem *arcPtr = (ArcItem *) itemPtr;
- double x, y, nx, ny;
- double s = sin(angleRad);
- double c = cos(angleRad);
-
- x = arcPtr->bbox[0] - originX;
- y = arcPtr->bbox[1] - originY;
- nx = x * c - y * s;
- ny = x * s + y * c;
- arcPtr->bbox[0] = nx + originX;
- arcPtr->bbox[1] = ny + originY;
-
- x = arcPtr->bbox[2] - originX;
- y = arcPtr->bbox[3] - originY;
- nx = x * c - y * s;
- ny = x * s + y * c;
- arcPtr->bbox[2] = nx + originX;
- arcPtr->bbox[3] = ny + originY;
+ double s = sin(angleRad), c = cos(angleRad);
+ double coords[4];
+
+ memcpy(coords, arcPtr->bbox, sizeof(coords));
+ TkRotatePoint(originX, originY, s, c, &coords[0], &coords[1]);
+ TkRotatePoint(originX, originY, s, c, &coords[2], &coords[3]);
+
+ /*
+ * Sort the points for the bounding box.
+ */
+
+ arcPtr->bbox[0] = (coords[0] < coords[2]) ? coords[0] : coords[2];
+ arcPtr->bbox[1] = (coords[1] < coords[3]) ? coords[1] : coords[3];
+ arcPtr->bbox[2] = (coords[0] < coords[2]) ? coords[2] : coords[0];
+ arcPtr->bbox[3] = (coords[1] < coords[3]) ? coords[3] : coords[1];
/*
* TODO: update the arc endpoints?
diff --git a/generic/tkCanvBmap.c b/generic/tkCanvBmap.c
index 948379d..34c74f3 100644
--- a/generic/tkCanvBmap.c
+++ b/generic/tkCanvBmap.c
@@ -817,16 +817,9 @@ RotateBitmap(
double angleRad)
{
BitmapItem *bmapPtr = (BitmapItem *) itemPtr;
- double x, y, nx, ny;
- double s = sin(angleRad);
- double c = cos(angleRad);
-
- x = bmapPtr->x - originX;
- y = bmapPtr->y - originY;
- nx = x * c - y * s;
- ny = x * s + y * c;
- bmapPtr->x = nx + originX;
- bmapPtr->y = ny + originY;
+
+ TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad),
+ &bmapPtr->x, &bmapPtr->y);
ComputeBitmapBbox(canvas, bmapPtr);
}
diff --git a/generic/tkCanvImg.c b/generic/tkCanvImg.c
index 20fcd52..f2b73a6 100644
--- a/generic/tkCanvImg.c
+++ b/generic/tkCanvImg.c
@@ -789,16 +789,9 @@ RotateImage(
double angleRad)
{
ImageItem *imgPtr = (ImageItem *) itemPtr;
- double x, y, nx, ny;
- double s = sin(angleRad);
- double c = cos(angleRad);
-
- x = imgPtr->x - originX;
- y = imgPtr->y - originY;
- nx = x * c - y * s;
- ny = x * s + y * c;
- imgPtr->x = nx + originX;
- imgPtr->y = ny + originY;
+
+ TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad),
+ &imgPtr->x, &imgPtr->y);
ComputeImageBbox(canvas, imgPtr);
}
diff --git a/generic/tkCanvLine.c b/generic/tkCanvLine.c
index ce4d40d..3f8f5c1 100644
--- a/generic/tkCanvLine.c
+++ b/generic/tkCanvLine.c
@@ -1875,19 +1875,6 @@ TranslateLine(
*--------------------------------------------------------------
*/
-static inline void
-DoRotate(
- double originX, double originY,
- double sine, double cosine,
- double *xPtr, double *yPtr)
-{
- double x = *xPtr - originX;
- double y = *yPtr - originY;
-
- *xPtr = originX + x * cosine - y * sine;
- *yPtr = originY + x * sine + y * cosine;
-}
-
static void
RotateLine(
Tk_Canvas canvas, /* Canvas containing item. */
@@ -1902,18 +1889,18 @@ RotateLine(
for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints;
i++, coordPtr += 2) {
- DoRotate(originX, originY, s, c, &coordPtr[0], &coordPtr[1]);
+ TkRotatePoint(originX, originY, s, c, &coordPtr[0], &coordPtr[1]);
}
if (linePtr->firstArrowPtr != NULL) {
for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW;
i++, coordPtr += 2) {
- DoRotate(originX, originY, s, c, &coordPtr[0], &coordPtr[1]);
+ TkRotatePoint(originX, originY, s, c, &coordPtr[0], &coordPtr[1]);
}
}
if (linePtr->lastArrowPtr != NULL) {
for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW;
i++, coordPtr += 2) {
- DoRotate(originX, originY, s, c, &coordPtr[0], &coordPtr[1]);
+ TkRotatePoint(originX, originY, s, c, &coordPtr[0], &coordPtr[1]);
}
}
ComputeLineBbox(canvas, linePtr);
diff --git a/generic/tkCanvPoly.c b/generic/tkCanvPoly.c
index ae18067..1677bbb 100644
--- a/generic/tkCanvPoly.c
+++ b/generic/tkCanvPoly.c
@@ -1771,11 +1771,7 @@ RotatePolygon(
for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
i++, coordPtr += 2) {
- double x = coordPtr[0] - originX;
- double y = coordPtr[1] - originY;
-
- coordPtr[0] = originX + x * c - y * s;
- coordPtr[1] = originY + x * s + y * c;
+ TkRotatePoint(originX, originY, s, c, &coordPtr[0], &coordPtr[1]);
}
ComputePolygonBbox(canvas, polyPtr);
}
diff --git a/generic/tkCanvText.c b/generic/tkCanvText.c
index 22b6dea..4f446ec 100644
--- a/generic/tkCanvText.c
+++ b/generic/tkCanvText.c
@@ -1277,12 +1277,9 @@ RotateText(
double angleRad) /* Amount by which item is to be rotated. */
{
TextItem *textPtr = (TextItem *) itemPtr;
- double s = sin(angleRad), c = cos(angleRad);
- double x = textPtr->x - originX;
- double y = textPtr->y - originY;
- textPtr->x = originX + x * c - y * s;
- textPtr->y = originY + x * s + y * c;
+ TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad),
+ &textPtr->x, &textPtr->y);
ComputeTextBbox(canvas, textPtr);
}
diff --git a/generic/tkCanvUtil.c b/generic/tkCanvUtil.c
index 6ce671d..52d7bf6 100644
--- a/generic/tkCanvUtil.c
+++ b/generic/tkCanvUtil.c
@@ -1265,7 +1265,6 @@ Tk_ChangeOutlineGC(
}
return 0;
}
-
/*
*--------------------------------------------------------------
@@ -1865,6 +1864,43 @@ TkCanvTranslatePath(
}
/*
+ *--------------------------------------------------------------
+ *
+ * TkRotatePoint --
+ *
+ * Rotate a point about another point. The angle should be converted into
+ * its sine and cosine before calling this function.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * The point in (*xPtr,*yPtr) is updated to be rotated about
+ * (originX,originY) by the amount given by the sine and cosine of the
+ * angle to rotate.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkRotatePoint(
+ double originX, double originY, /* The point about which to rotate. */
+ double sine, double cosine, /* How much to rotate? */
+ double *xPtr, double *yPtr) /* The point to be rotated. (INOUT) */
+{
+ double x = *xPtr - originX;
+ double y = *yPtr - originY;
+
+ /*
+ * Beware! The canvas coordinate space is flipped vertically, so rotations
+ * go the "wrong" way with respect to mathematics.
+ */
+
+ *xPtr = originX + x * cosine + y * sine;
+ *yPtr = originY - x * sine + y * cosine;
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff --git a/generic/tkCanvWind.c b/generic/tkCanvWind.c
index 8c44a6c..9f38932 100644
--- a/generic/tkCanvWind.c
+++ b/generic/tkCanvWind.c
@@ -943,12 +943,9 @@ RotateWinItem(
double angleRad) /* Amount by which item is to be rotated. */
{
WindowItem *winItemPtr = (WindowItem *) itemPtr;
- double s = sin(angleRad), c = cos(angleRad);
- double x = winItemPtr->x - originX;
- double y = winItemPtr->y - originY;
- winItemPtr->x = originX + x * c - y * s;
- winItemPtr->y = originY + x * s + y * c;
+ TkRotatePoint(originX, originY, sin(angleRad), cos(angleRad),
+ &winItemPtr->x, &winItemPtr->y);
ComputeWindowBbox(canvas, winItemPtr);
}
diff --git a/generic/tkInt.h b/generic/tkInt.h
index 767bbbb..9c6a28f 100644
--- a/generic/tkInt.h
+++ b/generic/tkInt.h
@@ -1259,6 +1259,9 @@ MODULE_SCOPE void TkpCancelWarp(TkDisplay *dispPtr);
MODULE_SCOPE int TkListCreateFrame(ClientData clientData,
Tcl_Interp *interp, Tcl_Obj *listObj,
int toplevel, Tcl_Obj *nameObj);
+MODULE_SCOPE void TkRotatePoint(double originX, double originY,
+ double sine, double cosine, double *xPtr,
+ double *yPtr);
#ifdef _WIN32
#define TkParseColor XParseColor
diff --git a/generic/tkRectOval.c b/generic/tkRectOval.c
index b1bce7b..279e89e 100644
--- a/generic/tkRectOval.c
+++ b/generic/tkRectOval.c
@@ -1306,19 +1306,6 @@ OvalToArea(
*--------------------------------------------------------------
*/
-static inline void
-DoRotate(
- double originX, double originY,
- double sine, double cosine,
- double *xPtr, double *yPtr)
-{
- double x = *xPtr - originX;
- double y = *yPtr - originY;
-
- *xPtr = originX + x * cosine - y * sine;
- *yPtr = originY + x * sine + y * cosine;
-}
-
static void
RotateRectOval(
Tk_Canvas canvas, /* Canvas containing rectangle. */
@@ -1329,10 +1316,20 @@ RotateRectOval(
{
RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
double s = sin(angleRad), c = cos(angleRad);
- double *coords = rectOvalPtr->bbox;
+ double coords[4];
+
+ memcpy(coords, rectOvalPtr->bbox, sizeof(coords));
+ TkRotatePoint(originX, originY, s, c, &coords[0], &coords[1]);
+ TkRotatePoint(originX, originY, s, c, &coords[2], &coords[3]);
+
+ /*
+ * Sort the points for the bounding box.
+ */
- DoRotate(originX, originY, s, c, &coords[0], &coords[1]);
- DoRotate(originX, originY, s, c, &coords[2], &coords[3]);
+ rectOvalPtr->bbox[0] = (coords[0] < coords[2]) ? coords[0] : coords[2];
+ rectOvalPtr->bbox[1] = (coords[1] < coords[3]) ? coords[1] : coords[3];
+ rectOvalPtr->bbox[2] = (coords[0] < coords[2]) ? coords[2] : coords[0];
+ rectOvalPtr->bbox[3] = (coords[1] < coords[3]) ? coords[3] : coords[1];
ComputeRectOvalBbox(canvas, rectOvalPtr);
}