Skip to content

Commit

Permalink
Correct GC offset calculation #788
Browse files Browse the repository at this point in the history
The offset calculation in the GC when having an odd line width is
erroneous in case rotation transformations have been applied to the GC.
With a rotation of 45°, the calculation even suffers from singularities
that result in effectively nothing being drawn. With other
transformation properties, off-by-one error occur.

This change inverts the offset calculation: Instead of performing a
forward transformation of a dummy point whose result is applied to the
expected offset, the inverse transformation is applied to the expected
offset. This avoids singularities and imprecision in the calculation and
ensures that when applying rotations to the GC, the drawing figures are
as expected.

Fixes #788.
  • Loading branch information
HeikoKlare committed Aug 29, 2023
1 parent 4daf005 commit 5daeaec
Showing 1 changed file with 19 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -323,25 +323,26 @@ void checkGC(int mask) {
data.gdipFont = gdipFont;
}
if ((state & DRAW_OFFSET) != 0) {
data.gdipXOffset = data.gdipYOffset = 0;
long matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
PointF point = new PointF();
point.X = point.Y = 1;
Gdip.Graphics_GetTransform(gdipGraphics, matrix);
Gdip.Matrix_TransformVectors(matrix, point, 1);
Gdip.Matrix_delete(matrix);
float scaling = point.X;
if (scaling < 0) scaling = -scaling;
float penWidth = data.lineWidth * scaling;
if (penWidth == 0 || (((int)penWidth) & 1) == 1) {
data.gdipXOffset = 0.5f / scaling;
}
scaling = point.Y;
if (scaling < 0) scaling = -scaling;
penWidth = data.lineWidth * scaling;
if (penWidth == 0 || (((int)penWidth) & 1) == 1) {
data.gdipYOffset = 0.5f / scaling;
PointF offset = new PointF();
int effectiveLineWidth = data.lineWidth < 1 ? 1 : Math.round(data.lineWidth);
// In case the effective line width is odd, add (0.5, 0.5) to coordinates in
// the coordinate system in which drawings are performed.
// I.e., a line starting at (0,0) will effectively start in pixel right below
// that coordinate with its center at (0.5, 0.5).
if (effectiveLineWidth % 2 == 1) {
offset.X = offset.Y = 0.5f;
}
// The offset will be applied to the coordinate system of the GC; so transform
// it from the drawing coordinate system to the coordinate system of the GC by
// applying the inverse transformation as the one applied to the GC and correct
// it by the line width.
long newMatrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
Gdip.Graphics_GetTransform(gdipGraphics, newMatrix);
Gdip.Matrix_Invert(newMatrix);
Gdip.Matrix_TransformVectors(newMatrix, offset, 1);
Gdip.Matrix_delete(newMatrix);
data.gdipXOffset = Math.abs(offset.X) / effectiveLineWidth;
data.gdipYOffset = Math.abs(offset.Y) / effectiveLineWidth;
}
return;
}
Expand Down

0 comments on commit 5daeaec

Please sign in to comment.