mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
New rotation system (see forum thread).
Major changes: - when rotating, the top left corner of the rectangle stays in place. - ValueViewers get a dc that is pre-rotated/translated for them, i.e. (0,0) is the top-left of the viewer (with ValueViewer::getRotation). - moved 'angle' from individual Styles to the Style base class. - any rotation angle is now possible. angle is still an int for now. This warrants a version bump git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@782 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+161
-88
@@ -12,86 +12,157 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rotation
|
||||
|
||||
// constrain an angle to {0,90,180,270}
|
||||
// constrain an angle to [0..360)
|
||||
int constrain_angle(int angle) {
|
||||
int a = ((angle + 45) % 360 + 360) % 360; // [0..360)
|
||||
return (a / 90) * 90; // multiple of 90
|
||||
return (angle + 3600) % 360;
|
||||
}
|
||||
|
||||
Rotation::Rotation(int angle, const RealRect& rect, double zoom, double strectch, bool is_internal)
|
||||
Rotation::Rotation(int angle, const RealRect& rect, double zoom, double stretch, RotationFlags flags)
|
||||
: angle(constrain_angle(angle))
|
||||
, size(rect.size())
|
||||
, origin(rect.position())
|
||||
, zoomX(::sideways(angle) ? zoom : zoom * strectch)
|
||||
, zoomY(!::sideways(angle) ? zoom : zoom * strectch)
|
||||
, zoomX(zoom * stretch)
|
||||
, zoomY(zoom)
|
||||
{
|
||||
if (is_internal) {
|
||||
size = trNoNeg(size);
|
||||
if (stretch != 1.0) {
|
||||
size.width /= stretch;
|
||||
}
|
||||
// set origin
|
||||
if (revX()) origin.x += size.width;
|
||||
if (revY()) origin.y += size.height;
|
||||
if (flags & ROTATION_ATTACH_TOP_LEFT) {
|
||||
if (revX()) origin.x += zoom * (sideways() ? size.height : size.width);
|
||||
if (revY()) origin.y += zoom * (sideways() ? size.width : size.height);
|
||||
}
|
||||
}
|
||||
|
||||
RealRect Rotation::getExternalRect() const {
|
||||
return RealRect(origin - RealSize(revX() ? size.width : 0, revY() ? size.height : 0), size);
|
||||
void Rotation::setStretch(double s) {
|
||||
size.width *= s * getStretch();
|
||||
zoomX = zoomY * s;
|
||||
}
|
||||
|
||||
|
||||
RealPoint Rotation::tr(const RealPoint& p) const {
|
||||
return tr(RealSize(p.x, p.y)) + origin; // TODO : optimize?
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double x = p.x * zoomX, y = p.y * zoomY;
|
||||
return RealPoint(c * x + s * y + origin.x,
|
||||
-s * x + c * y + origin.y);
|
||||
}
|
||||
RealSize Rotation::tr(const RealSize& s) const {
|
||||
if (sideways()) {
|
||||
return RealSize(negX(s.height) * zoomY, negY(s.width) * zoomX);
|
||||
RealPoint Rotation::trPixel(const RealPoint& p) const {
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double x = p.x * zoomX + 0.5, y = p.y * zoomY + 0.5;
|
||||
return RealPoint(c * x + s * y + origin.x - 0.5,
|
||||
-s * x + c * y + origin.y - 0.5);
|
||||
}
|
||||
RealPoint Rotation::trNoZoom(const RealPoint& p) const {
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double x = p.x, y = p.y;
|
||||
return RealPoint(c * x + s * y + origin.x,
|
||||
-s * x + c * y + origin.y);
|
||||
}
|
||||
RealPoint Rotation::trPixelNoZoom(const RealPoint& p) const {
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double x = p.x + 0.5, y = p.y + 0.5;
|
||||
return RealPoint(c * x + s * y + origin.x - 0.5,
|
||||
-s * x + c * y + origin.y - 0.5);
|
||||
}
|
||||
/*
|
||||
RealSize Rotation::trSize(const RealSize& size) const {
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double x = size.width * zoomX, y = size.height * zoomY;
|
||||
return RealSize(c * x + s * y, s * x + c * y);
|
||||
}
|
||||
*/
|
||||
RealSize Rotation::trSizeToBB(const RealSize& size) const {
|
||||
if (straight()) {
|
||||
if (sideways()) {
|
||||
return RealSize(size.height * zoomY, size.width * zoomX);
|
||||
} else {
|
||||
return RealSize(size.width * zoomX, size.height * zoomY);
|
||||
}
|
||||
} else {
|
||||
return RealSize(negX(s.width) * zoomX, negY(s.height) * zoomY);
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double x = size.width * zoomX, y = size.height * zoomY;
|
||||
return RealSize(fabs(c * x) + fabs(s * y), fabs(s * x) + fabs(c * y));
|
||||
}
|
||||
}
|
||||
RealRect Rotation::tr(const RealRect& r) const {
|
||||
return RealRect(tr(r.position()), tr(r.size()));
|
||||
}
|
||||
|
||||
RealSize Rotation::trNoNeg(const RealSize& s) const {
|
||||
if (sideways()) {
|
||||
return RealSize(s.height * zoomY, s.width * zoomX);
|
||||
RealRect Rotation::trRectToBB(const RealRect& r) const {
|
||||
if (straight()) {
|
||||
RealSize s = trSizeToBB(r.size());
|
||||
return RealRect(tr(r.position()) - RealSize(revX()?s.width:0, revY()?s.height:0), s);
|
||||
} else {
|
||||
return RealSize(s.width * zoomX, s.height * zoomY);
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double x = r.x * zoomX, y = r.y * zoomY;
|
||||
double w = r.width * zoomX, h = r.height * zoomY;
|
||||
RealRect result(c * x + s * y + origin.x,
|
||||
-s * x + c * y + origin.y,
|
||||
0,0);
|
||||
if (c > 0) {
|
||||
result.width += c * w;
|
||||
result.height += c * h;
|
||||
} else {
|
||||
result.x += c * w;
|
||||
result.width -= c * w;
|
||||
result.y += c * h;
|
||||
result.height -= c * h;
|
||||
}
|
||||
if (s > 0) {
|
||||
result.width += s * h;
|
||||
result.y -= s * w;
|
||||
result.height += s * w;
|
||||
} else {
|
||||
result.x += s * h;
|
||||
result.width -= s * h;
|
||||
result.height -= s * w;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
RealRect Rotation::trNoNeg(const RealRect& r) const {
|
||||
RealSize s = trNoNeg(r.size());
|
||||
return RealRect(tr(r.position()) - RealSize(revX()?s.width:0, revY()?s.height:0), s);
|
||||
RealRect Rotation::trRectStraight(const RealRect& r) const {
|
||||
assert(angle == 0);
|
||||
return RealRect(r.position() + origin, r.size());
|
||||
}
|
||||
RealRect Rotation::trNoNegNoZoom(const RealRect& r) const {
|
||||
RealSize s = sideways() ? RealSize(r.height, r.width) : r.size();
|
||||
return RealRect(tr(r.position()) - RealSize(revX()?s.width:0, revY()?s.height:0), s);
|
||||
}
|
||||
|
||||
|
||||
RealSize Rotation::trInv(const RealSize& s) const {
|
||||
if (sideways()) {
|
||||
return RealSize(negY(s.height) / zoomY, negX(s.width) / zoomX);
|
||||
wxRegion Rotation::trRectToRegion(const RealRect& r) const {
|
||||
if (straight()) {
|
||||
return trRectToBB(r).toRect();
|
||||
} else {
|
||||
return RealSize(negX(s.width) / zoomX, negY(s.height) / zoomY);
|
||||
wxPoint points[4] = {trPixel(RealPoint(r.left(), r.top() ))
|
||||
,trPixel(RealPoint(r.left(), r.bottom()))
|
||||
,trPixel(RealPoint(r.right(), r.bottom()))
|
||||
,trPixel(RealPoint(r.right(), r.top() ))};
|
||||
return wxRegion(4,points);
|
||||
}
|
||||
}
|
||||
|
||||
RealPoint Rotation::trInv(const RealPoint& p) const {
|
||||
RealPoint p2((p.x - origin.x) / zoomX, (p.y - origin.y) / zoomY);
|
||||
if (sideways()) {
|
||||
return RealPoint(negY(p2.y), negX(p2.x));
|
||||
} else {
|
||||
return RealPoint(negX(p2.x), negY(p2.y));
|
||||
}
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double x = (p.x - origin.x) / zoomX, y = (p.y - origin.y) / zoomY;
|
||||
return RealPoint(c * x - s * y,
|
||||
s * x + c * y);
|
||||
}
|
||||
|
||||
RealSize Rotation::trInvNoNeg(const RealSize& s) const {
|
||||
if (sideways()) {
|
||||
return RealSize(s.height / zoomY, s.width / zoomX);
|
||||
} else {
|
||||
return RealSize(s.width / zoomX, s.height / zoomY);
|
||||
}
|
||||
RealPoint Rotation::boundingBoxCorner(const RealSize& size) const {
|
||||
// This function is a bit tricky,
|
||||
// I derived it by drawing the four cases.
|
||||
// Two succeeding cases must agree where they overlap (0,90,180,270 degrees)
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
double w = size.width * zoomX, h = size.height * zoomY;
|
||||
if (angle <= 90) return RealPoint(0, -w * s);
|
||||
if (angle <= 180) return RealPoint(w * c, h * c - w * s);
|
||||
if (angle <= 270) return RealPoint(w * c + h * s, h * c);
|
||||
else return RealPoint(h * s, 0);
|
||||
}
|
||||
/*
|
||||
RealPoint Rotation::boundingBoxCorner(const RealSize& size) const {
|
||||
//if(true)return RealPoint(0,0);
|
||||
// This function is a bit tricky,
|
||||
// I derived it by drawing the four cases.
|
||||
// Two succeeding cases must agree where they overlap (0,90,180,270 degrees)
|
||||
double a = deg_to_rad(angle), s = sin(a), c = cos(a);
|
||||
if (angle <= 90) return RealPoint( + size.width * s * s, - size.width * s * c);
|
||||
if (angle <= 180) return RealPoint(size.width - size.height * s * c, size.height * c * c);
|
||||
if (angle <= 270) return RealPoint(size.width - size.width * s * s, size.height + size.width * s * c);
|
||||
else return RealPoint( size.height * s * c, size.height - size.height * c * c);
|
||||
}
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rotater
|
||||
|
||||
@@ -100,17 +171,12 @@ Rotater::Rotater(Rotation& rot, const Rotation& by)
|
||||
, rot(rot)
|
||||
{
|
||||
// apply rotation
|
||||
RealRect new_ext = rot.trNoNeg(by.getExternalRect());
|
||||
rot.angle = constrain_angle(rot.angle + by.angle);
|
||||
if (by.sideways()) {
|
||||
rot.zoomX *= by.zoomY;
|
||||
rot.zoomY *= by.zoomX;
|
||||
} else {
|
||||
rot.zoomX *= by.zoomX;
|
||||
rot.zoomY *= by.zoomY;
|
||||
}
|
||||
rot.size = new_ext.size();
|
||||
rot.origin = new_ext.position() + RealSize(rot.revX() ? rot.size.width : 0, rot.revY() ? rot.size.height : 0);
|
||||
rot.origin = rot.tr(by.origin);
|
||||
rot.size = by.size;
|
||||
rot.angle = constrain_angle(rot.angle + by.angle);
|
||||
// zooming is not really correct if rot.zoomX != rot.zoomY
|
||||
rot.zoomX *= by.zoomX;
|
||||
rot.zoomY *= by.zoomY;
|
||||
}
|
||||
|
||||
Rotater::~Rotater() {
|
||||
@@ -119,8 +185,8 @@ Rotater::~Rotater() {
|
||||
|
||||
// ----------------------------------------------------------------------------- : RotatedDC
|
||||
|
||||
RotatedDC::RotatedDC(DC& dc, int angle, const RealRect& rect, double zoom, RenderQuality quality, bool is_internal)
|
||||
: Rotation(angle, rect, zoom, 1.0, is_internal)
|
||||
RotatedDC::RotatedDC(DC& dc, int angle, const RealRect& rect, double zoom, RenderQuality quality, RotationFlags flags)
|
||||
: Rotation(angle, rect, zoom, 1.0, flags)
|
||||
, dc(dc), quality(quality)
|
||||
{}
|
||||
|
||||
@@ -133,11 +199,11 @@ RotatedDC::RotatedDC(DC& dc, const Rotation& rotation, RenderQuality quality)
|
||||
|
||||
void RotatedDC::DrawText (const String& text, const RealPoint& pos, int blur_radius, int boldness, double stretch_) {
|
||||
if (text.empty()) return;
|
||||
if (quality == QUALITY_AA) {
|
||||
if (quality >= QUALITY_AA) {
|
||||
RealRect r(pos, GetTextExtent(text));
|
||||
RealRect r_ext = trNoNeg(r);
|
||||
draw_resampled_text(dc, r_ext, stretch_ * stretch(), revX(), revY(), angle, text, blur_radius, boldness);
|
||||
} else if (quality == QUALITY_SUB_PIXEL) {
|
||||
RealRect r_ext = trRectToBB(r);
|
||||
draw_resampled_text(dc, tr(pos), r_ext, stretch_ * getStretch(), angle, text, blur_radius, boldness);
|
||||
} else if (quality >= QUALITY_SUB_PIXEL) {
|
||||
RealPoint p_ext = tr(pos)*text_scaling;
|
||||
double usx,usy;
|
||||
dc.GetUserScale(&usx, &usy);
|
||||
@@ -158,17 +224,16 @@ void RotatedDC::DrawBitmap(const Bitmap& bitmap, const RealPoint& pos) {
|
||||
DrawImage(bitmap.ConvertToImage(), pos);
|
||||
}
|
||||
}
|
||||
void RotatedDC::DrawImage (const Image& image, const RealPoint& pos, ImageCombine combine, int angle) {
|
||||
Image rotated = rotate_image(image, angle + this->angle);
|
||||
wxRect r = trNoNegNoZoom(RealRect(pos, RealSize(image)));
|
||||
draw_combine_image(dc, to_int(r.x), to_int(r.y), rotated, combine);
|
||||
void RotatedDC::DrawImage(const Image& image, const RealPoint& pos, ImageCombine combine) {
|
||||
Image rotated = rotate_image(image, angle);
|
||||
DrawPreRotatedImage(rotated, RealRect(pos,trInvS(RealSize(image))), combine);
|
||||
}
|
||||
void RotatedDC::DrawPreRotatedBitmap(const Bitmap& bitmap, const RealPoint& pos) {
|
||||
RealPoint p_ext = tr(pos) - RealSize(revX()?bitmap.GetWidth():0, revY()?bitmap.GetHeight():0);
|
||||
void RotatedDC::DrawPreRotatedBitmap(const Bitmap& bitmap, const RealRect& rect) {
|
||||
RealPoint p_ext = tr(rect.position()) + boundingBoxCorner(rect.size());
|
||||
dc.DrawBitmap(bitmap, to_int(p_ext.x), to_int(p_ext.y), true);
|
||||
}
|
||||
void RotatedDC::DrawPreRotatedImage (const Image& image, const RealPoint& pos, ImageCombine combine) {
|
||||
RealPoint p_ext = tr(pos) - RealSize(revX()?image.GetWidth():0, revY()?image.GetHeight():0);
|
||||
void RotatedDC::DrawPreRotatedImage (const Image& image, const RealRect& rect, ImageCombine combine) {
|
||||
RealPoint p_ext = tr(rect.position()) + boundingBoxCorner(rect.size());
|
||||
draw_combine_image(dc, to_int(p_ext.x), to_int(p_ext.y), image, combine);
|
||||
}
|
||||
|
||||
@@ -178,13 +243,26 @@ void RotatedDC::DrawLine (const RealPoint& p1, const RealPoint& p2) {
|
||||
}
|
||||
|
||||
void RotatedDC::DrawRectangle(const RealRect& r) {
|
||||
wxRect r_ext = trNoNeg(r);
|
||||
dc.DrawRectangle(r_ext.x, r_ext.y, r_ext.width, r_ext.height);
|
||||
if (straight()) {
|
||||
wxRect r_ext = trRectToBB(r);
|
||||
dc.DrawRectangle(r_ext.x, r_ext.y, r_ext.width, r_ext.height);
|
||||
} else {
|
||||
wxPoint points[4] = {trPixel(RealPoint(r.left(), r.top() ))
|
||||
,trPixel(RealPoint(r.left(), r.bottom()))
|
||||
,trPixel(RealPoint(r.right(), r.bottom()))
|
||||
,trPixel(RealPoint(r.right(), r.top() ))};
|
||||
dc.DrawPolygon(4,points);
|
||||
}
|
||||
}
|
||||
|
||||
void RotatedDC::DrawRoundedRectangle(const RealRect& r, double radius) {
|
||||
wxRect r_ext = trNoNeg(r);
|
||||
dc.DrawRoundedRectangle(r_ext.x, r_ext.y, r_ext.width, r_ext.height, trS(radius));
|
||||
if (straight()) {
|
||||
wxRect r_ext = trRectToBB(r);
|
||||
dc.DrawRoundedRectangle(r_ext.x, r_ext.y, r_ext.width, r_ext.height, trS(radius));
|
||||
} else {
|
||||
// TODO
|
||||
DrawRectangle(r);
|
||||
}
|
||||
}
|
||||
|
||||
void RotatedDC::DrawCircle(const RealPoint& center, double radius) {
|
||||
@@ -192,19 +270,14 @@ void RotatedDC::DrawCircle(const RealPoint& center, double radius) {
|
||||
dc.DrawCircle(p.x + 1, p.y + 1, trS(radius));
|
||||
}
|
||||
|
||||
/// Convert radians to degrees
|
||||
double rad_to_deg(double rad) { return rad * (180.0 / M_PI); }
|
||||
/// Convert degrees to radians
|
||||
double deg_to_rad(double deg) { return deg * (M_PI / 180.0); }
|
||||
|
||||
void RotatedDC::DrawEllipticArc(const RealPoint& center, const RealSize& size, double start, double end) {
|
||||
wxPoint c_ext = tr(center - size/2);
|
||||
wxSize s_ext = trNoNeg(size);
|
||||
wxSize s_ext = trSizeToBB(size);
|
||||
dc.DrawEllipticArc(c_ext.x, c_ext.y, s_ext.x, s_ext.y, rad_to_deg(start) + angle, rad_to_deg(end) + angle);
|
||||
}
|
||||
void RotatedDC::DrawEllipticSpoke(const RealPoint& center, const RealSize& size, double angle) {
|
||||
wxPoint c_ext = tr(center - size/2);
|
||||
wxSize s_ext = trNoNeg(size);
|
||||
wxSize s_ext = trSizeToBB(size);
|
||||
double rot_angle = angle + deg_to_rad(this->angle);
|
||||
double sin_angle = sin(rot_angle), cos_angle = cos(rot_angle);
|
||||
// position of center and of point on the boundary can vary because of rounding errors,
|
||||
@@ -281,7 +354,7 @@ double RotatedDC::GetCharHeight() const {
|
||||
}
|
||||
|
||||
void RotatedDC::SetClippingRegion(const RealRect& rect) {
|
||||
dc.SetClippingRegion(trNoNeg(rect));
|
||||
dc.SetClippingRegion(trRectToRegion(rect));
|
||||
}
|
||||
void RotatedDC::DestroyClippingRegion() {
|
||||
dc.DestroyClippingRegion();
|
||||
@@ -290,7 +363,7 @@ void RotatedDC::DestroyClippingRegion() {
|
||||
// ----------------------------------------------------------------------------- : Other
|
||||
|
||||
Bitmap RotatedDC::GetBackground(const RealRect& r) {
|
||||
wxRect wr = trNoNeg(r);
|
||||
wxRect wr = trRectToBB(r);
|
||||
Bitmap background(wr.width, wr.height);
|
||||
wxMemoryDC mdc;
|
||||
mdc.SelectObject(background);
|
||||
|
||||
+55
-44
@@ -17,6 +17,11 @@ class Font;
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rotation
|
||||
|
||||
enum RotationFlags
|
||||
{ ROTATION_NORMAL
|
||||
, ROTATION_ATTACH_TOP_LEFT
|
||||
};
|
||||
|
||||
/// An object that can rotate coordinates inside a specified rectangle
|
||||
/** This class has lots of tr*** functions, they convert
|
||||
* internal coordinates to external/screen coordinates.
|
||||
@@ -28,48 +33,61 @@ class Rotation {
|
||||
/** with the given rectangle of external coordinates and a given rotation angle and zoom factor.
|
||||
* if is_internal then the rect gives the internal coordinates, its origin should be (0,0)
|
||||
*/
|
||||
Rotation(int angle, const RealRect& rect, double zoom = 1.0, double strectch = 1.0, bool is_internal = false);
|
||||
Rotation(int angle, const RealRect& rect, double zoom = 1.0, double strectch = 1.0, RotationFlags flags = ROTATION_NORMAL);
|
||||
|
||||
/// Change the zoom factor
|
||||
inline void setZoom(double z) { zoomX = zoomY = z; }
|
||||
/// Retrieve the zoom factor
|
||||
inline double getZoom() const { return zoomY; }
|
||||
/// Change the angle
|
||||
void setAngle(int a);
|
||||
/// Change the stretch factor
|
||||
void setStretch(double s);
|
||||
/// Stretch factor
|
||||
inline double getStretch() const { return zoomX / zoomY; }
|
||||
/// Get the angle
|
||||
inline int getAngle() const { return angle; }
|
||||
/// Change the origin
|
||||
inline void setOrigin(const RealPoint& o) { origin = o; }
|
||||
|
||||
|
||||
/// The internal size
|
||||
inline RealSize getInternalSize() const { return trInvNoNeg(size); }
|
||||
inline RealSize getInternalSize() const { return size; }
|
||||
inline double getWidth() const { return size.width; }
|
||||
inline double getHeight() const { return size.height; }
|
||||
/// The intarnal rectangle (origin at (0,0))
|
||||
inline RealRect getInternalRect() const { return RealRect(RealPoint(0,0), getInternalSize()); }
|
||||
inline RealRect getInternalRect() const { return RealRect(RealPoint(0,0), size); }
|
||||
/// The size of the external rectangle (as passed to the constructor) == trNoNeg(getInternalSize())
|
||||
inline RealSize getExternalSize() const { return size; }
|
||||
inline RealSize getExternalSize() const { return trSizeToBB(size); }
|
||||
/// The external rectangle (as passed to the constructor) == trNoNeg(getInternalRect())
|
||||
RealRect getExternalRect() const;
|
||||
inline RealRect getExternalRect() const { return trRectToBB(getInternalRect()); }
|
||||
|
||||
/// Translate a size or length
|
||||
inline double trS(double s) const { return s * zoomY; }
|
||||
inline double trX(double s) const { return s * zoomX; }
|
||||
inline double trY(double s) const { return s * zoomY; }
|
||||
inline RealSize trS(const RealSize& s) const { return RealSize(s.width * zoomX, s.height * zoomY); }
|
||||
|
||||
/// Translate an angle
|
||||
inline int trAngle(int a) { return (angle + a) % 360; }
|
||||
|
||||
/// Translate a single point
|
||||
RealPoint tr(const RealPoint& p) const;
|
||||
/// Translate a single size, the result may be negative
|
||||
RealSize tr(const RealSize& s) const;
|
||||
/// Translate a rectangle, the size of the result may be negative
|
||||
RealRect tr(const RealRect& r) const;
|
||||
|
||||
/// Translate a size, the result will never be negative
|
||||
RealSize trNoNeg(const RealSize& s) const;
|
||||
/// Translate a rectangle, the result will never have a negative size
|
||||
RealRect trNoNeg(const RealRect& r) const;
|
||||
/// Translate a rectangle, the result will never have a negative size
|
||||
/** The rectangle is also not zoomed */
|
||||
RealRect trNoNegNoZoom(const RealRect& r) const;
|
||||
/// Translate a single point, but don't zoom
|
||||
RealPoint trNoZoom(const RealPoint& p) const;
|
||||
/// Translate a 'pixel'. A pixel has size 1*1
|
||||
RealPoint trPixel(const RealPoint& p) const;
|
||||
/// Translate a 'pixel', but don't zoom
|
||||
RealPoint trPixelNoZoom(const RealPoint& p) const;
|
||||
/// Translate a single size
|
||||
RealSize trSize(const RealSize& s) const;
|
||||
/// Translate a single size, returns the bounding box size (non-negative)
|
||||
RealSize trSizeToBB(const RealSize& s) const;
|
||||
/// Translate a rectangle, returns the bounding box
|
||||
/* //%%the size of the result may be negative*/
|
||||
RealRect trRectToBB(const RealRect& r) const;
|
||||
/// Translate a rectangle, can only be used when not rotating
|
||||
RealRect trRectStraight(const RealRect& r) const;
|
||||
/// Translate a rectangle into a region (supports rotation
|
||||
wxRegion trRectToRegion(const RealRect& rect) const;
|
||||
|
||||
/// Translate a size or length back to internal 'coordinates'
|
||||
inline double trInvS(double s) const { return s / zoomY; }
|
||||
@@ -80,36 +98,28 @@ class Rotation {
|
||||
|
||||
/// Translate a point back to internal coordinates
|
||||
RealPoint trInv(const RealPoint& p) const;
|
||||
/// Translate a size back to internal coordinates
|
||||
RealSize trInv(const RealSize& s) const;
|
||||
/// Translate a size back to internal coordinates, that are not negative
|
||||
RealSize trInvNoNeg(const RealSize& s) const;
|
||||
|
||||
/// Stretch factor
|
||||
inline double stretch() const { return zoomX / zoomY; }
|
||||
|
||||
protected:
|
||||
int angle; ///< The angle of rotation in degrees (counterclockwise)
|
||||
RealSize size; ///< Size of the rectangle, in external coordinates
|
||||
RealSize size; ///< Size of the rectangle, in internal coordinates
|
||||
RealPoint origin; ///< tr(0,0)
|
||||
double zoomX; ///< Zoom factor, zoom = 2.0 means that 1 internal = 2 external
|
||||
double zoomY;
|
||||
|
||||
friend class Rotater;
|
||||
|
||||
public:
|
||||
/// Is the rotation sideways (90 or 270 degrees)?
|
||||
inline bool sideways() const { return ::sideways(angle); }
|
||||
|
||||
protected:
|
||||
/// Is the x axis 'reversed' (after turning sideways)?
|
||||
inline bool revX() const { return angle >= 180; }
|
||||
/// Is the y axis 'reversed' (after turning sideways)?
|
||||
inline bool revY() const { return angle == 90 || angle == 180; }
|
||||
/// Negate if revX
|
||||
inline double negX(double d) const { return revX() ? -d : d; }
|
||||
/// Negate if revY
|
||||
inline double negY(double d) const { return revY() ? -d : d; }
|
||||
/// Is the rotation 'simple', i.e. a multiple of 90 degrees?
|
||||
inline bool straight() const { return ::straight(angle); }
|
||||
/// Is the rotation sideways (90 or 270 degrees)?
|
||||
// Note: angle & 2 == 0 for angle in {0, 180} and != 0 for angle in {90, 270)
|
||||
inline bool sideways() const { return (angle & 2) != 0; }
|
||||
|
||||
/// Determine the top-left corner of the bounding box around the rotated box s (in external coordinates)
|
||||
RealPoint boundingBoxCorner(const RealSize& s) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rotater
|
||||
@@ -138,9 +148,9 @@ class Rotater {
|
||||
|
||||
/// Render quality of text
|
||||
enum RenderQuality {
|
||||
QUALITY_AA, ///< Our own anti aliassing
|
||||
QUALITY_SUB_PIXEL, ///< Sub-pixel positioning
|
||||
QUALITY_LOW, ///< Normal
|
||||
QUALITY_SUB_PIXEL, ///< Sub-pixel positioning
|
||||
QUALITY_AA, ///< Our own anti aliassing
|
||||
};
|
||||
|
||||
/// A DC with rotation applied
|
||||
@@ -148,20 +158,21 @@ enum RenderQuality {
|
||||
*/
|
||||
class RotatedDC : public Rotation {
|
||||
public:
|
||||
RotatedDC(DC& dc, int angle, const RealRect& rect, double zoom, RenderQuality quality, bool is_internal = false);
|
||||
RotatedDC(DC& dc, int angle, const RealRect& rect, double zoom, RenderQuality quality, RotationFlags flags = ROTATION_NORMAL);
|
||||
RotatedDC(DC& dc, const Rotation& rotation, RenderQuality quality);
|
||||
|
||||
|
||||
// --------------------------------------------------- : Drawing
|
||||
|
||||
void DrawText (const String& text, const RealPoint& pos, int blur_radius = 0, int boldness = 1, double stretch = 1.0);
|
||||
/// Draw abitmap, it must already be zoomed!
|
||||
void DrawBitmap(const Bitmap& bitmap, const RealPoint& pos);
|
||||
/// Draw an image using the given combining mode, the image must already be zoomed!
|
||||
void DrawImage (const Image& image, const RealPoint& pos, ImageCombine combine = COMBINE_DEFAULT, int angle = 0);
|
||||
/// Draw a bitmap that is already zoomed and rotated
|
||||
void DrawPreRotatedBitmap(const Bitmap& bitmap, const RealPoint& pos);
|
||||
void DrawImage (const Image& image, const RealPoint& pos, ImageCombine combine = COMBINE_DEFAULT);
|
||||
/// Draw a bitmap that is already zoomed and rotated.
|
||||
/** The rectangle the position in internal coordinates, and the size before rotating and zooming */
|
||||
void DrawPreRotatedBitmap(const Bitmap& bitmap, const RealRect& rect);
|
||||
/// Draw an image that is already zoomed and rotated
|
||||
void DrawPreRotatedImage(const Image& image, const RealPoint& pos, ImageCombine combine = COMBINE_DEFAULT);
|
||||
void DrawPreRotatedImage(const Image& image, const RealRect& rect, ImageCombine combine = COMBINE_DEFAULT);
|
||||
void DrawLine (const RealPoint& p1, const RealPoint& p2);
|
||||
void DrawRectangle(const RealRect& r);
|
||||
void DrawRoundedRectangle(const RealRect& r, double radius);
|
||||
|
||||
@@ -49,7 +49,7 @@ template <> void GetDefaultMember::handle(const Version& v) {
|
||||
// ----------------------------------------------------------------------------- : Versions
|
||||
|
||||
// NOTE: Don't use leading zeroes, they mean octal
|
||||
const Version app_version = 305; // 0.3.5
|
||||
const Version app_version = 306; // 0.3.6
|
||||
#ifdef UNICODE
|
||||
const Char* version_suffix = _(" (beta)");
|
||||
#else
|
||||
@@ -67,5 +67,6 @@ const Char* version_suffix = _(" (beta, ascii build)");
|
||||
* 0.3.3 : keyword separator before/after
|
||||
* 0.3.4 : html export; choice rendering based on scripted 'image'
|
||||
* 0.3.5 : word lists, symbol font 'as text'
|
||||
* 0.3.6 : free rotation, rotation behaviour changed.
|
||||
*/
|
||||
const Version file_version = 305; // 0.3.5
|
||||
const Version file_version = 306; // 0.3.6
|
||||
|
||||
Reference in New Issue
Block a user