风火轮 –动画效果:擦除、形状、轮子、随机线条、翻转远近、缩放、旋转、弹跳效果
今天再花了一个白天时间,把PPT动画的进入效果全部实现。
-
浮入效果
头文件
class TCbwAnimationEffect_Erase : public TCbwAnimationEffect { // 擦除
virtual void __fastcall BuildMaskMat(cv::Mat& destMat, cv::Mat& srcMat,
TRect displayRect);
public:
__fastcall TCbwAnimationEffect_Erase();
static TCbwAnimationEffect * Build();
};
class TCbwAnimationEffect_Shape : public TCbwAnimationEffect { // 形状
virtual void __fastcall BuildMaskMat(cv::Mat& destMat, cv::Mat& srcMat,
TRect displayRect);
public:
__fastcall TCbwAnimationEffect_Shape();
static TCbwAnimationEffect * Build();
};
class TCbwAnimationEffect_Wheel : public TCbwAnimationEffect { // 轮子
virtual void __fastcall BuildMaskMat(cv::Mat& destMat, cv::Mat& srcMat,
TRect displayRect);
public:
__fastcall TCbwAnimationEffect_Wheel();
static TCbwAnimationEffect * Build();
};
class TCbwAnimationEffect_RandomLine : public TCbwAnimationEffect { // 随机线
virtual void __fastcall BuildMaskMat(cv::Mat& destMat, cv::Mat& srcMat,
TRect displayRect);
BYTE * FOccurredLines;
public:
__fastcall TCbwAnimationEffect_RandomLine();
static TCbwAnimationEffect * Build();
};
class TCbwAnimationEffect_RotateToNear : public TCbwAnimationEffect_SameMask
{ // 翻转式由远及近
virtual void __fastcall BuildDisplayMat(cv::Mat& destMat, cv::Mat& srcMat,
TRect displayRect);
public:
__fastcall TCbwAnimationEffect_RotateToNear();
static TCbwAnimationEffect * Build();
};
class TCbwAnimationEffect_Zoom : public TCbwAnimationEffect_SameMask { // 缩放
virtual void __fastcall BuildDisplayMat(cv::Mat& destMat, cv::Mat& srcMat,
TRect displayRect);
public:
__fastcall TCbwAnimationEffect_Zoom();
static TCbwAnimationEffect * Build();
};
class TCbwAnimationEffect_Rotate : public TCbwAnimationEffect_SameMask { // 旋转
virtual void __fastcall BuildDisplayMat(cv::Mat& destMat, cv::Mat& srcMat,
TRect displayRect);
public:
__fastcall TCbwAnimationEffect_Rotate();
static TCbwAnimationEffect * Build();
};
class TCbwAnimationEffect_Bounce : public TCbwAnimationEffect { // 随机线
virtual TRect __fastcall BuildDisplayRect(OBJECTMAT * m);
public:
__fastcall TCbwAnimationEffect_Bounce();
static TCbwAnimationEffect * Build();
};
实现:
// ***************************** 擦除效果 **************************************
__fastcall TCbwAnimationEffect_Erase::TCbwAnimationEffect_Erase()
: TCbwAnimationEffect() {
EffectType = cetErase;
}
TCbwAnimationEffect * TCbwAnimationEffect_Erase::Build() {
return new TCbwAnimationEffect_Erase;
}
void __fastcall TCbwAnimationEffect_Erase::BuildMaskMat(cv::Mat& destMat,
cv::Mat& srcMat, TRect displayRect) {
int effectOptionType = MyOptionType.Items[1].CurrentValue * 2;
// 为了共用CbwEffectDirection类型
TRect wholeRect(0, 0, displayRect.right - displayRect.left,
displayRect.bottom - displayRect.top);
TRect partRect = wholeRect;
bool vertFlag =
(cedFromBottom == effectOptionType || cedFromTop == effectOptionType);
double delta = double(FCurrentIndex + 1) / FPeriodLength * (vertFlag ?
partRect.bottom : partRect.right);
if (cedFromBottom == effectOptionType) // 自底部
partRect.top = partRect.bottom - delta;
if (cedFromLeft == effectOptionType) // 自左侧
partRect.right = partRect.left + delta;
if (cedFromTop == effectOptionType) // 自顶部
partRect.bottom = partRect.top + delta;
if (cedFromRight == effectOptionType) // 自右侧
partRect.left = partRect.right - delta;
BYTE * pSrc = srcMat.data;
BYTE * pDst = destMat.data;
for (int row = 0; row < destMat.rows; ++row)
for (int col = 0; col < destMat.cols; ++col) {
bool hasValueFlag = (*pSrc++ != 0);
if (!hasValueFlag)
* pDst = 0;
int y = (row - partRect.top) * (partRect.bottom - row);
int x = (col - partRect.left) * (partRect.right - col);
bool inFlag = (y >= 0 && x >= 0);
*pDst++ = (inFlag ? 255 : 0);
}
}
// ***************************** 擦除效果 **************************************
// ***************************** 形状效果 **************************************
__fastcall TCbwAnimationEffect_Shape::TCbwAnimationEffect_Shape()
: TCbwAnimationEffect() {
EffectType = cetShape;
}
TCbwAnimationEffect * TCbwAnimationEffect_Shape::Build() {
return new TCbwAnimationEffect_Shape;
}
void __fastcall TCbwAnimationEffect_Shape::BuildMaskMat(cv::Mat& destMat,
cv::Mat& srcMat, TRect displayRect) {
int zoomType = MyOptionType.Items[1].CurrentValue; // 放大、缩小
int shapeType = MyOptionType.Items[2].CurrentValue; // 类型
TRect wholeRect(0, 0, displayRect.right - displayRect.left,
displayRect.bottom - displayRect.top);
double cx = wholeRect.right / 2.0, cy = wholeRect.bottom / 2.0;
double deltaX = double(FCurrentIndex + 1) / FPeriodLength * cx;
double deltaY = double(FCurrentIndex + 1) / FPeriodLength * cy;
double startX = deltaX, startY = deltaY;
double endX = wholeRect.right - deltaX, endY = wholeRect.bottom - deltaY;
if (zoomType == csdZoomOut) {
startX = cx - deltaX;
startY = cy - deltaY;
endX = cx + deltaX;
endY = cy + deltaY;
}
BYTE * pSrc = srcMat.data;
BYTE * pDst = destMat.data;
for (int row = 0; row < destMat.rows; ++row)
for (int col = 0; col < destMat.cols; ++col) {
bool hasValueFlag = (*pSrc++ != 0);
if (!hasValueFlag)
* pDst = 0;
bool inFlag = false;
double a = (cx - startX) * 1.5, b = (cy - startY) * 1.5;
if (shapeType == cstCircle) { // 圆
if (a > 0 && b > 0) {
double v = (row - cy) * (row - cy) / (b * b) +
(col - cx) * (col - cx) / (a * a);
inFlag = (v <= 1);
}
}
if (shapeType == cstRect) { // 方框
inFlag =
(fabs(cx - startX) >= fabs(cx - col) && fabs(cy - startY) >=
fabs(cy - row));
}
if (shapeType == cstDiamond) { // 菱形
if (a > 0 && b > 0) {
if (zoomType == csdZoomOut) {
a *= 2;
b *= 2;
}
bool lr1 = (col < (((-a) * (1 - (row - cy) / (b))) + cx));
bool lr2 = (col < (((-a) * (1 - (row - cy) / (-b))) + cx));
bool lr3 = (col < (((a) * (1 - (row - cy) / (-b))) + cx));
bool lr4 = (col < (((a) * (1 - (row - cy) / (b))) + cx));
inFlag = (!lr1 && !lr2 && lr3 && lr4);
}
}
if (shapeType == cstPlus) { // 加号
inFlag =
(fabs(cx - startX) > fabs(cx - col) || fabs(cy - startY) >
fabs(cy - row));
}
*pDst++ = (inFlag != (zoomType == csdZoomOut) ? 0 : 255);
}
}
// ***************************** 形状效果 **************************************
// ***************************** 轮子效果 **************************************
__fastcall TCbwAnimationEffect_Wheel::TCbwAnimationEffect_Wheel()
: TCbwAnimationEffect() {
EffectType = cetWheel;
}
TCbwAnimationEffect * TCbwAnimationEffect_Wheel::Build() {
return new TCbwAnimationEffect_Wheel;
}
void __fastcall TCbwAnimationEffect_Wheel::BuildMaskMat(cv::Mat& destMat,
cv::Mat& srcMat, TRect displayRect) {
bool clockwiseFlag = (MyOptionType.Items[1].CurrentValue == 0); // 方向
int pattern = MyOptionType.Items[2].CurrentValue + 1; // 轮辐图案
if (pattern == 5)
pattern = 8;
TRect wholeRect(0, 0, displayRect.right - displayRect.left,
displayRect.bottom - displayRect.top);
double cx = wholeRect.right / 2.0, cy = wholeRect.bottom / 2.0;
TCbwFloatPoint centerPoint(cx, cy);
double unitDegree = 360 / pattern;
double deltaDegree = double(FCurrentIndex + 1) / FPeriodLength * unitDegree;
BYTE * pSrc = srcMat.data;
BYTE * pDst = destMat.data;
for (int row = 0; row < destMat.rows; ++row)
for (int col = 0; col < destMat.cols; ++col) {
TCbwFloatPoint p(col, row);
double theta = p.ThetaToPoint(centerPoint);
if (clockwiseFlag)
theta = 360 - theta;
bool inFlag = false;
for (int i = 0; i < pattern; ++i) {
if (theta >= unitDegree * i && (theta - unitDegree * i) <=
deltaDegree)
inFlag = true;
}
*pDst++ = inFlag ? 255 : 0;
}
}
// ***************************** 轮子效果 **************************************
// ***************************** 随机线效果 **************************************
__fastcall TCbwAnimationEffect_RandomLine::TCbwAnimationEffect_RandomLine()
: TCbwAnimationEffect() {
EffectType = cetRandomLine;
FOccurredLines = NULL;
}
TCbwAnimationEffect * TCbwAnimationEffect_RandomLine::Build() {
return new TCbwAnimationEffect_RandomLine;
}
void __fastcall TCbwAnimationEffect_RandomLine::BuildMaskMat(cv::Mat& destMat,
cv::Mat& srcMat, TRect displayRect) {
bool horzFlag = (MyOptionType.Items[1].CurrentValue == 0); // 方向
TRect wholeRect(0, 0, displayRect.right - displayRect.left,
displayRect.bottom - displayRect.top);
int totalLineNumber = (horzFlag ? wholeRect.bottom : wholeRect.right);
int number = double(FCurrentIndex + 1) / FPeriodLength * totalLineNumber;
if (!FOccurredLines) {
FOccurredLines = new BYTE[totalLineNumber];
ZeroMemory(FOccurredLines, totalLineNumber);
}
int destNumber =
number -int(double(FCurrentIndex) / FPeriodLength * totalLineNumber);
BYTE * pSrc = srcMat.data;
BYTE * pDst = destMat.data;
vector<int>totalLines;
for (int i = 0; i < totalLineNumber; ++i)
totalLines.push_back(i);
while (destNumber-- > 0 && totalLines.size()) {
int n = random(totalLines.size());
while (FOccurredLines[totalLines[n]]) {
totalLines.erase(totalLines.begin() + n);
n = random(totalLines.size());
}
FOccurredLines[totalLines[n]] = 1;
totalLines.erase(totalLines.begin() + n);
}
for (int row = 0; row < destMat.rows; ++row)
for (int col = 0; col < destMat.cols; ++col) {
bool inFlag = (horzFlag ? FOccurredLines[row] :
FOccurredLines[col]);
*pDst++ = inFlag ? 255 : 0;
}
if (FCurrentIndex == FPeriodLength - 1) {
delete FOccurredLines;
FOccurredLines = NULL;
}
}
// ***************************** 随机线效果 **************************************
// ***************************** 翻转式由远及近效果 **************************************
__fastcall TCbwAnimationEffect_RotateToNear::TCbwAnimationEffect_RotateToNear()
: TCbwAnimationEffect_SameMask() {
EffectType = cetRotateToNear;
}
TCbwAnimationEffect * TCbwAnimationEffect_RotateToNear::Build() {
return new TCbwAnimationEffect_RotateToNear;
}
void __fastcall TCbwAnimationEffect_RotateToNear::BuildDisplayMat
(cv::Mat& destMat, cv::Mat& srcMat, TRect displayRect) {
bool clockwiseFlag = (MyOptionType.Items[1].CurrentValue == 0); // 顺时针
cv::Point2f center = cv::Point2f(srcMat.cols / 2, srcMat.rows / 2); // 旋转中心
double angle = -45 * (1-double(FCurrentIndex + 1) / FPeriodLength); // 旋转角度
if (clockwiseFlag)
angle *= -1;
double scale = 0.5 * (1+double(FCurrentIndex + 1) / FPeriodLength); // 缩放尺度
cv::Mat rotateMat = cv::getRotationMatrix2D(center, angle, scale);
cv::warpAffine(srcMat, destMat, rotateMat, srcMat.size());
}
// ***************************** 翻转式由远及近效果 **************************************
// ***************************** 缩放效果 **************************************
__fastcall TCbwAnimationEffect_Zoom::TCbwAnimationEffect_Zoom()
: TCbwAnimationEffect_SameMask() {
EffectType = cetZoomEffect;
}
TCbwAnimationEffect * TCbwAnimationEffect_Zoom::Build() {
return new TCbwAnimationEffect_Zoom;
}
void __fastcall TCbwAnimationEffect_Zoom::BuildDisplayMat(cv::Mat& destMat,
cv::Mat& srcMat, TRect displayRect) {
bool clockwiseFlag = (MyOptionType.Items[1].CurrentValue == 0); // 顺时针
cv::Point2f center = cv::Point2f(srcMat.cols / 2, srcMat.rows / 2); // 旋转中心
double scale = 0.5 * (1+double(FCurrentIndex + 1) / FPeriodLength); // 缩放尺度
cv::Mat rotateMat = cv::getRotationMatrix2D(center, 0, scale);
cv::warpAffine(srcMat, destMat, rotateMat, srcMat.size());
}
// ***************************** 缩放效果 **************************************
// ***************************** 旋转效果 **************************************
__fastcall TCbwAnimationEffect_Rotate::TCbwAnimationEffect_Rotate()
: TCbwAnimationEffect_SameMask() {
EffectType = cetRotateEffect;
}
TCbwAnimationEffect * TCbwAnimationEffect_Rotate::Build() {
return new TCbwAnimationEffect_Rotate;
}
void __fastcall TCbwAnimationEffect_Rotate::BuildDisplayMat(cv::Mat& destMat,
cv::Mat& srcMat, TRect displayRect) {
bool horzFlag = (MyOptionType.Items[1].CurrentValue == 0); // 方向
double periodLength = FPeriodLength / 2.0;
double value = (FCurrentIndex + 1) / periodLength;
int segment = value;
value -= int(value);
double scale = fabs(value - 0.5) * 2;
int cols = srcMat.cols * scale, rows = srcMat.rows;
if (!horzFlag) {
cols = srcMat.cols;
rows = srcMat.rows * scale;
}
if (cols == 0 || rows == 0)
return;
cv::Mat partMat = destMat(cv::Rect((destMat.cols - cols) / 2,
(destMat.rows - rows) / 2, cols, rows));
cv::Size dsize = cv::Size(cols, rows);
resize(srcMat, partMat, dsize);
if (value > 0.5 != (segment % 2))
flip(partMat, partMat, horzFlag ? 1 : 0);
}
// ***************************** 旋转效果 **************************************
// ***************************** 弹跳效果 **************************************
__fastcall TCbwAnimationEffect_Bounce::TCbwAnimationEffect_Bounce()
: TCbwAnimationEffect() {
EffectType = cetBounce;
}
TCbwAnimationEffect * TCbwAnimationEffect_Bounce::Build() {
return new TCbwAnimationEffect_Bounce;
}
TRect __fastcall TCbwAnimationEffect_Bounce::BuildDisplayRect(OBJECTMAT * m) {
double x = double(FCurrentIndex + 1) / FPeriodLength;
double v = sin((x - 1) * 3 * PI);
double y = fabs(200 * v / exp(0.3 * (x - 1)));
y = m->LeftTopPosition.y - y;
x = m->LeftTopPosition.x + (x - 1) * 500;
TRect result(x, y, x + m->Mat.cols, y + m->Mat.rows);
return result;
}
// ***************************** 弹跳效果 **************************************
配置:
图标
实现完成后,发现弹跳的效果没有达到预期。
先解决有问题,先完成,再完善。
本周按计划完成PPT动画效果框架设计与实现。年也过完了,下周把电子黑板的功能更上一层楼。