Merge branch 'master' of CorentinB/uGFX into master
This commit is contained in:
commit
82e1a667c5
1 changed files with 29 additions and 61 deletions
|
@ -2991,75 +2991,43 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co
|
||||||
* equal to 'norm'. */
|
* equal to 'norm'. */
|
||||||
static void get_normal_vector(coord_t dx, coord_t dy, coord_t norm, coord_t *nx, coord_t *ny)
|
static void get_normal_vector(coord_t dx, coord_t dy, coord_t norm, coord_t *nx, coord_t *ny)
|
||||||
{
|
{
|
||||||
int32_t dx2, dy2, len_sq, norm_sq, norm_sq2;
|
coord_t absDx, absDy;
|
||||||
int div, step, best, delta, abs_delta;
|
int32_t len_n, len, len2;
|
||||||
|
char maxSteps;
|
||||||
|
|
||||||
dx2 = dx; dy2 = dy;
|
/* Take the absolute value of dx and dy, multiplied by 2 for precision */
|
||||||
norm_sq = (int32_t)norm * norm;
|
absDx = (dx >= 0 ? dx : -dx) * 2;
|
||||||
norm_sq2 = norm_sq * 512;
|
absDy = (dy >= 0 ? dy : -dy) * 2;
|
||||||
|
|
||||||
/* Scale dx2 and dy2 so that
|
/* Compute the quadrate length */
|
||||||
* len_sq / 2 <= norm_sq * 512 <= len_sq * 2.
|
len2 = absDx * absDx + absDy * absDy;
|
||||||
* The scaling by 512 is to yield higher accuracy in division later. */
|
|
||||||
len_sq = dx2 * dx2 + dy2 * dy2;
|
|
||||||
|
|
||||||
if (len_sq < norm_sq2)
|
/* First aproximation : length = |dx| + |dy| */
|
||||||
{
|
len = absDx + absDy;
|
||||||
while (len_sq && len_sq < norm_sq2)
|
|
||||||
{
|
|
||||||
len_sq <<= 2; dx2 <<= 1; dy2 <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (len_sq > norm_sq2)
|
|
||||||
{
|
|
||||||
while (len_sq && len_sq > norm_sq2)
|
|
||||||
{
|
|
||||||
len_sq >>= 2; dx2 >>= 1; dy2 >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now find the divider div so that
|
/* Give a max number of steps, the calculation usually takes 3 or 4 */
|
||||||
* len_sq / div^2 == norm_sq i.e. div = sqrt(len_sq / norm_sq)
|
for(maxSteps = 8; maxSteps > 0; maxSteps--)
|
||||||
*
|
{
|
||||||
* This is done using bisection search to avoid the need for floating
|
/* Use an adapted version of Newton's algorithm to find the correct length
|
||||||
* point sqrt.
|
* This calculation converge quadratically towards the correct length
|
||||||
*
|
* n(x+1) = (n(x) + len^2 / n(x)) / 2
|
||||||
* Based on previous scaling, we know that
|
|
||||||
* len_sq / 2 <= norm_sq * 512 <=> div <= sqrt(1024) = 32
|
|
||||||
* len_sq * 2 >= norm_sq * 512 <=> div >= sqrt(256) = 16
|
|
||||||
*/
|
*/
|
||||||
div = 24; step = 8;
|
len_n = (len + len2 / len) / 2;
|
||||||
best = 256;
|
|
||||||
|
|
||||||
for (;;)
|
/* We reach max precision when the last result is equal or greater than the previous one */
|
||||||
{
|
if(len_n >= len){
|
||||||
dx = dx2 / div;
|
break;
|
||||||
dy = dy2 / div;
|
|
||||||
len_sq = dx*dx + dy*dy;
|
|
||||||
|
|
||||||
delta = len_sq - norm_sq;
|
|
||||||
|
|
||||||
abs_delta = (delta >= 0) ? delta : -delta;
|
|
||||||
|
|
||||||
if (abs_delta < best)
|
|
||||||
{
|
|
||||||
*nx = dy;
|
|
||||||
*ny = -dx;
|
|
||||||
best = abs_delta;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delta > 0)
|
len = len_n;
|
||||||
div += step;
|
|
||||||
else if (delta < 0)
|
|
||||||
div -= step;
|
|
||||||
else if (delta == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (step == 0)
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
step >>= 1; /* Do one round with step = 0 to calculate final result. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute the normal vector using nx = dy * desired length / vector length
|
||||||
|
* The solution is rounded to the nearest integer
|
||||||
|
*/
|
||||||
|
*nx = rounding_div(dy * norm * 2, len);
|
||||||
|
*ny = rounding_div(-dx * norm * 2, len);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdispGDrawThickLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color, coord_t width, bool_t round) {
|
void gdispGDrawThickLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color, coord_t width, bool_t round) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue