1#pragma once
2#ifndef __CVTT_ENDPOINTSELECTOR_H__
3#define __CVTT_ENDPOINTSELECTOR_H__
4
5#include "ConvectionKernels_ParallelMath.h"
6#include "ConvectionKernels_UnfinishedEndpoints.h"
7#include "ConvectionKernels_PackedCovarianceMatrix.h"
8
9namespace cvtt
10{
11 namespace Internal
12 {
13 static const int NumEndpointSelectorPasses = 3;
14
15 template<int TVectorSize, int TIterationCount>
16 class EndpointSelector
17 {
18 public:
19 typedef ParallelMath::Float MFloat;
20
21 EndpointSelector()
22 {
23 for (int ch = 0; ch < TVectorSize; ch++)
24 {
25 m_centroid[ch] = ParallelMath::MakeFloatZero();
26 m_direction[ch] = ParallelMath::MakeFloatZero();
27 }
28 m_weightTotal = ParallelMath::MakeFloatZero();
29 m_minDist = ParallelMath::MakeFloat(FLT_MAX);
30 m_maxDist = ParallelMath::MakeFloat(-FLT_MAX);
31 }
32
33 void ContributePass(const MFloat *value, int pass, const MFloat &weight)
34 {
35 if (pass == 0)
36 ContributeCentroid(value, weight);
37 else if (pass == 1)
38 ContributeDirection(value, weight);
39 else if (pass == 2)
40 ContributeMinMax(value);
41 }
42
43 void FinishPass(int pass)
44 {
45 if (pass == 0)
46 FinishCentroid();
47 else if (pass == 1)
48 FinishDirection();
49 }
50
51 UnfinishedEndpoints<TVectorSize> GetEndpoints(const float channelWeights[TVectorSize]) const
52 {
53 MFloat unweightedBase[TVectorSize];
54 MFloat unweightedOffset[TVectorSize];
55
56 for (int ch = 0; ch < TVectorSize; ch++)
57 {
58 MFloat min = m_centroid[ch] + m_direction[ch] * m_minDist;
59 MFloat max = m_centroid[ch] + m_direction[ch] * m_maxDist;
60
61 float safeWeight = channelWeights[ch];
62 if (safeWeight == 0.f)
63 safeWeight = 1.0f;
64
65 unweightedBase[ch] = min / channelWeights[ch];
66 unweightedOffset[ch] = (max - min) / channelWeights[ch];
67 }
68
69 return UnfinishedEndpoints<TVectorSize>(unweightedBase, unweightedOffset);
70 }
71
72 private:
73 void ContributeCentroid(const MFloat *value, const MFloat &weight)
74 {
75 for (int ch = 0; ch < TVectorSize; ch++)
76 m_centroid[ch] = m_centroid[ch] + value[ch] * weight;
77 m_weightTotal = m_weightTotal + weight;
78 }
79
80 void FinishCentroid()
81 {
82 MFloat denom = m_weightTotal;
83 ParallelMath::MakeSafeDenominator(denom);
84
85 for (int ch = 0; ch < TVectorSize; ch++)
86 m_centroid[ch] = m_centroid[ch] / denom;
87 }
88
89 void ContributeDirection(const MFloat *value, const MFloat &weight)
90 {
91 MFloat diff[TVectorSize];
92 for (int ch = 0; ch < TVectorSize; ch++)
93 diff[ch] = value[ch] - m_centroid[ch];
94
95 m_covarianceMatrix.Add(diff, weight);
96 }
97
98 void FinishDirection()
99 {
100 MFloat approx[TVectorSize];
101 for (int ch = 0; ch < TVectorSize; ch++)
102 approx[ch] = ParallelMath::MakeFloat(1.0f);
103
104 for (int i = 0; i < TIterationCount; i++)
105 {
106 MFloat product[TVectorSize];
107 m_covarianceMatrix.Product(product, approx);
108
109 MFloat largestComponent = product[0];
110 for (int ch = 1; ch < TVectorSize; ch++)
111 largestComponent = ParallelMath::Max(largestComponent, product[ch]);
112
113 // product = largestComponent*newApprox
114 ParallelMath::MakeSafeDenominator(largestComponent);
115 for (int ch = 0; ch < TVectorSize; ch++)
116 approx[ch] = product[ch] / largestComponent;
117 }
118
119 // Normalize
120 MFloat approxLen = ParallelMath::MakeFloatZero();
121 for (int ch = 0; ch < TVectorSize; ch++)
122 approxLen = approxLen + approx[ch] * approx[ch];
123
124 approxLen = ParallelMath::Sqrt(approxLen);
125
126 ParallelMath::MakeSafeDenominator(approxLen);
127
128 for (int ch = 0; ch < TVectorSize; ch++)
129 m_direction[ch] = approx[ch] / approxLen;
130 }
131
132 void ContributeMinMax(const MFloat *value)
133 {
134 MFloat dist = ParallelMath::MakeFloatZero();
135 for (int ch = 0; ch < TVectorSize; ch++)
136 dist = dist + m_direction[ch] * (value[ch] - m_centroid[ch]);
137
138 m_minDist = ParallelMath::Min(m_minDist, dist);
139 m_maxDist = ParallelMath::Max(m_maxDist, dist);
140 }
141
142 ParallelMath::Float m_centroid[TVectorSize];
143 ParallelMath::Float m_direction[TVectorSize];
144 PackedCovarianceMatrix<TVectorSize> m_covarianceMatrix;
145 ParallelMath::Float m_weightTotal;
146
147 ParallelMath::Float m_minDist;
148 ParallelMath::Float m_maxDist;
149 };
150 }
151}
152
153#endif
154