From 9f567a512e0a2294ae55aa6eb799931a61fb5f14 Mon Sep 17 00:00:00 2001 From: twanvl Date: Sat, 7 Jul 2007 16:19:17 +0000 Subject: [PATCH] Rotation can now zoom in x and y directions separatly; text can be scaled stretched/compressed horizontally. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@520 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/data/field/text.cpp | 10 ++++ src/data/field/text.hpp | 6 +++ src/gfx/gfx.hpp | 7 +-- src/gfx/resample_text.cpp | 80 +++++++++++++++++----------- src/gui/value/text.cpp | 4 +- src/render/text/viewer.cpp | 2 +- src/render/value/choice.cpp | 4 +- src/render/value/color.cpp | 2 +- src/render/value/image.cpp | 6 +-- src/render/value/multiple_choice.cpp | 4 +- src/util/alignment.cpp | 25 +++++---- src/util/alignment.hpp | 3 +- src/util/rotation.cpp | 49 +++++++++-------- src/util/rotation.hpp | 20 ++++--- 14 files changed, 137 insertions(+), 85 deletions(-) diff --git a/src/data/field/text.cpp b/src/data/field/text.cpp index 5d97f444..a45a472d 100644 --- a/src/data/field/text.cpp +++ b/src/data/field/text.cpp @@ -56,6 +56,16 @@ TextStyle::TextStyle(const TextFieldP& field) , direction(LEFT_TO_RIGHT) {} +double TextStyle::getStretch() const { + if (content_width > 0 && ((alignment() & ALIGN_STRETCH) || (alignment() & ALIGN_STRETCH_OVERFLOW))) { + double factor = (width - padding_left - padding_right) / content_width; + if (alignment() == ALIGN_STRETCH || factor < 1.0) { + return factor; + } + } + return 1.0; +} + bool TextStyle::update(Context& ctx) { return Style ::update(ctx) | font .update(ctx) diff --git a/src/data/field/text.hpp b/src/data/field/text.hpp index 6d46b747..acbd663a 100644 --- a/src/data/field/text.hpp +++ b/src/data/field/text.hpp @@ -80,8 +80,14 @@ class TextStyle : public Style { /// The rotation to use when drawing inline Rotation getRotation() const { + return Rotation(angle, getRect(), 1.0, getStretch()); + } + /// The rotation to use when determining content layout, does not include the stretch factor + inline Rotation getRotationNoStretch() const { return Rotation(angle, getRect()); } + /// Stretch factor to use + double getStretch() const; private: DECLARE_REFLECTION(); diff --git a/src/gfx/gfx.hpp b/src/gfx/gfx.hpp index 157a8018..df089f60 100644 --- a/src/gfx/gfx.hpp +++ b/src/gfx/gfx.hpp @@ -45,10 +45,11 @@ void sharp_resample_and_clip(const Image& img_in, Image& img_out, wxRect rect, i /// Draw text by first drawing it using a larger font and then downsampling it /** optionally rotated by an angle. - * rect = rectangle to draw in - * (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right + * rect = rectangle to draw in + * stretch_x = amount to stretch horizontally after drawing + * (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right */ -void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text, int blur_radius = 0, int repeat = 1); +void draw_resampled_text(DC& dc, const RealRect& rect, double stretch_x, int wc, int hc, int angle, const String& text, int blur_radius = 0, int repeat = 1); // scaling factor to use when drawing resampled text extern const int text_scaling; diff --git a/src/gfx/resample_text.cpp b/src/gfx/resample_text.cpp index e225f4bc..c7647ba0 100644 --- a/src/gfx/resample_text.cpp +++ b/src/gfx/resample_text.cpp @@ -20,27 +20,62 @@ const int text_scaling = 4; // Downsamples the red channel of the input image to the alpha channel of the output image // img_in must be text_scaling times as large as img_out void downsample_to_alpha(Image& img_in, Image& img_out) { - assert(img_in.GetWidth() == img_out.GetWidth() * text_scaling); assert(img_in.GetHeight() == img_out.GetHeight() * text_scaling); - // scale in the x direction, this overwrites parts of the input image + Byte* temp = nullptr; Byte* in = img_in.GetData(); Byte* out = img_in.GetData(); - int count = img_out.GetWidth() * img_in.GetHeight(); - for (int i = 0 ; i < count ; ++i) { - int total = 0; - for (int j = 0 ; j < text_scaling ; ++j) { - total += in[3 * (j + text_scaling * i)]; + // scale in the x direction, this overwrites parts of the input image + if (img_in.GetWidth() == img_out.GetWidth() * text_scaling) { + // no stretching + int count = img_out.GetWidth() * img_in.GetHeight(); + for (int i = 0 ; i < count ; ++i) { + int total = 0; + for (int j = 0 ; j < text_scaling ; ++j) { + total += in[3 * (j + text_scaling * i)]; + } + out[i] = total / text_scaling; } - out[i] = total / text_scaling; + } else { + // resample to buffer + temp = new Byte[img_out.GetWidth() * img_in.GetHeight()]; + out = temp; + // custom stretch, see resample_image.cpp + const int shift = 32-12-8; // => max size = 4096, max alpha = 255 + int w1 = img_in.GetWidth(), w2 = img_out.GetWidth(), h = img_in.GetHeight(); + int out_fact = (w2 << shift) / w1; // how much to output for 256 input = 1 pixel + int out_rest = (w2 << shift) % w1; + for (int y = 0 ; y < h ; ++y) { + int in_rem = out_fact + out_rest; + for (int x = 0 ; x < w2 ; ++x) { + int out_rem = 1 << shift; + int tot = 0; + while (out_rem >= in_rem) { + // eat a whole input pixel + tot += *in * in_rem; + out_rem -= in_rem; + in_rem = out_fact; + in += 3; + } + if (out_rem > 0) { + // eat a partial input pixel + tot += *in * out_rem; + in_rem -= out_rem; + } + // store + *out = tot >> shift; + out += 1; + } + } + in = temp; } // now scale in the y direction, and write to the output alpha img_out.InitAlpha(); - out = img_out.GetAlpha(); + out = img_out.GetAlpha(); int line_size = img_out.GetWidth(); for (int y = 0 ; y < img_out.GetHeight() ; ++y) { - for (int x = 0 ; x < img_out.GetWidth() ; ++x) { + for (int x = 0 ; x < line_size ; ++x) { int total = 0; for (int j = 0 ; j < text_scaling ; ++j) { total += in[x + line_size * (j + text_scaling * y)]; @@ -49,26 +84,7 @@ void downsample_to_alpha(Image& img_in, Image& img_out) { } } - /* - img_out.InitAlpha(); - Byte* in = img_in.GetData(); - Byte* out = img_out.GetAlpha(); - int w = img_out.GetWidth(), h = img_out.GetHeight(); - int line_size = 3 * w * text_scaling; - for (int y = 0 ; y < h ; ++y) { - for (int x = 0 ; x < w ; ++x) { - int total = 0; - for (int i = 0 ; i < text_scaling ; ++i) { - for (int j = 0 ; j < text_scaling ; ++j) { - total += in[3*j]; - } - in += line_size; - } - *out++ = total / (text_scaling * text_scaling); - in += 3 * text_scaling - line_size * text_scaling; - } - in += line_size * (text_scaling - 1); - }*/ + delete[] temp; } // simple blur @@ -97,7 +113,7 @@ void blur_image_alpha(Image& img) { // optionally rotated by an angle // (w2,h2) = size of text // (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right -void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text, int blur_radius, int repeat) { +void draw_resampled_text(DC& dc, const RealRect& rect, double stretch_x, int wc, int hc, int angle, const String& text, int blur_radius, int repeat) { // enlarge slightly; some fonts are larger then the GetTextExtent tells us (especially italic fonts) int w = static_cast(rect.width) + 3 + 2 * blur_radius, h = static_cast(rect.height) + 1 + 2 * blur_radius; // determine sub-pixel position @@ -116,7 +132,7 @@ void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle mdc.SelectObject(wxNullBitmap); Image img_large = buffer.ConvertToImage(); // step 2. sample down - Image img_small(w, h, false); + Image img_small(stretch_x * w, h, false); fill_image(img_small, dc.GetTextForeground()); downsample_to_alpha(img_large, img_small); // blur diff --git a/src/gui/value/text.cpp b/src/gui/value/text.cpp index c9244469..ca83717a 100644 --- a/src/gui/value/text.cpp +++ b/src/gui/value/text.cpp @@ -776,10 +776,10 @@ void TextValueEditor::determineSize(bool force_fit) { int sbw = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); RealPoint pos = rot.tr(style().getPos()); scrollbar->SetSize( - (int)(pos.x + rot.trS(style().width) + 1 - sbw), + (int)(pos.x + rot.trX(style().width) + 1 - sbw), (int)pos.y - 1, (int)sbw, - (int)rot.trS(style().height) + 2); + (int)rot.trY(style().height) + 2); v.reset(); } else { // Height depends on font diff --git a/src/render/text/viewer.cpp b/src/render/text/viewer.cpp index 276d5827..59369d94 100644 --- a/src/render/text/viewer.cpp +++ b/src/render/text/viewer.cpp @@ -134,7 +134,7 @@ void TextViewer::drawSeparators(RotatedDC& dc) { bool TextViewer::prepare(RotatedDC& dc, const String& text, TextStyle& style, Context& ctx) { if (lines.empty()) { // not prepared yet - Rotater r(dc, style.getRotation()); + Rotater r(dc, style.getRotationNoStretch()); prepareElements(text, style, ctx); prepareLines(dc, text, style, ctx); return true; diff --git a/src/render/value/choice.cpp b/src/render/value/choice.cpp index 4769a6c5..6617b47c 100644 --- a/src/render/value/choice.cpp +++ b/src/render/value/choice.cpp @@ -35,8 +35,8 @@ void ChoiceValueViewer::draw(RotatedDC& dc) { } else if(style().render_style & RENDER_TEXT) { // also drawing text, use original size } else { - img_options.width = (int) dc.trS(style().width); - img_options.height = (int) dc.trS(style().height); + img_options.width = (int) dc.trX(style().width); + img_options.height = (int) dc.trY(style().height); img_options.preserve_aspect = style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT; } Image image = img.generate(img_options, true); diff --git a/src/render/value/color.cpp b/src/render/value/color.cpp index 125a5cf0..05159519 100644 --- a/src/render/value/color.cpp +++ b/src/render/value/color.cpp @@ -93,7 +93,7 @@ void ColorValueViewer::onStyleChange(bool already_prepared) { void ColorValueViewer::loadMask(const Rotation& rot) const { if (style().mask_filename().empty()) return; // no mask - int w = (int) rot.trS(style().width), h = (int) rot.trS(style().height); + int w = (int) rot.trX(style().width), h = (int) rot.trY(style().height); if (alpha_mask && alpha_mask->size == wxSize(w,h)) return; // mask loaded and right size // (re) load the mask Image image; diff --git a/src/render/value/image.cpp b/src/render/value/image.cpp index 7b3e5df9..618e420f 100644 --- a/src/render/value/image.cpp +++ b/src/render/value/image.cpp @@ -22,7 +22,7 @@ void ImageValueViewer::draw(RotatedDC& dc) { InputStreamP image_file = getSet().openIn(value().filename); Image image; if (image.LoadFile(*image_file)) { - image.Rescale((int)dc.trS(style().width), (int)dc.trS(style().height)); + image.Rescale((int)dc.trX(style().width), (int)dc.trY(style().height)); // apply mask to image loadMask(dc); if (alpha_mask) alpha_mask->setAlpha(image); @@ -34,7 +34,7 @@ void ImageValueViewer::draw(RotatedDC& dc) { } // if there is no image, generate a placeholder if (!bitmap.Ok()) { - UInt w = (UInt)dc.trS(style().width), h = (UInt)dc.trS(style().height); + UInt w = (UInt)dc.trX(style().width), h = (UInt)dc.trY(style().height); loadMask(dc); if (style().default_image.isReady()) { // we have a script to use for the default image @@ -85,7 +85,7 @@ void ImageValueViewer::onStyleChange(bool already_prepared) { void ImageValueViewer::loadMask(const Rotation& rot) const { if (style().mask_filename().empty()) return; // no mask - int w = (int) rot.trS(style().width), h = (int) rot.trS(style().height); + int w = (int) rot.trX(style().width), h = (int) rot.trY(style().height); if (alpha_mask && alpha_mask->size == wxSize(w,h)) return; // mask loaded and right size // (re) load the mask Image image; diff --git a/src/render/value/multiple_choice.cpp b/src/render/value/multiple_choice.cpp index e4f88b58..6368e90e 100644 --- a/src/render/value/multiple_choice.cpp +++ b/src/render/value/multiple_choice.cpp @@ -56,8 +56,8 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) { } else if(style().render_style & RENDER_TEXT) { // also drawing text, use original size } else { - img_options.width = (int) dc.trS(style().width); - img_options.height = (int) dc.trS(style().height); + img_options.width = (int) dc.trX(style().width); + img_options.height = (int) dc.trY(style().height); img_options.preserve_aspect = style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT; } Image image = img.generate(img_options, true); diff --git a/src/util/alignment.cpp b/src/util/alignment.cpp index 9cc13231..5be303e1 100644 --- a/src/util/alignment.cpp +++ b/src/util/alignment.cpp @@ -36,16 +36,18 @@ RealPoint align_in_rect(Alignment align, const RealSize& to_align, const RealRec /// Convert a String to an Alignment Alignment from_string(const String& s) { int al = ALIGN_TOP_LEFT; - if (s.find(_("left")) !=String::npos) al = ALIGN_LEFT | (al & ~ALIGN_HORIZONTAL); - if (s.find(_("center")) !=String::npos) al = ALIGN_CENTER | (al & ~ALIGN_HORIZONTAL); - if (s.find(_("right")) !=String::npos) al = ALIGN_RIGHT | (al & ~ALIGN_HORIZONTAL); - if (s.find(_("justify")) !=String::npos) al = ALIGN_JUSTIFY | (al & ~ALIGN_HORIZONTAL); - if (s.find(_("justify-words")) !=String::npos) al = ALIGN_JUSTIFY_WORDS | (al & ~ALIGN_HORIZONTAL); - if (s.find(_("shrink-overflow"))!=String::npos) al = ALIGN_JUSTIFY_OVERFLOW | (al & ~ALIGN_JUSTIFY_OVERFLOW); - if (s.find(_("top")) !=String::npos) al = ALIGN_TOP | (al & ~ALIGN_VERTICAL); - if (s.find(_("middle")) !=String::npos) al = ALIGN_MIDDLE | (al & ~ALIGN_VERTICAL); - if (s.find(_("bottom")) !=String::npos) al = ALIGN_BOTTOM | (al & ~ALIGN_VERTICAL); - if (s.find(_("stretch")) !=String::npos) al = ALIGN_STRETCH; + if (s.find(_("left")) !=String::npos) al = ALIGN_LEFT | (al & ~ALIGN_HORIZONTAL); + if (s.find(_("center")) !=String::npos) al = ALIGN_CENTER | (al & ~ALIGN_HORIZONTAL); + if (s.find(_("right")) !=String::npos) al = ALIGN_RIGHT | (al & ~ALIGN_HORIZONTAL); + if (s.find(_("justify")) !=String::npos) al = ALIGN_JUSTIFY | (al & ~ALIGN_HORIZONTAL); + if (s.find(_("justify-words")) !=String::npos) al = ALIGN_JUSTIFY_WORDS | (al & ~ALIGN_HORIZONTAL); + if (s.find(_("justify-overflow")) !=String::npos) al = ALIGN_JUSTIFY_OVERFLOW | (al & ~ALIGN_JUSTIFY_OVERFLOW); + if (s.find(_("shrink-overflow")) !=String::npos) al = ALIGN_STRETCH_OVERFLOW | (al & ~ALIGN_STRETCH_OVERFLOW); // compatability + if (s.find(_("stretch-overflow")) !=String::npos) al = ALIGN_STRETCH_OVERFLOW | (al & ~ALIGN_STRETCH_OVERFLOW); + if (s.find(_("top")) !=String::npos) al = ALIGN_TOP | (al & ~ALIGN_VERTICAL); + if (s.find(_("middle")) !=String::npos) al = ALIGN_MIDDLE | (al & ~ALIGN_VERTICAL); + if (s.find(_("bottom")) !=String::npos) al = ALIGN_BOTTOM | (al & ~ALIGN_VERTICAL); + if (s.find(_("stretch")) !=String::npos) al = ALIGN_STRETCH; return static_cast(al); } @@ -62,8 +64,9 @@ String to_string(Alignment align) { if (align & ALIGN_LEFT) ret += _(" right"); if (align & ALIGN_LEFT) ret += _(" justify"); if (align & ALIGN_LEFT) ret += _(" justify-words"); + if (align & ALIGN_JUSTIFY_OVERFLOW) ret += _(" justify-overflow"); // modifier - if (align & ALIGN_JUSTIFY_OVERFLOW) ret += _(" shrink-overflow"); + if (align & ALIGN_STRETCH_OVERFLOW) ret += _(" stretch-overflow"); if (align & ALIGN_STRETCH) ret += _(" stretch"); return ret.substr(1); } diff --git a/src/util/alignment.hpp b/src/util/alignment.hpp index f93975c6..e19a5391 100644 --- a/src/util/alignment.hpp +++ b/src/util/alignment.hpp @@ -30,7 +30,8 @@ enum Alignment , ALIGN_VERTICAL = ALIGN_TOP | ALIGN_MIDDLE | ALIGN_BOTTOM // modifiers , ALIGN_JUSTIFY_OVERFLOW = 0x1000 -, ALIGN_STRETCH = 0x2000 +, ALIGN_STRETCH_OVERFLOW = 0x2000 +, ALIGN_STRETCH = 0x4000 // common combinations , ALIGN_TOP_LEFT = ALIGN_TOP | ALIGN_LEFT , ALIGN_TOP_CENTER = ALIGN_TOP | ALIGN_CENTER diff --git a/src/util/rotation.cpp b/src/util/rotation.cpp index 9d57e555..e2f09076 100644 --- a/src/util/rotation.cpp +++ b/src/util/rotation.cpp @@ -18,11 +18,12 @@ int constrain_angle(int angle) { return (a / 90) * 90; // multiple of 90 } -Rotation::Rotation(int angle, const RealRect& rect, double zoom, bool is_internal) +Rotation::Rotation(int angle, const RealRect& rect, double zoom, double strectch, bool is_internal) : angle(constrain_angle(angle)) , size(rect.size()) , origin(rect.position()) - , zoom(zoom) + , zoomX(zoom * strectch) + , zoomY(zoom) { if (is_internal) { size = trNoNeg(size); @@ -41,9 +42,9 @@ RealPoint Rotation::tr(const RealPoint& p) const { } RealSize Rotation::tr(const RealSize& s) const { if (sideways()) { - return RealSize(negX(s.height), negY(s.width)) * zoom; + return RealSize(negX(s.height) * zoomY, negY(s.width) * zoomX); } else { - return RealSize(negX(s.width), negY(s.height)) * zoom; + return RealSize(negX(s.width) * zoomX, negY(s.height) * zoomY); } } RealRect Rotation::tr(const RealRect& r) const { @@ -52,13 +53,13 @@ RealRect Rotation::tr(const RealRect& r) const { RealSize Rotation::trNoNeg(const RealSize& s) const { if (sideways()) { - return RealSize(s.height, s.width) * zoom; + return RealSize(s.height * zoomY, s.width * zoomX); } else { - return RealSize(s.width, s.height) * zoom; + return RealSize(s.width * zoomX, s.height * zoomY); } } RealRect Rotation::trNoNeg(const RealRect& r) const { - RealSize s = (sideways() ? RealSize(r.height, r.width) : r.size()) * zoom; + RealSize s = trNoNeg(r.size()); return RealRect(tr(r.position()) - RealSize(revX()?s.width:0, revY()?s.height:0), s); } RealRect Rotation::trNoNegNoZoom(const RealRect& r) const { @@ -69,14 +70,14 @@ RealRect Rotation::trNoNegNoZoom(const RealRect& r) const { RealSize Rotation::trInv(const RealSize& s) const { if (sideways()) { - return RealSize(negY(s.height), negX(s.width)) / zoom; + return RealSize(negY(s.height) / zoomY, negX(s.width) / zoomX); } else { - return RealSize(negX(s.width), negY(s.height)) / zoom; + return RealSize(negX(s.width) / zoomX, negY(s.height) / zoomY); } } RealPoint Rotation::trInv(const RealPoint& p) const { - RealPoint p2 = (p - origin) / zoom; + RealPoint p2((p.x - origin.x) / zoomX, (p.y - origin.y) / zoomY); if (sideways()) { return RealPoint(negY(p2.y), negX(p2.x)); } else { @@ -86,9 +87,9 @@ RealPoint Rotation::trInv(const RealPoint& p) const { RealSize Rotation::trInvNoNeg(const RealSize& s) const { if (sideways()) { - return RealSize(s.height, s.width) / zoom; + return RealSize(s.height / zoomY, s.width / zoomX); } else { - return RealSize(s.width, s.height) / zoom; + return RealSize(s.width / zoomX, s.height / zoomY); } } @@ -101,7 +102,13 @@ Rotater::Rotater(Rotation& rot, const Rotation& by) // apply rotation RealRect new_ext = rot.trNoNeg(by.getExternalRect()); rot.angle = constrain_angle(rot.angle + by.angle); - rot.zoom *= by.zoom; + 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); } @@ -129,7 +136,7 @@ void RotatedDC::DrawText (const String& text, const RealPoint& pos, int blur_ra if (quality == QUALITY_AA) { RealRect r(pos, GetTextExtent(text)); RealRect r_ext = trNoNeg(r); - draw_resampled_text(dc, r_ext, revX(), revY(), angle, text, blur_radius, boldness); + draw_resampled_text(dc, r_ext, stretch(), revX(), revY(), angle, text, blur_radius, boldness); } else if (quality == QUALITY_SUB_PIXEL) { RealPoint p_ext = tr(pos)*text_scaling; double usx,usy; @@ -210,14 +217,14 @@ void RotatedDC::SetTextForeground(const Color& color) { dc.SetTextForeground(col void RotatedDC::SetLogicalFunction(int function) { dc.SetLogicalFunction(function); } void RotatedDC::SetFont(const wxFont& font) { - if (quality == QUALITY_LOW && zoom == 1) { + if (quality == QUALITY_LOW && zoomX == 1 && zoomY == 1) { dc.SetFont(font); } else { wxFont scaled = font; if (quality == QUALITY_LOW) { - scaled.SetPointSize((int) trS(font.GetPointSize())); + scaled.SetPointSize((int) trY(font.GetPointSize())); } else { - scaled.SetPointSize((int) (trS(font.GetPointSize()) * text_scaling)); + scaled.SetPointSize((int) (trY(font.GetPointSize()) * text_scaling)); } dc.SetFont(scaled); } @@ -244,9 +251,9 @@ RealSize RotatedDC::GetTextExtent(const String& text) const { h += h - charHeight; #endif if (quality == QUALITY_LOW) { - return RealSize(w,h) / zoom; + return RealSize(w / zoomX, h / zoomY); } else { - return RealSize(w,h) / zoom / text_scaling; + return RealSize(w / (zoomX * text_scaling), h / (zoomY * text_scaling)); } } double RotatedDC::GetCharHeight() const { @@ -259,9 +266,9 @@ double RotatedDC::GetCharHeight() const { h = 2 * extent - h; #endif if (quality == QUALITY_LOW) { - return h / zoom; + return h / zoomY; } else { - return h / zoom / text_scaling; + return h / (zoomY * text_scaling); } } diff --git a/src/util/rotation.hpp b/src/util/rotation.hpp index bc989553..4fb67fa7 100644 --- a/src/util/rotation.hpp +++ b/src/util/rotation.hpp @@ -28,10 +28,10 @@ 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, bool is_internal = false); + Rotation(int angle, const RealRect& rect, double zoom = 1.0, double strectch = 1.0, bool is_internal = false); /// Change the zoom factor - inline void setZoom(double z) { zoom = z; } + inline void setZoom(double z) { zoomX = zoomY = z; } /// Change the angle void setAngle(int a); /// The internal size @@ -44,7 +44,9 @@ class Rotation { RealRect getExternalRect() const; /// Translate a size or length - inline double trS(double s) const { return s * zoom; } + 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; } /// Translate a single point RealPoint tr(const RealPoint& p) const; @@ -62,9 +64,11 @@ class Rotation { RealRect trNoNegNoZoom(const RealRect& r) const; /// Translate a size or length back to internal 'coordinates' - inline double trInvS(double s) const { return s / zoom; } + inline double trInvS(double s) const { return s / zoomY; } + inline double trInvX(double s) const { return s / zoomX; } + inline double trInvY(double s) const { return s / zoomY; } /// Translate a size back to internal 'coordinates', doesn't rotate - inline RealSize trInvS(const RealSize& s) const { return RealSize(s.width / zoom, s.height / zoom); } + inline RealSize trInvS(const RealSize& s) const { return RealSize(s.width / zoomX, s.height / zoomY); } /// Translate a point back to internal coordinates RealPoint trInv(const RealPoint& p) const; @@ -73,11 +77,15 @@ class Rotation { /// 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 RealPoint origin; ///< tr(0,0) - double zoom; ///< Zoom factor, zoom = 2.0 means that 1 internal = 2 external + double zoomX; ///< Zoom factor, zoom = 2.0 means that 1 internal = 2 external + double zoomY; friend class Rotater;