AGG第十八课 agg::trans_affine仿射变换

1 affine仿射变换概念

在几何上定义为两个向量空间之间的一个仿射变换或者仿射映射(来自拉丁语,affinis,"和。..相关")由一个线性变换接上一个平移组成。

2  agg::trans_affine成员函数说明

2.1 缩放

inline const trans_affine&trans_affine::scale(double x, double y)

参数一对x横坐标的缩放系数,参数二对y纵坐标的缩放系数

这里有一个问题:就是图形的缩放之后,并不是在原有的位置上,进行缩放,而是整体的缩放,比如最明显的是圆形,圆心的位置发生了改变,所以需要进行平移,恢复到以前的圆心。

2.2 旋转

inline const trans_affine&trans_affine::rotate(double a)

参数对图形进行旋转,旋转的圆心是坐标的原点(0,0),也就是显示界面的左上角,和一般的笛卡尔坐标不一样的地方,Y轴的纵坐标进行了翻转,Y轴向下逐渐增大。

应用注意事项:参数采用的是弧度的形式,至于弧度(radians)和角度(degrees)之间的区别,请参考其他的章节,不再赘述。所以该参数的范围是[-pi,pi].pi = 3.141592653.正值表示顺时针旋转,负值逆时针旋转,旋转的中心对称点是(0,0),切记!!很可能会旋转到界面之外。

Tips:角度转弧度agg::deg2rad(doubledegrees)

2.3 平移

inline const trans_affine&trans_affine::translate(double x, double y)

参数一,X轴平移量,参数二,Y轴平移量

3 关于仿射变换的数学知识

本文不打算描述trans_affine仿射变换的基本原理,其中的代码在agg_trans_affine.h文件中定义,涉及到的六个仿射变量如下:

double sx, shy, shx, sy, tx, ty;

可以搜索仿射变换的基本原理。

4 一些测试实例

4.1 旋转出界面

实例代码如下:

ras.reset();

agg::ellipse ell(400,400,20,70);

//坐标转换

agg::trans_affine mtx;

//mtx.scale(0.5,1); //x轴缩小到原来的一半

mtx.rotate(agg::deg2rad(30));//旋转30度

//mtx.translate(200,200);//X,Y坐标分别平移100

typedef agg::conv_transform<agg::ellipse> ell_ct_type;

ell_ct_type ctell(ell,mtx); //矩阵变换

ras.add_path(ctell);

agg::render_scanlines_aa_solid(ras,sl,renb,agg::rgba8(255,0,0));

ras.reset();

这是网上最经典的一个使用例子,但是并没有说明旋转是如何实现的,稍微修改了一下代码:

mtx.rotate(agg::deg2rad(60));//旋转60度

结果:发现界面上什么也没有,椭圆不见了!!

原因:顺时针旋转出界面。

4.2 通过滑动条查看旋转的过程

void RotateEclipse()

{

//关于agg::slider_ctrl<agg::rgba8>的基本使用,请参考其他的章节

int value = m_slider1.value();//取值

agg::rendering_buffer &rbuf = rbuf_window();

agg::pixfmt_bgr24 pixf(rbuf);

typedef agg::renderer_base<agg::pixfmt_bgr24> renderer_base_type;

renderer_base_type renb(pixf);

agg::rasterizer_scanline_aa<> ras;

agg::scanline_u8 sl;

ren_bas.clear(agg::rgba8(255,255,255));

agg::trans_affine mtx;

//mtx.scale(0.5,0.5); //x轴缩小到原来的一半

mtx.rotate(agg::deg2rad(value));//旋转30度

//mtx.translate(100 ,100);//X,Y坐标分别平移100

agg::ellipse ell(900,900,20,30);

typedef agg::conv_transform<agg::ellipse> ell_ct_type;

ell_ct_type ctell(ell,mtx); //矩阵变换

ras.reset();

ras.add_path(ctell);

agg::render_scanlines_aa_solid(ras,sl,renb,agg::rgba8(255,0,0));

agg::render_ctrl(ras, sl, renb, m_slider1);

}

5版本差异以及具体应用

1)AGG2.3版本

目前已经很难下载到,早期的项目有应用到,没有继续更新!!

如下代码对矩形进行缩放:

ras.reset();

agg::path_storage ps;

ps.move_to(30,30);

ps.line_to(50,30);

