|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tinbetween.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tcurves.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tstroke.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tpalette.h"
|
|
Toshihiro Shimizu |
890ddd |
//#include "tcolorstyles.h"
|
|
Toshihiro Shimizu |
890ddd |
//#include "tregion.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tmathutil.h"
|
|
Toshihiro Shimizu |
890ddd |
//#include "tstrokeutil.h"
|
|
Toshihiro Shimizu |
890ddd |
//#include "tsystem.h"
|
|
Toshihiro Shimizu |
890ddd |
#include <utility></utility>
|
|
Toshihiro Shimizu |
890ddd |
#include <limits></limits>
|
|
Toshihiro Shimizu |
890ddd |
#include <list></list>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "../tvectorimage/tvectorimageP.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//#include "tdebugmessage.h"
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double average(std::vector<double> &values, double range = 2.5)</double>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
UINT size = values.size();
|
|
Toshihiro Shimizu |
890ddd |
if (size == 0)
|
|
Toshihiro Shimizu |
890ddd |
return std::numeric_limits<double>::signaling_NaN();</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (size == 1)
|
|
Toshihiro Shimizu |
890ddd |
return values[0];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double sum = 0;
|
|
Toshihiro Shimizu |
890ddd |
UINT j = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (; j < size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
sum += values[j];
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double average = sum / size;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double variance = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
variance += (average - values[j]) * (average - values[j]);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
variance /= size;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double err;
|
|
Toshihiro Shimizu |
890ddd |
int acceptedNum = 0;
|
|
Toshihiro Shimizu |
890ddd |
sum = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
err = values[j] - average;
|
|
Toshihiro Shimizu |
890ddd |
err *= err;
|
|
Toshihiro Shimizu |
890ddd |
if (err <= range * variance) {
|
|
Toshihiro Shimizu |
890ddd |
sum += values[j];
|
|
Toshihiro Shimizu |
890ddd |
acceptedNum++;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
assert(acceptedNum > 0);
|
|
Toshihiro Shimizu |
890ddd |
return (acceptedNum > 0) ? sum / (double)acceptedNum : average;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double weightedAverage(std::vector<double> &values, std::vector<double> &weights, double range = 2.5)</double></double>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
UINT size = values.size();
|
|
Toshihiro Shimizu |
890ddd |
if (size == 0)
|
|
Toshihiro Shimizu |
890ddd |
return std::numeric_limits<double>::signaling_NaN();</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double sum = 0;
|
|
Toshihiro Shimizu |
890ddd |
double totalWeight = 0;
|
|
Toshihiro Shimizu |
890ddd |
UINT j = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (; j < size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
sum += weights[j] * values[j];
|
|
Toshihiro Shimizu |
890ddd |
totalWeight += weights[j];
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
assert(totalWeight > 0);
|
|
Toshihiro Shimizu |
890ddd |
if (totalWeight == 0)
|
|
Toshihiro Shimizu |
890ddd |
return std::numeric_limits<double>::signaling_NaN();</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double average = sum / totalWeight;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double variance = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
variance += weights[j] * (average - values[j]) * (average - values[j]);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
variance /= totalWeight;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double err;
|
|
Toshihiro Shimizu |
890ddd |
totalWeight = 0;
|
|
Toshihiro Shimizu |
890ddd |
sum = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
err = values[j] - average;
|
|
Toshihiro Shimizu |
890ddd |
err *= err;
|
|
Toshihiro Shimizu |
890ddd |
if (err <= range * variance) {
|
|
Toshihiro Shimizu |
890ddd |
sum += weights[j] * values[j];
|
|
Toshihiro Shimizu |
890ddd |
totalWeight += weights[j];
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
assert(totalWeight > 0);
|
|
Toshihiro Shimizu |
890ddd |
return (totalWeight != 0) ? sum / totalWeight : average;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
inline UINT angleNumber(const std::vector<std::pair<int, double="">> &corners, double angle)</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
UINT count = 0;
|
|
Toshihiro Shimizu |
890ddd |
UINT size = corners.size();
|
|
Toshihiro Shimizu |
890ddd |
for (UINT j = 0; j < size; j++)
|
|
Toshihiro Shimizu |
890ddd |
if (corners[j].second >= angle)
|
|
Toshihiro Shimizu |
890ddd |
count++;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return count;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
inline bool isTooComplex(UINT n1, UINT n2, UINT maxSubsetNumber = 100)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
UINT n, r;
|
|
Toshihiro Shimizu |
890ddd |
if (n1 > n2) {
|
|
Toshihiro Shimizu |
890ddd |
n = n1;
|
|
Toshihiro Shimizu |
890ddd |
r = n2;
|
|
Toshihiro Shimizu |
890ddd |
} else if (n1 < n2) {
|
|
Toshihiro Shimizu |
890ddd |
n = n2;
|
|
Toshihiro Shimizu |
890ddd |
r = n1;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
assert(!"equal angle number");
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (n - r < r)
|
|
Toshihiro Shimizu |
890ddd |
r = n - r;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
n*(n-1)* ...(n-r+1) < n^r that must be <= 2^(num bits of UINT)-1
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
s:=sizeof(UINT)*8
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if
|
|
Toshihiro Shimizu |
890ddd |
n <= 2^( (s-1)/r) =>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
log n <= (s-1)/r (the base of log is 2) =>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
r*log n <= s-1 =>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
log n^r <= log 2^(s-1) =>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
n^r <= 2^(s-1) < (2^s)-1
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
const UINT one = 1;
|
|
Toshihiro Shimizu |
890ddd |
if (n > (one << ((sizeof(UINT) * 8 - 1) / r)))
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
register UINT product1 = n; //product1 = n*(n-1)* ...(n-r+1)
|
|
Toshihiro Shimizu |
890ddd |
for (register UINT i = 1; i < r; i++)
|
|
Toshihiro Shimizu |
890ddd |
product1 *= --n;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
register UINT rFact = r;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while (r > 1)
|
|
Toshihiro Shimizu |
890ddd |
rFact *= --r;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return (product1 / rFact > maxSubsetNumber);
|
|
Toshihiro Shimizu |
890ddd |
//product1/rFact is number of combination
|
|
Toshihiro Shimizu |
890ddd |
// ( n )
|
|
Toshihiro Shimizu |
890ddd |
// ( r )
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void eraseSmallAngles(std::vector<std::pair<int, double="">> &corners, double angle)</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
std::vector<std::pair<int, double="">>::iterator it = corners.begin();</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while (it != corners.end()) {
|
|
Toshihiro Shimizu |
890ddd |
if ((*it).second < angle)
|
|
Toshihiro Shimizu |
890ddd |
it = corners.erase(it);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
++it;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
//output:
|
|
Toshihiro Shimizu |
890ddd |
// min is the minimum angle greater or equal to minDegree (i.e the minimum angle of the corners)
|
|
Toshihiro Shimizu |
890ddd |
// max is tha maximum angle greater or equal to minDegree
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void detectCorners(const TStroke *stroke, double minDegree,
|
|
Toshihiro Shimizu |
890ddd |
std::vector<std::pair<int, double="">> &corners, double &min, double &max)</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
const double minSin = fabs(sin(minDegree * TConsts::pi_180));
|
|
Toshihiro Shimizu |
890ddd |
double angle, vectorialProduct, metaCornerLen, partialLen;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT quadCount1 = stroke->getChunkCount();
|
|
Toshihiro Shimizu |
890ddd |
TPointD speed1, speed2;
|
|
Toshihiro Shimizu |
890ddd |
int j;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPointD tan1, tan2;
|
|
Toshihiro Shimizu |
890ddd |
min = 180;
|
|
Toshihiro Shimizu |
890ddd |
max = minDegree;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 1; j < (int)quadCount1; j++) {
|
|
Toshihiro Shimizu |
890ddd |
speed1 = stroke->getChunk(j - 1)->getSpeed(1);
|
|
Toshihiro Shimizu |
890ddd |
speed2 = stroke->getChunk(j)->getSpeed(0);
|
|
Toshihiro Shimizu |
890ddd |
if (!(speed1 == TPointD() || speed2 == TPointD())) {
|
|
Toshihiro Shimizu |
890ddd |
tan1 = normalize(speed1);
|
|
Toshihiro Shimizu |
890ddd |
tan2 = normalize(speed2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
vectorialProduct = fabs(cross(tan1, tan2));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (tan1 * tan2 < 0) {
|
|
Toshihiro Shimizu |
890ddd |
angle = 180 - asin(tcrop(vectorialProduct, -1.0, 1.0)) * TConsts::invOf_pi_180;
|
|
Toshihiro Shimizu |
890ddd |
corners.push_back(std::make_pair(j, angle));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (min > angle)
|
|
Toshihiro Shimizu |
890ddd |
min = angle;
|
|
Toshihiro Shimizu |
890ddd |
if (max < angle)
|
|
Toshihiro Shimizu |
890ddd |
max = angle;
|
|
Toshihiro Shimizu |
890ddd |
} else if (vectorialProduct >= minSin) {
|
|
Toshihiro Shimizu |
890ddd |
angle = asin(tcrop(vectorialProduct, -1.0, 1.0)) * TConsts::invOf_pi_180;
|
|
Toshihiro Shimizu |
890ddd |
corners.push_back(std::make_pair(j, angle));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (min > angle)
|
|
Toshihiro Shimizu |
890ddd |
min = angle;
|
|
Toshihiro Shimizu |
890ddd |
if (max < angle)
|
|
Toshihiro Shimizu |
890ddd |
max = angle;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
const double ratioLen = 2.5;
|
|
Toshihiro Shimizu |
890ddd |
const double ratioAngle = 0.2;
|
|
Toshihiro Shimizu |
890ddd |
std::vector<std::pair<int, double="">>::iterator it = corners.begin();</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 1; j < (int)quadCount1; j++) //"meta angoli" ( meta perche' derivabili)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (it != corners.end() && j == (*it).first) {
|
|
Toshihiro Shimizu |
890ddd |
++it;
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (j - 2 >= 0 && (corners.empty() || it == corners.begin() || j - 1 != (*(it - 1)).first) && j + 1 < (int)quadCount1 && (corners.empty() || it == corners.end() || j + 1 != (*it).first)) {
|
|
Toshihiro Shimizu |
890ddd |
speed1 = stroke->getChunk(j - 2)->getSpeed(1);
|
|
Toshihiro Shimizu |
890ddd |
speed2 = stroke->getChunk(j + 1)->getSpeed(0);
|
|
Toshihiro Shimizu |
890ddd |
if (!(speed1 == TPointD() || speed2 == TPointD())) {
|
|
Toshihiro Shimizu |
890ddd |
tan1 = normalize(speed1);
|
|
Toshihiro Shimizu |
890ddd |
tan2 = normalize(speed2);
|
|
Toshihiro Shimizu |
890ddd |
vectorialProduct = fabs(cross(tan1, tan2));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (tan1 * tan2 < 0) {
|
|
Toshihiro Shimizu |
890ddd |
angle = 180 - asin(tcrop(vectorialProduct, -1.0, 1.0)) * TConsts::invOf_pi_180;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
metaCornerLen = ratioLen * (stroke->getChunk(j - 1)->getLength() + stroke->getChunk(j)->getLength());
|
|
Toshihiro Shimizu |
890ddd |
partialLen = 0;
|
|
Toshihiro Shimizu |
890ddd |
bool goodAngle = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (int i = j - 3; i >= 0 && (corners.empty() || it == corners.begin() || i + 1 != (*(it - 1)).first); i--) {
|
|
Toshihiro Shimizu |
890ddd |
tan1 = stroke->getChunk(i)->getSpeed(1);
|
|
Toshihiro Shimizu |
890ddd |
if (tan1 == TPointD())
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
tan1 = normalize(tan1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tan2 = stroke->getChunk(i + 1)->getSpeed(1);
|
|
Toshihiro Shimizu |
890ddd |
if (tan2 == TPointD())
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
tan2 = normalize(tan2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
vectorialProduct = fabs(cross(tan1, tan2));
|
|
Toshihiro Shimizu |
890ddd |
double nearAngle = asin(tcrop(vectorialProduct, -1.0, 1.0)) * TConsts::invOf_pi_180;
|
|
Toshihiro Shimizu |
890ddd |
if (tan1 * tan2 < 0)
|
|
Toshihiro Shimizu |
890ddd |
nearAngle = 180 - nearAngle;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (nearAngle > ratioAngle * angle)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
partialLen += stroke->getChunk(i)->getLength();
|
|
Toshihiro Shimizu |
890ddd |
if (partialLen > metaCornerLen) {
|
|
Toshihiro Shimizu |
890ddd |
goodAngle = true;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (goodAngle) {
|
|
Toshihiro Shimizu |
890ddd |
partialLen = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = j + 2; i + 1 < (int)quadCount1 && (corners.empty() || it == corners.end() || i + 1 != (*it).first); i++) {
|
|
Toshihiro Shimizu |
890ddd |
tan1 = stroke->getChunk(i)->getSpeed(0);
|
|
Toshihiro Shimizu |
890ddd |
if (tan1 == TPointD())
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
tan1 = normalize(tan1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
tan2 = stroke->getChunk(i + 1)->getSpeed(0);
|
|
Toshihiro Shimizu |
890ddd |
if (tan2 == TPointD())
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
tan2 = normalize(tan2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
vectorialProduct = fabs(cross(tan1, tan2));
|
|
Toshihiro Shimizu |
890ddd |
double nearAngle = asin(tcrop(vectorialProduct, -1.0, 1.0)) * TConsts::invOf_pi_180;
|
|
Toshihiro Shimizu |
890ddd |
if (tan1 * tan2 < 0)
|
|
Toshihiro Shimizu |
890ddd |
nearAngle = 180 - nearAngle;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (nearAngle > 0.1 * angle)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
partialLen += stroke->getChunk(i)->getLength();
|
|
Toshihiro Shimizu |
890ddd |
if (partialLen > metaCornerLen) {
|
|
Toshihiro Shimizu |
890ddd |
goodAngle = true;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (goodAngle) {
|
|
Toshihiro Shimizu |
890ddd |
//l'angolo viene un po' declassato in quanto meta
|
|
Toshihiro Shimizu |
890ddd |
it = corners.insert(it, std::make_pair(j, angle * 0.7)) + 1;
|
|
Toshihiro Shimizu |
890ddd |
if (min > angle)
|
|
Toshihiro Shimizu |
890ddd |
min = angle;
|
|
Toshihiro Shimizu |
890ddd |
if (max < angle)
|
|
Toshihiro Shimizu |
890ddd |
max = angle;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double variance(std::vector<double> &values)</double>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
UINT size = values.size();
|
|
Toshihiro Shimizu |
890ddd |
if (size == 0)
|
|
Toshihiro Shimizu |
890ddd |
return std::numeric_limits<double>::signaling_NaN();</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double sum = 0;
|
|
Toshihiro Shimizu |
890ddd |
UINT j = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (; j < size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
sum += values[j];
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double average = sum / size;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double variance = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
variance += (average - values[j]) * (average - values[j]);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return variance / size;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void findBestSolution(const TStroke *stroke1, const TStroke *stroke2,
|
|
Toshihiro Shimizu |
890ddd |
std::pair<int, double=""> *partialAngles1, UINT partialAngles1Size,</int,>
|
|
Toshihiro Shimizu |
890ddd |
const std::vector<std::pair<int, double="">> &angles2,</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
UINT r, std::list<std::pair<int, double="">> &partialSolution,</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
double &bestValue,
|
|
Toshihiro Shimizu |
890ddd |
std::vector<int> &bestVector)</int>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
if (r == partialAngles1Size) {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT j;
|
|
Toshihiro Shimizu |
890ddd |
vector<std::pair<int, double="">> angles1;</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::list<std::pair<int, double="">>::iterator it = partialSolution.begin();</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (; it != partialSolution.end(); ++it) {
|
|
Toshihiro Shimizu |
890ddd |
angles1.push_back(*it);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < partialAngles1Size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
angles1.push_back(partialAngles1[j]);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT angles1Size = angles1.size();
|
|
Toshihiro Shimizu |
890ddd |
vector<double> rationAngles(angles1Size), ratioLength(angles1Size + 1);</double>
|
|
Toshihiro Shimizu |
890ddd |
vector<double> ratioX, ratioY;</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles1Size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
rationAngles[j] = fabs(angles1[j].second - angles2[j].second) / (angles1[j].second + angles2[j].second);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT firstQuad1 = 0;
|
|
Toshihiro Shimizu |
890ddd |
UINT firstQuad2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
UINT nextQuad1, nextQuad2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRectD bbox1 = stroke1->getBBox();
|
|
Toshihiro Shimizu |
890ddd |
TRectD bbox2 = stroke2->getBBox();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double app, div;
|
|
Toshihiro Shimizu |
890ddd |
double invTotalLen1 = stroke1->getLength();
|
|
Toshihiro Shimizu |
890ddd |
assert(invTotalLen1 > 0);
|
|
Toshihiro Shimizu |
890ddd |
invTotalLen1 = 1.0 / invTotalLen1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double invTotalLen2 = stroke2->getLength();
|
|
Toshihiro Shimizu |
890ddd |
assert(invTotalLen2 > 0);
|
|
Toshihiro Shimizu |
890ddd |
invTotalLen2 = 1.0 / invTotalLen2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j <= angles1Size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (j < angles1Size) {
|
|
Toshihiro Shimizu |
890ddd |
nextQuad1 = angles1[j].first;
|
|
Toshihiro Shimizu |
890ddd |
nextQuad2 = angles2[j].first;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
nextQuad1 = stroke1->getChunkCount();
|
|
Toshihiro Shimizu |
890ddd |
nextQuad2 = stroke2->getChunkCount();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ratioLength[j] = fabs(stroke1->getLengthAtControlPoint(nextQuad1 * 2) * invTotalLen1 - stroke2->getLengthAtControlPoint(nextQuad2 * 2) * invTotalLen2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPointD p1(stroke1->getChunk(nextQuad1 - 1)->getP2() -
|
|
Toshihiro Shimizu |
890ddd |
stroke1->getChunk(firstQuad1)->getP0());
|
|
Toshihiro Shimizu |
890ddd |
p1.x = fabs(p1.x);
|
|
Toshihiro Shimizu |
890ddd |
p1.y = fabs(p1.y);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPointD p2(stroke2->getChunk(nextQuad2 - 1)->getP2() -
|
|
Toshihiro Shimizu |
890ddd |
stroke2->getChunk(firstQuad2)->getP0());
|
|
Toshihiro Shimizu |
890ddd |
p2.x = fabs(p2.x);
|
|
Toshihiro Shimizu |
890ddd |
p2.y = fabs(p2.y);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
app = fabs(bbox1.getLx() * p2.x - bbox2.getLx() * p1.x);
|
|
Toshihiro Shimizu |
890ddd |
div = (bbox1.getLx() * p2.x + bbox2.getLx() * p1.x);
|
|
Toshihiro Shimizu |
890ddd |
if (div)
|
|
Toshihiro Shimizu |
890ddd |
ratioX.push_back(app / div);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
app = fabs(bbox1.getLy() * p2.y - bbox2.getLy() * p1.y);
|
|
Toshihiro Shimizu |
890ddd |
div = (bbox1.getLy() * p2.y + bbox2.getLy() * p1.y);
|
|
Toshihiro Shimizu |
890ddd |
if (div)
|
|
Toshihiro Shimizu |
890ddd |
ratioY.push_back(app / div);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
firstQuad1 = nextQuad1;
|
|
Toshihiro Shimizu |
890ddd |
firstQuad2 = nextQuad2;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double varAng, varX, varY, varLen;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
varX = average(ratioX);
|
|
Toshihiro Shimizu |
890ddd |
varY = average(ratioY);
|
|
Toshihiro Shimizu |
890ddd |
varLen = average(ratioLength);
|
|
Toshihiro Shimizu |
890ddd |
varAng = average(rationAngles);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double estimate = varX + varY + varAng + varLen;
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
#ifdef _DEBUG
|
|
Toshihiro Shimizu |
890ddd |
for(UINT dI=0; dI
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream() << angles1[dI].first<<" ";
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream() <<"estimate "<< estimate<<"=" ;
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (estimate < bestValue) {
|
|
Toshihiro Shimizu |
890ddd |
bestValue = estimate;
|
|
Toshihiro Shimizu |
890ddd |
if (bestVector.size() != angles1Size) {
|
|
Toshihiro Shimizu |
890ddd |
assert(!"bad size for bestVector");
|
|
Toshihiro Shimizu |
890ddd |
bestVector.resize(angles1Size);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles1Size; j++) {
|
|
Toshihiro Shimizu |
890ddd |
bestVector[j] = angles1[j].first;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (r == 1) {
|
|
Toshihiro Shimizu |
890ddd |
for (UINT i = 0; i < partialAngles1Size; i++) {
|
|
Toshihiro Shimizu |
890ddd |
findBestSolution(stroke1, stroke2,
|
|
Toshihiro Shimizu |
890ddd |
partialAngles1 + i, 1,
|
|
Toshihiro Shimizu |
890ddd |
angles2,
|
|
Toshihiro Shimizu |
890ddd |
1, partialSolution,
|
|
Toshihiro Shimizu |
890ddd |
bestValue,
|
|
Toshihiro Shimizu |
890ddd |
bestVector);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
partialSolution.push_back(partialAngles1[0]);
|
|
Toshihiro Shimizu |
890ddd |
findBestSolution(stroke1, stroke2,
|
|
Toshihiro Shimizu |
890ddd |
partialAngles1 + 1, partialAngles1Size - 1,
|
|
Toshihiro Shimizu |
890ddd |
angles2,
|
|
Toshihiro Shimizu |
890ddd |
r - 1, partialSolution,
|
|
Toshihiro Shimizu |
890ddd |
bestValue,
|
|
Toshihiro Shimizu |
890ddd |
bestVector);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
partialSolution.pop_back();
|
|
Toshihiro Shimizu |
890ddd |
findBestSolution(stroke1, stroke2,
|
|
Toshihiro Shimizu |
890ddd |
partialAngles1 + 1, partialAngles1Size - 1,
|
|
Toshihiro Shimizu |
890ddd |
angles2,
|
|
Toshihiro Shimizu |
890ddd |
r, partialSolution,
|
|
Toshihiro Shimizu |
890ddd |
bestValue,
|
|
Toshihiro Shimizu |
890ddd |
bestVector);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void findBestSolution(const TStroke *stroke1, const TStroke *stroke2,
|
|
Toshihiro Shimizu |
890ddd |
std::vector<std::pair<int, double="">> &angles1,</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
const std::vector<std::pair<int, double="">> &angles2,</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
double &bestValue,
|
|
Toshihiro Shimizu |
890ddd |
std::vector<int> &bestVector)</int>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
assert(angles1.size() > angles2.size());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
list<std::pair<int, double="">> partialSolution;</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
findBestSolution(stroke1, stroke2,
|
|
Toshihiro Shimizu |
890ddd |
&(angles1[0]), angles1.size(),
|
|
Toshihiro Shimizu |
890ddd |
angles2,
|
|
Toshihiro Shimizu |
890ddd |
angles2.size(), partialSolution,
|
|
Toshihiro Shimizu |
890ddd |
bestValue, bestVector);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void trivialSolution(const TStroke *stroke1, const TStroke *stroke2,
|
|
Toshihiro Shimizu |
890ddd |
const std::vector<std::pair<int, double="">> &angles1,</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
const std::vector<std::pair<int, double="">> &angles2,</std::pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
std::vector<int> &solution)</int>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
assert(angles1.size() > angles2.size());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT j;
|
|
Toshihiro Shimizu |
890ddd |
double subStrokeRatio2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double invTotalLen2 = stroke2->getLength();
|
|
Toshihiro Shimizu |
890ddd |
assert(invTotalLen2);
|
|
Toshihiro Shimizu |
890ddd |
invTotalLen2 = 1.0 / invTotalLen2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double invTotalLen1 = stroke1->getLength();
|
|
Toshihiro Shimizu |
890ddd |
assert(invTotalLen1 > 0);
|
|
Toshihiro Shimizu |
890ddd |
invTotalLen1 = 1.0 / invTotalLen1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (solution.size() != angles2.size()) {
|
|
Toshihiro Shimizu |
890ddd |
assert(!"bad size for solution");
|
|
Toshihiro Shimizu |
890ddd |
solution.resize(angles2.size());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int toBeErased = angles1.size() - angles2.size();
|
|
Toshihiro Shimizu |
890ddd |
UINT count = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double diff, ratio, oldRatio = 100;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
subStrokeRatio2 = stroke2->getLengthAtControlPoint(angles2[count].first * 2) * invTotalLen2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles1.size() && count < solution.size(); j++) {
|
|
Toshihiro Shimizu |
890ddd |
if (toBeErased == 0) {
|
|
Toshihiro Shimizu |
890ddd |
solution[count++] = angles1[j].first;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
ratio = stroke1->getLengthAtControlPoint(angles1[j].first * 2) * invTotalLen1;
|
|
Toshihiro Shimizu |
890ddd |
assert(ratio > 0 && ratio <= 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
diff = ratio - subStrokeRatio2;
|
|
Toshihiro Shimizu |
890ddd |
if (diff >= 0) {
|
|
Toshihiro Shimizu |
890ddd |
if (fabs(diff) < fabs(oldRatio - subStrokeRatio2)) {
|
|
Toshihiro Shimizu |
890ddd |
solution[count] = angles1[j].first;
|
|
Toshihiro Shimizu |
890ddd |
oldRatio = 100;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
assert(j > 0);
|
|
Toshihiro Shimizu |
890ddd |
solution[count] = angles1[j - 1].first;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
count++;
|
|
Toshihiro Shimizu |
890ddd |
if (angles2.size() < count)
|
|
Toshihiro Shimizu |
890ddd |
subStrokeRatio2 = stroke2->getLengthAtControlPoint(angles2[count].first * 2) * invTotalLen2;
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
subStrokeRatio2 = 1;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
toBeErased--;
|
|
Toshihiro Shimizu |
890ddd |
oldRatio = ratio;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
assert(count == solution.size());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TStroke *extract(const TStroke *source, UINT firstQuad, UINT lastQuad)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
UINT quadCount = source->getChunkCount();
|
|
Toshihiro Shimizu |
890ddd |
if (firstQuad >= quadCount) {
|
|
Toshihiro Shimizu |
890ddd |
assert(!"bad quadric index");
|
|
Toshihiro Shimizu |
890ddd |
firstQuad = quadCount - 1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (lastQuad < firstQuad) {
|
|
Toshihiro Shimizu |
890ddd |
assert(!"bad quadric index");
|
|
Toshihiro Shimizu |
890ddd |
lastQuad = firstQuad;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (lastQuad >= quadCount) {
|
|
Toshihiro Shimizu |
890ddd |
assert(!"bad quadric index");
|
|
Toshihiro Shimizu |
890ddd |
lastQuad = quadCount - 1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT cpIndex0 = firstQuad * 2;
|
|
Toshihiro Shimizu |
890ddd |
UINT cpIndex1 = lastQuad * 2 + 2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
vector<tthickpoint> points(cpIndex1 - cpIndex0 + 1);</tthickpoint>
|
|
Toshihiro Shimizu |
890ddd |
UINT count = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (UINT j = cpIndex0; j <= cpIndex1; j++) {
|
|
Toshihiro Shimizu |
890ddd |
points[count++] = source->getControlPoint(j);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return new TStroke(points);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void sample(const TStroke *stroke, int samplingSize, vector<tpointd> &sampledPoint)</tpointd>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
double samplingFrequency = 1.0 / (double)samplingSize;
|
|
Toshihiro Shimizu |
890ddd |
sampledPoint.resize(samplingSize);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double totalLen = stroke->getLength();
|
|
Toshihiro Shimizu |
890ddd |
double step = totalLen * samplingFrequency;
|
|
Toshihiro Shimizu |
890ddd |
double len = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (int p = 0; p < samplingSize - 1; p++) {
|
|
Toshihiro Shimizu |
890ddd |
sampledPoint[p] = stroke->getPointAtLength(len);
|
|
Toshihiro Shimizu |
890ddd |
len += step;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
sampledPoint.back() = stroke->getControlPoint(stroke->getControlPointCount() - 1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class TInbetween::Imp
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
//----------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
struct StrokeTransform {
|
|
Toshihiro Shimizu |
890ddd |
typedef enum {
|
|
Toshihiro Shimizu |
890ddd |
EQUAL,
|
|
Toshihiro Shimizu |
890ddd |
POINT,
|
|
Toshihiro Shimizu |
890ddd |
GENERAL
|
|
Toshihiro Shimizu |
890ddd |
} TransformationType;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPointD m_translate;
|
|
Toshihiro Shimizu |
890ddd |
TPointD m_rotationAndScaleCenter;
|
|
Toshihiro Shimizu |
890ddd |
double m_scaleX, m_scaleY, m_rotation;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TransformationType m_type;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//saved for optimization
|
|
Toshihiro Shimizu |
890ddd |
TAffine m_inverse;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
vector<int> m_firstStrokeCornerIndexes;</int>
|
|
Toshihiro Shimizu |
890ddd |
vector<int> m_secondStrokeCornerIndexes;</int>
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP m_firstImage, m_lastImage;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::vector<stroketransform> m_transformation;</stroketransform>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void computeTransformation();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void transferColor(const TVectorImageP &destination) const;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP tween(double t) const;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Imp(const TVectorImageP firstImage, const TVectorImageP lastImage)
|
|
Toshihiro Shimizu |
890ddd |
: m_firstImage(firstImage), m_lastImage(lastImage)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
computeTransformation();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TInbetween::TInbetween(const TVectorImageP firstImage, const TVectorImageP lastImage)
|
|
Toshihiro Shimizu |
890ddd |
: m_imp(new TInbetween::Imp(firstImage, lastImage))
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TInbetween::~TInbetween()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
delete m_imp;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TInbetween::Imp::computeTransformation()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
const UINT samplingPointNumber = 10;
|
|
Toshihiro Shimizu |
890ddd |
const UINT bboxSamplingWeight = samplingPointNumber / 2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
StrokeTransform transform;
|
|
Toshihiro Shimizu |
890ddd |
double cs, sn, totalLen1, totalLen2, constK, constQ, constB, constD, constA;
|
|
Toshihiro Shimizu |
890ddd |
UINT cpCount1, cpCount2;
|
|
Toshihiro Shimizu |
890ddd |
TPointD stroke1Centroid, stroke2Centroid, stroke1Begin, stroke2Begin, stroke1End, stroke2End, versor1, versor2;
|
|
Toshihiro Shimizu |
890ddd |
vector<tpointd> samplingPoint1(samplingPointNumber), samplingPoint2(samplingPointNumber);</tpointd>
|
|
Toshihiro Shimizu |
890ddd |
TStroke *stroke1, *stroke2;
|
|
Toshihiro Shimizu |
890ddd |
vector<double> ratioSampling, weigths, subStrokeXScaling, subStrokeYScaling;</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT strokeCount1 = m_firstImage->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
UINT strokeCount2 = m_lastImage->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
if (strokeCount1 > strokeCount2)
|
|
Toshihiro Shimizu |
890ddd |
strokeCount1 = strokeCount2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_transformation.clear();
|
|
Toshihiro Shimizu |
890ddd |
m_transformation.reserve(strokeCount1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
const int maxSubSetNum = (strokeCount1) ? 1000 / strokeCount1 : 1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT j, p;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (UINT i = 0; i < strokeCount1; i++) {
|
|
Toshihiro Shimizu |
890ddd |
stroke1 = m_firstImage->getStroke(i);
|
|
Toshihiro Shimizu |
890ddd |
stroke2 = m_lastImage->getStroke(i);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//check if the strokes are equal
|
|
Toshihiro Shimizu |
890ddd |
cpCount1 = stroke1->getControlPointCount();
|
|
Toshihiro Shimizu |
890ddd |
cpCount2 = stroke2->getControlPointCount();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.clear();
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.clear();
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate = TPointD();
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter = TPointD();
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleX = 0;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleY = 0;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotation = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool isEqual = true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (cpCount1 == cpCount2) {
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cpCount1 && isEqual; j++) {
|
|
Toshihiro Shimizu |
890ddd |
isEqual = (stroke1->getControlPoint(j) == stroke2->getControlPoint(j));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
isEqual = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (isEqual) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_type = StrokeTransform::EQUAL;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
totalLen1 = stroke1->getLength();
|
|
Toshihiro Shimizu |
890ddd |
totalLen2 = stroke2->getLength();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (totalLen1 == 0 || totalLen2 == 0) {
|
|
Toshihiro Shimizu |
890ddd |
if (totalLen1 == 0 && totalLen2 == 0) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_type = StrokeTransform::POINT;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_inverse = TAffine();
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.resize(2);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes[0] = 0;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes[1] = stroke1->getChunkCount();
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.resize(2);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes[0] = 0;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes[1] = stroke2->getChunkCount();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
const double startMinAngle = 30.0;
|
|
Toshihiro Shimizu |
890ddd |
vector<pair<int, double="">> angles1, angles2;</pair<int,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_type = StrokeTransform::GENERAL;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double minAngle, maxAngle;
|
|
Toshihiro Shimizu |
890ddd |
int minAngle1, maxAngle1, minAngle2, maxAngle2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
angles1.clear();
|
|
Toshihiro Shimizu |
890ddd |
angles2.clear();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
detectCorners(stroke1, startMinAngle, angles1, minAngle, maxAngle);
|
|
Toshihiro Shimizu |
890ddd |
minAngle1 = (int)minAngle;
|
|
Toshihiro Shimizu |
890ddd |
maxAngle1 = (int)maxAngle;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::getStream()<
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
detectCorners(stroke2, startMinAngle, angles2, minAngle, maxAngle);
|
|
Toshihiro Shimizu |
890ddd |
minAngle2 = (int)minAngle;
|
|
Toshihiro Shimizu |
890ddd |
maxAngle2 = (int)maxAngle;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (angles1.empty())
|
|
Toshihiro Shimizu |
890ddd |
angles2.clear();
|
|
Toshihiro Shimizu |
890ddd |
if (angles2.empty())
|
|
Toshihiro Shimizu |
890ddd |
angles1.clear();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
debugStream.open("c:\\temp\\inbetween.txt", ios_base::out);
|
|
Toshihiro Shimizu |
890ddd |
debugStream <<"num angoli 1: "<< angles1.size() << endl;
|
|
Toshihiro Shimizu |
890ddd |
debugStream <<"num angoli 2: "<< angles2.size() << endl;
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double bestValue = (std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (angles1.size() != angles2.size()) {
|
|
Toshihiro Shimizu |
890ddd |
bestValue = (std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (isTooComplex(angles1.size(), angles2.size(), maxSubSetNum)) {
|
|
Toshihiro Shimizu |
890ddd |
//debugStream <<"is too complex" << endl;
|
|
Toshihiro Shimizu |
890ddd |
int firstAngle = (int)((angles1.size() < angles2.size()) ? minAngle2 : minAngle1);
|
|
Toshihiro Shimizu |
890ddd |
int lastAngle = (int)((angles1.size() < angles2.size()) ? maxAngle1 : maxAngle2);
|
|
Toshihiro Shimizu |
890ddd |
int bestAngle = (int)startMinAngle;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if ((int)(angles1.size() + angles2.size()) < lastAngle - firstAngle + 1) {
|
|
Toshihiro Shimizu |
890ddd |
double tempAngle;
|
|
Toshihiro Shimizu |
890ddd |
vector<double> sortedAngles1, sortedAngles2;</double>
|
|
Toshihiro Shimizu |
890ddd |
sortedAngles1.reserve(angles1.size());
|
|
Toshihiro Shimizu |
890ddd |
sortedAngles2.reserve(angles2.size());
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles1.size(); j++) {
|
|
Toshihiro Shimizu |
890ddd |
tempAngle = angles1[j].second;
|
|
Toshihiro Shimizu |
890ddd |
if (tempAngle >= firstAngle && tempAngle <= lastAngle)
|
|
Toshihiro Shimizu |
890ddd |
sortedAngles1.push_back(tempAngle);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles2.size(); j++) {
|
|
Toshihiro Shimizu |
890ddd |
tempAngle = angles2[j].second;
|
|
Toshihiro Shimizu |
890ddd |
if (tempAngle >= firstAngle && tempAngle <= lastAngle)
|
|
Toshihiro Shimizu |
890ddd |
sortedAngles2.push_back(tempAngle);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
vector<double> sortedAngles(sortedAngles1.size() + sortedAngles2.size());</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::sort(sortedAngles1.begin(), sortedAngles1.end());
|
|
Toshihiro Shimizu |
890ddd |
std::sort(sortedAngles2.begin(), sortedAngles2.end());
|
|
Toshihiro Shimizu |
890ddd |
std::merge(sortedAngles1.begin(), sortedAngles1.end(), sortedAngles2.begin(), sortedAngles2.end(), sortedAngles.begin());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < sortedAngles.size(); j++) {
|
|
Toshihiro Shimizu |
890ddd |
int numAng1 = angleNumber(angles1, sortedAngles[j]);
|
|
Toshihiro Shimizu |
890ddd |
int numAng2 = angleNumber(angles2, sortedAngles[j]);
|
|
Toshihiro Shimizu |
890ddd |
double val = (numAng1 == numAng2) ? 0 : fabs((float)(numAng1 - numAng2)) / (numAng1 + numAng2);
|
|
Toshihiro Shimizu |
890ddd |
if (val < bestValue) {
|
|
Toshihiro Shimizu |
890ddd |
bestValue = val;
|
|
Toshihiro Shimizu |
890ddd |
bestAngle = (int)(sortedAngles[j]);
|
|
Toshihiro Shimizu |
890ddd |
if (bestValue == 0 || !isTooComplex(numAng1, numAng2, maxSubSetNum))
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
} else //-----------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
for (int angle = firstAngle; angle <= lastAngle; angle++) {
|
|
Toshihiro Shimizu |
890ddd |
int numAng1 = angleNumber(angles1, angle);
|
|
Toshihiro Shimizu |
890ddd |
int numAng2 = angleNumber(angles2, angle);
|
|
Toshihiro Shimizu |
890ddd |
double val = (numAng1 == numAng2) ? 0 : fabs((float)(numAng1 - numAng2)) / (numAng1 + numAng2);
|
|
Toshihiro Shimizu |
890ddd |
if (val < bestValue) {
|
|
Toshihiro Shimizu |
890ddd |
bestValue = val;
|
|
Toshihiro Shimizu |
890ddd |
bestAngle = angle;
|
|
Toshihiro Shimizu |
890ddd |
if (bestValue == 0 || !isTooComplex(numAng1, numAng2, maxSubSetNum))
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
eraseSmallAngles(angles1, bestAngle);
|
|
Toshihiro Shimizu |
890ddd |
eraseSmallAngles(angles2, bestAngle);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
debugStream <<"bestAngle: "<< bestAngle << endl;
|
|
Toshihiro Shimizu |
890ddd |
debugStream <<"num angoli 1: "<< angles1.size() << endl;
|
|
Toshihiro Shimizu |
890ddd |
debugStream <<"num angoli 2: "<< angles2.size() << endl;
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bestValue = (std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (angles1.size() == angles2.size()) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(0);
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles1.size(); j++)
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(angles1[j].first);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(stroke1->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(0);
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles2.size(); j++)
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(angles2[j].first);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(stroke2->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
if (isTooComplex(angles1.size(), angles2.size(), maxSubSetNum)) {
|
|
Toshihiro Shimizu |
890ddd |
if (angles1.size() > angles2.size()) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.resize(angles2.size());
|
|
Toshihiro Shimizu |
890ddd |
trivialSolution(stroke1, stroke2, angles1, angles2, transform.m_firstStrokeCornerIndexes);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.insert(transform.m_firstStrokeCornerIndexes.begin(), 0);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(stroke1->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(0);
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles2.size(); j++)
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(angles2[j].first);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(stroke2->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(0);
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles1.size(); j++)
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(angles1[j].first);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(stroke1->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.resize(angles1.size());
|
|
Toshihiro Shimizu |
890ddd |
trivialSolution(stroke2, stroke1, angles2, angles1, transform.m_secondStrokeCornerIndexes);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.insert(transform.m_secondStrokeCornerIndexes.begin(), 0);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(stroke2->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
if (angles1.size() > angles2.size()) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.resize(angles2.size());
|
|
Toshihiro Shimizu |
890ddd |
findBestSolution(stroke1, stroke2, angles1, angles2, bestValue, transform.m_firstStrokeCornerIndexes);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.insert(transform.m_firstStrokeCornerIndexes.begin(), 0);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(stroke1->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(0);
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles2.size(); j++)
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(angles2[j].first);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(stroke2->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(0);
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles1.size(); j++)
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(angles1[j].first);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(stroke1->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.resize(angles1.size());
|
|
Toshihiro Shimizu |
890ddd |
findBestSolution(stroke2, stroke1, angles2, angles1, bestValue, transform.m_secondStrokeCornerIndexes);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.insert(transform.m_secondStrokeCornerIndexes.begin(), 0);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(stroke2->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(0);
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles1.size(); j++)
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(angles1[j].first);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_firstStrokeCornerIndexes.push_back(stroke1->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(0);
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < angles2.size(); j++)
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(angles2[j].first);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_secondStrokeCornerIndexes.push_back(stroke2->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT cornerSize = transform.m_firstStrokeCornerIndexes.size();
|
|
Toshihiro Shimizu |
890ddd |
assert(cornerSize == transform.m_secondStrokeCornerIndexes.size());
|
|
Toshihiro Shimizu |
890ddd |
assert(cornerSize >= 2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double totalRadRotation = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TStroke *subStroke1 = 0;
|
|
Toshihiro Shimizu |
890ddd |
TStroke *subStroke2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
stroke1Centroid = stroke1->getCentroid();
|
|
Toshihiro Shimizu |
890ddd |
stroke2Centroid = stroke2->getCentroid();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#ifdef _DEBUG
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_firstStrokeCornerIndexes[0] == 0);
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_secondStrokeCornerIndexes[0] == 0);
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_firstStrokeCornerIndexes[cornerSize - 1] == stroke1->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_secondStrokeCornerIndexes[cornerSize - 1] == stroke2->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize - 1; j++) {
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_firstStrokeCornerIndexes[j] < transform.m_firstStrokeCornerIndexes[j + 1]);
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_secondStrokeCornerIndexes[j] < transform.m_secondStrokeCornerIndexes[j + 1]);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_firstStrokeCornerIndexes[j] < stroke1->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_secondStrokeCornerIndexes[j] < stroke2->getChunkCount());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize - 1; j++) {
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// sampling
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
subStroke1 = extract(stroke1, transform.m_firstStrokeCornerIndexes[j], transform.m_firstStrokeCornerIndexes[j + 1] - 1);
|
|
Toshihiro Shimizu |
890ddd |
sample(subStroke1, samplingPointNumber, samplingPoint1);
|
|
Toshihiro Shimizu |
890ddd |
subStroke2 = extract(stroke2, transform.m_secondStrokeCornerIndexes[j], transform.m_secondStrokeCornerIndexes[j + 1] - 1);
|
|
Toshihiro Shimizu |
890ddd |
sample(subStroke2, samplingPointNumber, samplingPoint2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// compute Rotation
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.clear();
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.reserve(samplingPointNumber);
|
|
Toshihiro Shimizu |
890ddd |
weigths.clear();
|
|
Toshihiro Shimizu |
890ddd |
weigths.reserve(samplingPointNumber);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPointD pOld, pNew;
|
|
Toshihiro Shimizu |
890ddd |
// double totalW=0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (p = 0; p < samplingPointNumber; p++) {
|
|
Toshihiro Shimizu |
890ddd |
pOld = samplingPoint1[p];
|
|
Toshihiro Shimizu |
890ddd |
pNew = samplingPoint2[p];
|
|
Toshihiro Shimizu |
890ddd |
if (pOld == stroke1Centroid)
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
if (pNew == stroke2Centroid)
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
versor1 = normalize(pOld - stroke1Centroid);
|
|
Toshihiro Shimizu |
890ddd |
versor2 = normalize(pNew - stroke2Centroid);
|
|
Toshihiro Shimizu |
890ddd |
weigths.push_back(tdistance(pOld, stroke1Centroid) + tdistance(pNew, stroke2Centroid));
|
|
Toshihiro Shimizu |
890ddd |
cs = versor1 * versor2;
|
|
Toshihiro Shimizu |
890ddd |
sn = cross(versor1, versor2);
|
|
Toshihiro Shimizu |
890ddd |
double v = atan2(sn, cs);
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.push_back(v);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
delete subStroke1;
|
|
Toshihiro Shimizu |
890ddd |
delete subStroke2;
|
|
Toshihiro Shimizu |
890ddd |
subStroke1 = 0;
|
|
Toshihiro Shimizu |
890ddd |
subStroke2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double radRotation = weightedAverage(ratioSampling, weigths);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
totalRadRotation += radRotation;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
totalRadRotation /= (cornerSize - 1);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotation = TConsts::invOf_pi_180 * totalRadRotation;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (isAlmostZero(transform.m_rotation, 2)) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotation = 0.0;
|
|
Toshihiro Shimizu |
890ddd |
totalRadRotation = 0.0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#ifdef _DEBUG
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::getStream()<<"rotation "<< transform.m_rotation;
|
|
Toshihiro Shimizu |
890ddd |
// TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// compute Scale
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (transform.m_rotation == 0.0) {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
subStrokeXScaling.clear();
|
|
Toshihiro Shimizu |
890ddd |
subStrokeXScaling.reserve(cornerSize - 1);
|
|
Toshihiro Shimizu |
890ddd |
subStrokeYScaling.clear();
|
|
Toshihiro Shimizu |
890ddd |
subStrokeYScaling.reserve(cornerSize - 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize - 1; j++) {
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// sampling
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
subStroke1 = extract(stroke1, transform.m_firstStrokeCornerIndexes[j], transform.m_firstStrokeCornerIndexes[j + 1] - 1);
|
|
Toshihiro Shimizu |
890ddd |
sample(subStroke1, samplingPointNumber, samplingPoint1);
|
|
Toshihiro Shimizu |
890ddd |
subStroke2 = extract(stroke2, transform.m_secondStrokeCornerIndexes[j], transform.m_secondStrokeCornerIndexes[j + 1] - 1);
|
|
Toshihiro Shimizu |
890ddd |
sample(subStroke2, samplingPointNumber, samplingPoint2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// compute X Scale
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.clear();
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.reserve(samplingPointNumber + bboxSamplingWeight);
|
|
Toshihiro Shimizu |
890ddd |
double appX, appY;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPointD appPoint;
|
|
Toshihiro Shimizu |
890ddd |
double bboxXMin, bboxYMin, bboxXMax, bboxYMax;
|
|
Toshihiro Shimizu |
890ddd |
bboxXMin = bboxYMin = (std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
bboxXMax = bboxYMax = -(std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
int h;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (h = 0; h < subStroke1->getControlPointCount(); ++h) {
|
|
Toshihiro Shimizu |
890ddd |
appPoint = subStroke1->getControlPoint(h);
|
|
Toshihiro Shimizu |
890ddd |
if (appPoint.x < bboxXMin)
|
|
Toshihiro Shimizu |
890ddd |
bboxXMin = appPoint.x;
|
|
Toshihiro Shimizu |
890ddd |
if (appPoint.x > bboxXMax)
|
|
Toshihiro Shimizu |
890ddd |
bboxXMax = appPoint.x;
|
|
Toshihiro Shimizu |
890ddd |
if (appPoint.y < bboxYMin)
|
|
Toshihiro Shimizu |
890ddd |
bboxYMin = appPoint.y;
|
|
Toshihiro Shimizu |
890ddd |
if (appPoint.y > bboxYMax)
|
|
Toshihiro Shimizu |
890ddd |
bboxYMax = appPoint.y;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
appX = bboxXMax - bboxXMin;
|
|
Toshihiro Shimizu |
890ddd |
appY = bboxYMax - bboxYMin;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (appX) {
|
|
Toshihiro Shimizu |
890ddd |
bboxXMin = (std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
bboxXMax = -(std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
for (h = 0; h < subStroke2->getControlPointCount(); ++h) {
|
|
Toshihiro Shimizu |
890ddd |
appPoint = subStroke2->getControlPoint(h);
|
|
Toshihiro Shimizu |
890ddd |
if (appPoint.x < bboxXMin)
|
|
Toshihiro Shimizu |
890ddd |
bboxXMin = appPoint.x;
|
|
Toshihiro Shimizu |
890ddd |
if (appPoint.x > bboxXMax)
|
|
Toshihiro Shimizu |
890ddd |
bboxXMax = appPoint.x;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
appX = (isAlmostZero(appX, 1e-01)) ? -1 : (bboxXMax - bboxXMin) / appX;
|
|
Toshihiro Shimizu |
890ddd |
for (UINT tms = 0; tms < bboxSamplingWeight && appX >= 0; tms++)
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.push_back(appX);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (p = 0; p < samplingPointNumber; p++) {
|
|
Toshihiro Shimizu |
890ddd |
appX = fabs(samplingPoint1[p].x - stroke1Centroid.x);
|
|
Toshihiro Shimizu |
890ddd |
if (appX)
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.push_back(fabs(samplingPoint2[p].x - stroke2Centroid.x) / appX);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!ratioSampling.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
subStrokeXScaling.push_back(average(ratioSampling));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// compute Y Scale
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.clear();
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.reserve(samplingPointNumber + bboxSamplingWeight);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (appY) {
|
|
Toshihiro Shimizu |
890ddd |
bboxYMin = (std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
bboxYMax = -(std::numeric_limits<double>::max)();</double>
|
|
Toshihiro Shimizu |
890ddd |
for (h = 0; h < subStroke2->getControlPointCount(); ++h) {
|
|
Toshihiro Shimizu |
890ddd |
appPoint = subStroke2->getControlPoint(h);
|
|
Toshihiro Shimizu |
890ddd |
if (appPoint.y < bboxYMin)
|
|
Toshihiro Shimizu |
890ddd |
bboxYMin = appPoint.y;
|
|
Toshihiro Shimizu |
890ddd |
if (appPoint.y > bboxYMax)
|
|
Toshihiro Shimizu |
890ddd |
bboxYMax = appPoint.y;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
appY = (isAlmostZero(appY, 1e-01)) ? -1 : (bboxYMax - bboxYMin) / appY;
|
|
Toshihiro Shimizu |
890ddd |
for (UINT tms = 0; tms < bboxSamplingWeight && appY >= 0; tms++)
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.push_back(appY);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (p = 0; p < samplingPointNumber; p++) {
|
|
Toshihiro Shimizu |
890ddd |
appY = fabs(samplingPoint1[p].y - stroke1Centroid.y);
|
|
Toshihiro Shimizu |
890ddd |
if (appY)
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.push_back(fabs(samplingPoint2[p].y - stroke2Centroid.y) / appY);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!ratioSampling.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
subStrokeYScaling.push_back(average(ratioSampling));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
delete subStroke1;
|
|
Toshihiro Shimizu |
890ddd |
delete subStroke2;
|
|
Toshihiro Shimizu |
890ddd |
subStroke1 = 0;
|
|
Toshihiro Shimizu |
890ddd |
subStroke2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (subStrokeXScaling.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleX = 1.0;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleX = average(subStrokeXScaling);
|
|
Toshihiro Shimizu |
890ddd |
if (isAlmostZero(transform.m_scaleX - 1.0))
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleX = 1.0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (subStrokeYScaling.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleY = 1.0;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleY = average(subStrokeYScaling);
|
|
Toshihiro Shimizu |
890ddd |
if (isAlmostZero(transform.m_scaleY - 1.0))
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleY = 1.0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
#ifdef _DEBUG
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream()<<"x scale "<< transform.m_scaleX ;
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream()<<"y scale "<< transform.m_scaleY ;
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
subStrokeXScaling.clear();
|
|
Toshihiro Shimizu |
890ddd |
subStrokeXScaling.reserve(cornerSize - 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize - 1; j++) {
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// sampling
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
subStroke1 = extract(stroke1, transform.m_firstStrokeCornerIndexes[j], transform.m_firstStrokeCornerIndexes[j + 1] - 1);
|
|
Toshihiro Shimizu |
890ddd |
sample(subStroke1, samplingPointNumber, samplingPoint1);
|
|
Toshihiro Shimizu |
890ddd |
subStroke2 = extract(stroke2, transform.m_secondStrokeCornerIndexes[j], transform.m_secondStrokeCornerIndexes[j + 1] - 1);
|
|
Toshihiro Shimizu |
890ddd |
sample(subStroke2, samplingPointNumber, samplingPoint2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// compute Scale
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.clear();
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.reserve(samplingPointNumber + bboxSamplingWeight);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRectD bbox1 = subStroke1->getBBox();
|
|
Toshihiro Shimizu |
890ddd |
double app = tdistance2(bbox1.getP00(), bbox1.getP11());
|
|
Toshihiro Shimizu |
890ddd |
if (app) {
|
|
Toshihiro Shimizu |
890ddd |
TRectD bbox2 = TRotation(transform.m_rotation).inv() * subStroke2->getBBox();
|
|
Toshihiro Shimizu |
890ddd |
app = sqrt(tdistance2(bbox2.getP00(), bbox2.getP11()) / app);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (UINT tms = 0; tms < bboxSamplingWeight; tms++)
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.push_back(app);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double app;
|
|
Toshihiro Shimizu |
890ddd |
for (p = 0; p < samplingPointNumber; p++) {
|
|
Toshihiro Shimizu |
890ddd |
app = tdistance(samplingPoint1[p], stroke1Centroid);
|
|
Toshihiro Shimizu |
890ddd |
if (app) {
|
|
Toshihiro Shimizu |
890ddd |
ratioSampling.push_back(tdistance(samplingPoint2[p], stroke2Centroid) / app);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (!ratioSampling.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
subStrokeXScaling.push_back(average(ratioSampling));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
delete subStroke1;
|
|
Toshihiro Shimizu |
890ddd |
delete subStroke2;
|
|
Toshihiro Shimizu |
890ddd |
subStroke1 = 0;
|
|
Toshihiro Shimizu |
890ddd |
subStroke2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (subStrokeXScaling.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleX = transform.m_scaleY = 1.0;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleX = transform.m_scaleY = average(subStrokeXScaling);
|
|
Toshihiro Shimizu |
890ddd |
if (isAlmostZero(transform.m_scaleX - 1.0, 0.00001))
|
|
Toshihiro Shimizu |
890ddd |
transform.m_scaleX = transform.m_scaleY = 1.0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
#ifdef _DEBUG
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::getStream()<<"scale "<< transform.m_scaleX ;
|
|
Toshihiro Shimizu |
890ddd |
TDebugMessage::flush();
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
///////////////////////////////////////// compute centre of Rotation and Scaling
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
vector<tpointd> vpOld(cornerSize), vpNew(cornerSize);</tpointd>
|
|
Toshihiro Shimizu |
890ddd |
TPointD pOld, pNew;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize - 1; j++) {
|
|
Toshihiro Shimizu |
890ddd |
vpOld[j] = stroke1->getChunk(transform.m_firstStrokeCornerIndexes[j])->getP0();
|
|
Toshihiro Shimizu |
890ddd |
vpNew[j] = stroke2->getChunk(transform.m_secondStrokeCornerIndexes[j])->getP0();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
vpOld[j] = stroke1->getControlPoint(stroke1->getControlPointCount());
|
|
Toshihiro Shimizu |
890ddd |
vpNew[j] = stroke2->getControlPoint(stroke2->getControlPointCount());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (transform.m_rotation == 0.0) {
|
|
Toshihiro Shimizu |
890ddd |
if (transform.m_scaleX == 1.0 && transform.m_scaleY == 1.0) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate = stroke2Centroid - stroke1Centroid;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter = TPointD();
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
if (transform.m_scaleX == 1.0) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.x = 0;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.x = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize; j++) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.x += vpNew[j].x - vpOld[j].x;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.x = transform.m_translate.x / cornerSize;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.x = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize; j++) {
|
|
Toshihiro Shimizu |
890ddd |
pOld = vpOld[j];
|
|
Toshihiro Shimizu |
890ddd |
pNew = vpNew[j];
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.x += (transform.m_scaleX * pOld.x - pNew.x) / (transform.m_scaleX - 1.0);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.x = transform.m_rotationAndScaleCenter.x / cornerSize;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.x = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (transform.m_scaleY == 1.0) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.y = 0;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.y = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize; j++) {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.y += vpNew[j].y - vpOld[j].y;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.y = transform.m_translate.y / cornerSize;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.y = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize; j++) {
|
|
Toshihiro Shimizu |
890ddd |
pOld = vpOld[j];
|
|
Toshihiro Shimizu |
890ddd |
pNew = vpNew[j];
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.y += (transform.m_scaleY * pOld.y - pNew.y) / (transform.m_scaleY - 1.0);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.y = transform.m_rotationAndScaleCenter.y / cornerSize;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.y = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
assert(transform.m_scaleX = transform.m_scaleY);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
cs = transform.m_scaleX * cos(totalRadRotation);
|
|
Toshihiro Shimizu |
890ddd |
sn = transform.m_scaleX * sin(totalRadRotation);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// scelgo punti da usare come vincolo, per ottenere la translazione, dato un centro di rotazione
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// dato il punto pOld e pNew si calcola analiticamnete il punto di rotazione e scala
|
|
Toshihiro Shimizu |
890ddd |
// che minimizza la traslazione aggiuntiva e la traslazione stessa
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize; j++) {
|
|
Toshihiro Shimizu |
890ddd |
pOld = vpOld[j];
|
|
Toshihiro Shimizu |
890ddd |
pNew = vpNew[j];
|
|
Toshihiro Shimizu |
890ddd |
constK = pNew.x - cs * pOld.x + sn * pOld.y;
|
|
Toshihiro Shimizu |
890ddd |
constQ = pNew.y - sn * pOld.x - cs * pOld.y;
|
|
Toshihiro Shimizu |
890ddd |
constB = 2 * (constK * (cs - 1.) + sn * constQ);
|
|
Toshihiro Shimizu |
890ddd |
constD = 2 * (constQ * (cs - 1.) - sn * constK);
|
|
Toshihiro Shimizu |
890ddd |
constA = transform.m_scaleX * transform.m_scaleX + 1 - 2 * cs;
|
|
Toshihiro Shimizu |
890ddd |
assert(constA > 0);
|
|
Toshihiro Shimizu |
890ddd |
constA = 1.0 / (2 * constA);
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.x += -constB * constA;
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter.y += -constD * constA;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_rotationAndScaleCenter = transform.m_rotationAndScaleCenter * (1.0 / (double)cornerSize);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.x = (cs - 1.0) * transform.m_rotationAndScaleCenter.x - sn * transform.m_rotationAndScaleCenter.y + constK;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_translate.y = sn * transform.m_rotationAndScaleCenter.x + (cs - 1.0) * transform.m_rotationAndScaleCenter.y + constQ;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/////////////////////////////////////////
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
transform.m_inverse = (TTranslation(transform.m_translate) *
|
|
Toshihiro Shimizu |
890ddd |
TScale(transform.m_rotationAndScaleCenter, transform.m_scaleX, transform.m_scaleY) *
|
|
Toshihiro Shimizu |
890ddd |
TRotation(transform.m_rotationAndScaleCenter, transform.m_rotation))
|
|
Toshihiro Shimizu |
890ddd |
.inv();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//debugStream.close();
|
|
Toshihiro Shimizu |
890ddd |
} // end if !isPoint
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
} // end if !isEqual
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_transformation.push_back(transform);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
} // end for each stroke
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP TInbetween::Imp::tween(double t) const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
const double step = 5.0;
|
|
Toshihiro Shimizu |
890ddd |
const double interpolateError = 1.0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP vi = new TVectorImage;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT strokeCount1 = m_firstImage->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
UINT strokeCount2 = m_lastImage->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
vi->setPalette(m_firstImage->getPalette());
|
|
Toshihiro Shimizu |
890ddd |
if (strokeCount1 > strokeCount2)
|
|
Toshihiro Shimizu |
890ddd |
strokeCount1 = strokeCount2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
assert(m_transformation.size() == strokeCount1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double totalLen1, totalLen2, len1, len2, step1, step2;
|
|
Toshihiro Shimizu |
890ddd |
vector<tthickpoint> points;</tthickpoint>
|
|
Toshihiro Shimizu |
890ddd |
TStroke *stroke1, *stroke2, *subStroke1, *subStroke2, *stroke;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TAffine mt, invMatrix;
|
|
Toshihiro Shimizu |
890ddd |
TThickPoint point2, finalPoint;
|
|
Toshihiro Shimizu |
890ddd |
UINT i, j, cp, cpSize;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (i = 0; i < strokeCount1; i++) {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
stroke1 = m_firstImage->getStroke(i);
|
|
Toshihiro Shimizu |
890ddd |
stroke2 = m_lastImage->getStroke(i);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_transformation[i].m_type == StrokeTransform::EQUAL) {
|
|
Toshihiro Shimizu |
890ddd |
stroke = new TStroke(*stroke1);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
points.clear();
|
|
Toshihiro Shimizu |
890ddd |
totalLen1 = stroke1->getLength();
|
|
Toshihiro Shimizu |
890ddd |
totalLen2 = stroke2->getLength();
|
|
Toshihiro Shimizu |
890ddd |
;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (stroke1->getControlPointCount() == stroke2->getControlPointCount() &&
|
|
Toshihiro Shimizu |
890ddd |
stroke1->isSelfLoop() && stroke2->isSelfLoop()) {
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < stroke1->getControlPointCount(); i++) {
|
|
Toshihiro Shimizu |
890ddd |
TThickPoint p0 = stroke1->getControlPoint(i);
|
|
Toshihiro Shimizu |
890ddd |
TThickPoint p1 = stroke2->getControlPoint(i);
|
|
Toshihiro Shimizu |
890ddd |
points.push_back(p0 * (1 - t) + p1 * t);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
stroke = new TStroke(points);
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_transformation[i].m_type == StrokeTransform::POINT) {
|
|
Toshihiro Shimizu |
890ddd |
TThickPoint pOld = stroke1->getThickPointAtLength(0.5 * totalLen1);
|
|
Toshihiro Shimizu |
890ddd |
TThickPoint pNew = stroke2->getThickPointAtLength(0.5 * totalLen2);
|
|
Toshihiro Shimizu |
890ddd |
points.push_back(pOld * (1 - t) + pNew * t);
|
|
Toshihiro Shimizu |
890ddd |
points.push_back(points[0]);
|
|
Toshihiro Shimizu |
890ddd |
points.push_back(points[0]);
|
|
Toshihiro Shimizu |
890ddd |
stroke = new TStroke(points);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
mt = (m_transformation[i].m_inverse.isIdentity())
|
|
Toshihiro Shimizu |
890ddd |
? TAffine()
|
|
Toshihiro Shimizu |
890ddd |
: TTranslation(m_transformation[i].m_translate * t) *
|
|
Toshihiro Shimizu |
890ddd |
TScale(m_transformation[i].m_rotationAndScaleCenter, (1 - t) + t * m_transformation[i].m_scaleX, (1 - t) + t * m_transformation[i].m_scaleY) *
|
|
Toshihiro Shimizu |
890ddd |
TRotation(m_transformation[i].m_rotationAndScaleCenter, m_transformation[i].m_rotation * t);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UINT cornerSize = m_transformation[i].m_firstStrokeCornerIndexes.size();
|
|
Toshihiro Shimizu |
890ddd |
assert(cornerSize == m_transformation[i].m_secondStrokeCornerIndexes.size());
|
|
Toshihiro Shimizu |
890ddd |
if (cornerSize > m_transformation[i].m_secondStrokeCornerIndexes.size())
|
|
Toshihiro Shimizu |
890ddd |
cornerSize = m_transformation[i].m_secondStrokeCornerIndexes.size();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
assert(cornerSize >= 2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::vector<tthickpoint> controlPoints;</tthickpoint>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//if not m_transformation[i].m_findCorners => detect corner return different size =>cornerSize==2
|
|
Toshihiro Shimizu |
890ddd |
// assert(!m_transformation[i].m_findCorners || cornerSize==2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < cornerSize - 1; j++) {
|
|
Toshihiro Shimizu |
890ddd |
points.clear();
|
|
Toshihiro Shimizu |
890ddd |
subStroke1 = extract(stroke1, m_transformation[i].m_firstStrokeCornerIndexes[j], m_transformation[i].m_firstStrokeCornerIndexes[j + 1] - 1);
|
|
Toshihiro Shimizu |
890ddd |
subStroke2 = extract(stroke2, m_transformation[i].m_secondStrokeCornerIndexes[j], m_transformation[i].m_secondStrokeCornerIndexes[j + 1] - 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
totalLen1 = subStroke1->getLength();
|
|
Toshihiro Shimizu |
890ddd |
totalLen2 = subStroke2->getLength();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (totalLen1 > totalLen2) {
|
|
Toshihiro Shimizu |
890ddd |
step1 = step;
|
|
Toshihiro Shimizu |
890ddd |
step2 = (totalLen2 / totalLen1) * step;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
step1 = (totalLen1 / totalLen2) * step;
|
|
Toshihiro Shimizu |
890ddd |
step2 = step;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
len1 = 0;
|
|
Toshihiro Shimizu |
890ddd |
len2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while (len1 <= totalLen1 && len2 <= totalLen2) {
|
|
Toshihiro Shimizu |
890ddd |
point2 = subStroke2->getThickPointAtLength(len2);
|
|
Toshihiro Shimizu |
890ddd |
point2 = TThickPoint(m_transformation[i].m_inverse * subStroke2->getThickPointAtLength(len2), point2.thick);
|
|
Toshihiro Shimizu |
890ddd |
finalPoint = subStroke1->getThickPointAtLength(len1) * (1 - t) + t * point2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
points.push_back(TThickPoint(mt * (finalPoint), finalPoint.thick));
|
|
Toshihiro Shimizu |
890ddd |
len1 += step1;
|
|
Toshihiro Shimizu |
890ddd |
len2 += step2;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
point2 = subStroke2->getThickPointAtLength(totalLen2);
|
|
Toshihiro Shimizu |
890ddd |
point2 = TThickPoint(m_transformation[i].m_inverse * subStroke2->getThickPointAtLength(totalLen2), point2.thick);
|
|
Toshihiro Shimizu |
890ddd |
finalPoint = subStroke1->getThickPointAtLength(totalLen1) * (1 - t) + t * point2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
points.push_back(TThickPoint(mt * (finalPoint), finalPoint.thick));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
stroke = TStroke::interpolate(points, interpolateError, false
|
|
Toshihiro Shimizu |
890ddd |
/*m_transformation[i].m_findCorners*/);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (j == 0)
|
|
Toshihiro Shimizu |
890ddd |
controlPoints.push_back(stroke->getControlPoint(0));
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
controlPoints.back() = (controlPoints.back() + stroke->getControlPoint(0)) * 0.5;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
cpSize = stroke->getControlPointCount();
|
|
Toshihiro Shimizu |
890ddd |
for (cp = 1; cp < cpSize; cp++) {
|
|
Toshihiro Shimizu |
890ddd |
controlPoints.push_back(stroke->getControlPoint(cp));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
delete subStroke1;
|
|
Toshihiro Shimizu |
890ddd |
delete subStroke2;
|
|
Toshihiro Shimizu |
890ddd |
delete stroke;
|
|
Toshihiro Shimizu |
890ddd |
subStroke1 = 0;
|
|
Toshihiro Shimizu |
890ddd |
subStroke2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
stroke = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
stroke = new TStroke(controlPoints);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (stroke1->isSelfLoop() && stroke2->isSelfLoop())
|
|
Toshihiro Shimizu |
890ddd |
stroke->setSelfLoop();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
stroke->setStyle(stroke1->getStyle());
|
|
Toshihiro Shimizu |
890ddd |
stroke->outlineOptions() = stroke1->outlineOptions();
|
|
Toshihiro Shimizu |
890ddd |
VIStroke *vs = new VIStroke(stroke, m_firstImage->getVIStroke(i)->m_groupId);
|
|
Toshihiro Shimizu |
890ddd |
vi->m_imp->m_strokes.push_back(vs);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
} //end for each stroke
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_firstImage->isComputedRegionAlmostOnce())
|
|
Toshihiro Shimizu |
890ddd |
transferColor(vi);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return vi;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TInbetween::Imp::transferColor(const TVectorImageP &destination) const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
const TVectorImageP &original = m_firstImage;
|
|
Toshihiro Shimizu |
890ddd |
destination->setPalette(original->getPalette());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
destination->findRegions();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (destination->getRegionCount()) {
|
|
Toshihiro Shimizu |
890ddd |
UINT strokeCount1 = original->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
UINT strokeCount2 = destination->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
if (strokeCount1 > strokeCount2)
|
|
Toshihiro Shimizu |
890ddd |
strokeCount1 = strokeCount2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (UINT i = 0; i < strokeCount1; i++) {
|
|
Toshihiro Shimizu |
890ddd |
TVectorImage::transferStrokeColors(original, i, destination, i);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP TInbetween::tween(double t) const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return m_imp->tween(t);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-------------------------------------------------------------------
|