ps.line_to(50,50);

ps.line_to(30,50);

ps.line_to(30,30);

agg::trans_affine mtx;

//横坐标放大2倍,纵坐标放大3倍

mtx*= agg::trans_affine_scaling(2, 3);

//横坐标平移100,纵坐标平移300,正数向右,负数向左

mtx*=agg::trans_affine_translation(100,100);

typedefagg::conv_transform<agg::path_storage> ell_ct_type;

ell_ct_type ctell(ps,mtx); //矩阵变换

typedef agg::conv_stroke<ell_ct_type>ell_cc_cs_type;

ell_cc_cs_typecsccell(ctell);

ras.add_path(ctell);

2)AGG2.4/2.5版本

agg::trans_affine mtx;

mtx.scale(0.5,0.5); //x轴缩小到原来的一半

mtx.rotate(agg::deg2rad(40));//旋转30度

mtx.translate(100 ,100);//X,Y坐标分别平移100

typedefagg::conv_transform<agg::path_storage> ell_ct_type;

ell_ct_type ctell(ps,mtx); //矩阵变换

typedef agg::conv_stroke<ell_ct_type>ell_cc_cs_type;

ell_cc_cs_type csccell(ctell);

ras.add_path(csccell);

6 摘自agg_trans_affine.h的翻译

在笛卡尔坐标系中(Cartesian coordinates)仿射转换(affine transformation)是一种线性的转换(在一开始的时候就设定了)。她们可以自由的旋转(rotation),缩放(scaling),平移(translation)和剪切变换(skewing).经过任意的仿射变换,线段仍然是线段,她永远不可能编程一根曲线。

一言以蔽之,任何的矩阵变换都可以用一系列的离散变换实现。

原文如下:

//============================================================trans_affine

//

// See Implementation agg_trans_affine.cpp

//

// Affine transformation are lineartransformations in Cartesiancoordinates

// (strictly speaking not only inCartesian, but for the beginning wewill

// think so). They are rotation, scaling,translation and skewing.

// After any affine transformation a linesegment remains a line segment

// and it will never become a curve.

//

// There will be no math about matrixcalculations, since it has been

// described many times. Ask yourself avery simple question:

// "why do we need to understand anduse some matrix stuff insteadof just

// rotating, scaling and so on". Theanswers are:

//

// 1. Any combination of transformationscan be done by only 4multiplications

//   and 4 additions in floatingpoint.

// 2. One matrix transformation isequivalent to the number ofconsecutive

//   discrete transformations,i.e. the matrix "accumulates" alltransformations

//   in the order of theirsettings. Suppose we have 4 transformations:

//      * rotate by 30 degrees,

//      * scale X to 2.0,

//      * scale Y to 1.5,

//      * move to (100, 100).

//   The result will depend on theorder of these transformations,

//   and the advantage of matrixis that the sequence of discret calls:

//   rotate(30), scaleX(2.0),scaleY(1.5), move(100,100)

//   will have exactly the sameresult as the following matrixtransformations:

//

//   affine_matrix m;

//   m *= rotate_matrix(30);

//   m *= scaleX_matrix(2.0);

//   m *= scaleY_matrix(1.5);

//   m *= move_matrix(100,100);

//

//  m.transform_my_point_at_last(x, y);

//

// What is the good of it? In real life wewill set-up the matrix onlyonce

// and then transform many points, letalone the convenience to set any

// combination of transformations.

//

// So, how to use it? Very easy - literallyas it‘s shown above. Notquite,

// let us write a correct example:

//

// agg::trans_affine m;

// m *= agg::trans_affine_rotation(30.0 *3.1415926 / 180.0);

// m *= agg::trans_affine_scaling(2.0,1.5);

// m *=agg::trans_affine_translation(100.0, 100.0);

// m.transform(&x, &y);

//

// The affine matrix is all you need toperform any lineartransformation,

// but all transformations have originpoint (0,0). It means that we needto

// use 2 translations if we want to rotatesometing around (100,100):

//

// m *= agg::trans_affine_translation(-100.0,-100.0);         // move to (0,0)

// m *= agg::trans_affine_rotation(30.0 *3.1415926 / 180.0);  // rotate

// m *=agg::trans_affine_translation(100.0, 100.0);           // move back to (100,100)

//----------------------------------------------------------------------

时间: 2024-10-29 03:34:34

AGG第十八课 agg::trans_affine仿射变换的相关文章

AGG第二十八课 rasterizer的填充规则

AGG提供了很多额外的接口给SVG调用,因此很多的初学者像我,需要先学习SVG,然后了解接口的意义,才能够真正的掌握该接口,例如miter_join的含义. 1知识储备 字面上理解就是填充的规则,不就是图形的填充吗?哪有什么规则可言.对于单一的图形没有问题,如果是渲染圆环,两个环之间的区域填充颜色,该怎么办?这个时候就需要指定一种规则,一种填充的规则. AGG提供了两种算法来判断该点是否在填充区域内,如果该点在填充区域,然后填充该点.对于一个简单的无交叉的路径,是非常容易判断的.但是,对于一个复

AGG 第十九课 agg::bezier_arc

void DrawCurveOfBezierArc() { agg::rendering_buffer &rbuf = rbuf_window(); agg::pixfmt_bgr24 pixf(rbuf); typedef agg::renderer_base<agg::pixfmt_bgr24> renderer_base_type; renderer_base_type renb(pixf); typedef agg::renderer_scanline_aa_solid<

NeHe OpenGL教程 第三十八课:资源文件

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十八课:资源文件 从资源文件中载入图像: 如何把图像数据保存到*.exe程序中,使用Windows的资源文件吧,它既简单又实用. 欢迎来到NeHe教程第38课.离上节课的写作已经有些时日了,加上写了一整天的code,也许笔头已经

NeHe OpenGL教程 第二十八课:贝塞尔曲面

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( [email protected] ) 这篇教程旨在介绍贝塞尔曲面,希望有比我更

NeHe OpenGL教程 第十八课:二次几何体

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第十八课:二次几何体 二次几何体: 利用二次几何体,你可以很容易的创建球,圆盘,圆柱和圆锥. 二次曲面是一种画复合对象的方法,这种方法通常并不需要很多的三角形.我们将要使用第七课的代码.我们将要增加7个变量以及修改纹理以增加一些变化

斯坦福第十八课:应用实例:图片文字识别(Application Example: Photo OCR)

18.1  问题描述和流程图 18.2  滑动窗口 18.3  获取大量数据和人工数据 18.4  上限分析:哪部分管道的接下去做 18.1  问题描述和流程图 图像文字识别应用所作的事是,从一张给定的图片中识别文字.这比从一份扫描文档中 识别文字要复杂的多. 为了完成这样的工作,需要采取如下步骤: 为了完成这样的工作,需要采取如下步骤: 1. 文字侦测(Text detection)——将图片上的文字与其他环境对象分离开来 2. 字符切分(Character segmentation)——将文

AGG第二十六课 裁剪功能

AGG有四种类型的裁剪,分别工作在不同的层次 1. 基础渲染器Base Render 除非直接调用基础渲染器的绘制线段的方法,否则在一般情况下,都是在render_scanline的时候被调用,进行裁剪,这个时候已经进行了大量无用的工作.比如顶点源超出屏幕范围,在调用render_scanline函数之前,比如调用rasterizer对象的add_path函数,已经浪费大量的资源 2 光栅器rasterizer rasterizer主要应用于根据顶点源,生成线段的详细信息,这个时候调用裁剪,可以

AGG第二十二课 conv_contour函数auto_detect_orientation的字体应用

1 提供如下的代码结构渲染字体 agg::conv_transform<...> conv (path,matrix); agg::conv_curve<...> curve (conv); agg::conv_contour<...> contour(curve); curve.approximaltion_scale (scale); contour.auto_detect_orientation (true); contour.width (bold); 当bol

OpenGL教程翻译 第十八课 漫反射光(Diffuse Lighting)

OpenGL教程翻译 第十七课 环境光(Ambient Lighting) 原文地址:http://ogldev.atspace.co.uk/(源码请从原文主页下载) Background 环境光和漫反射光的主要不同是,漫反射光的计算需要依靠光线方向而环境光完全忽略了它!当只有环境光时整个场景被均等照亮.漫反射光会使物体面对光的部分比背对光的部分更加明亮. 此外漫反射光还增加了一点新的计算,光线的入射角决定了表面的亮度.通过下面的图片来演示这个概念: 让我们假设两条光线的强度是一样的,而唯一不一