summaryrefslogtreecommitdiff
path: root/navit/transform.c
diff options
context:
space:
mode:
authorsleske <sleske@ffa7fe5e-494d-0410-b361-a75ebd5db220>2013-06-29 21:28:15 +0000
committersleske <sleske@ffa7fe5e-494d-0410-b361-a75ebd5db220>2013-06-29 21:28:15 +0000
commitc34ab32c2c088cd93d9f4dc60831a65bf451e4c7 (patch)
tree8a3cd9fc428a832c39886f58afe51d8ba1cc2636 /navit/transform.c
parente6ab92626129cd2cca4c830bffcba409beb2c0d4 (diff)
downloadnavit-c34ab32c2c088cd93d9f4dc60831a65bf451e4c7.tar.gz
Refactor:core:Make transform() more readable and shorter by extracting loads of stuff.
git-svn-id: http://svn.code.sf.net/p/navit/code/trunk/navit@5540 ffa7fe5e-494d-0410-b361-a75ebd5db220
Diffstat (limited to 'navit/transform.c')
-rw-r--r--navit/transform.c218
1 files changed, 141 insertions, 77 deletions
diff --git a/navit/transform.c b/navit/transform.c
index 4939e8b4b..425fdd05b 100644
--- a/navit/transform.c
+++ b/navit/transform.c
@@ -375,7 +375,7 @@ transform_utm_to_geo(const double UTMEasting, const double UTMNorthing, int Zone
double e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared));
double N1, T1, C1, R1, D, M;
double LongOrigin;
- double mu, phi1, phi1Rad;
+ double mu, phi1Rad;
double x, y;
double rad2deg = 180/M_PI;
@@ -395,7 +395,6 @@ transform_utm_to_geo(const double UTMEasting, const double UTMNorthing, int Zone
phi1Rad = mu + (3*e1/2-27*e1*e1*e1/32)*sin(2*mu)
+ (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu)
+(151*e1*e1*e1/96)*sin(6*mu);
- phi1 = phi1Rad*rad2deg;
N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad));
T1 = tan(phi1Rad)*tan(phi1Rad);
@@ -415,97 +414,162 @@ transform_utm_to_geo(const double UTMEasting, const double UTMNorthing, int Zone
geo->lng=Long;
}
-int
-transform(struct transformation *t, enum projection pro, struct coord *c, struct point *p, int count, int mindist, int width, int *width_return)
+static struct coord
+transform_correct_projection(struct transformation *t, enum projection required_projection, struct coord c)
{
- struct coord c1;
- int xcn, ycn;
+ struct coord result;
struct coord_geo g;
- int xc, yc, zc=0, xco=0, yco=0, zco=0;
+ if (required_projection == t->pro) {
+ result=c;
+ } else {
+ transform_to_geo(required_projection, &c, &g);
+ transform_from_geo(t->pro, &g, &result);
+ }
+ return result;
+}
+
+static struct coord
+transform_shift_by_center_and_scale(struct transformation *t, struct coord c)
+{
+ struct coord result;
+ result.x = c.x - t->map_center.x;
+ result.y = c.y - t->map_center.y;
+ result.x >>= t->scale_shift;
+ result.y >>= t->scale_shift;
+ return result;
+}
+
+struct coord_3d {
+ int x;
+ int y;
+ int z;
+};
+
+
+static struct coord_3d
+transform_rotate(struct transformation *t, struct coord c)
+{
+ struct coord_3d result;
+ result.x=c.x*t->m00+c.y*t->m01+HOG(*t)*t->m02;
+ result.y=c.x*t->m10+c.y*t->m11+HOG(*t)*t->m12;
+ result.z=(c.x*t->m20+c.y*t->m21+HOG(*t)*t->m22);
+ result.z+=t->offz << POST_SHIFT;
+ dbg(3, "result: (%d,%d,%d)\n", result.x,result.y,result.z);
+ return result;
+}
+
+static struct coord_3d
+transform_z_clip(struct coord_3d c, struct coord_3d c_old, int zlimit)
+{
+ struct coord_3d result;
+ float clip_factor = (zlimit-c.z)/(c_old.z-c.z);
+ result.x=c.x+(c_old.x-c.x)*clip_factor;
+ result.y=c.y+(c_old.y-c.y)*clip_factor;
+ result.z=zlimit;
+ dbg(3,"clip result: (%d,%d,%d)\n", result.x, result.y, result.z);
+ return result;
+}
+
+static struct point
+transform_project_onto_view_plane(struct transformation *t, struct coord_3d c)
+{
+ struct point result;
+ result.x = (long long)c.x*t->xscale/c.z;
+ result.y = (long long)c.y*t->yscale/c.z;
+ return result;
+}
+
+static int
+transform_points_too_close(struct point screen_point, struct point screen_point_old, int mindist)
+{
+ if (!mindist){
+ return 0;
+ }
+ // approximation of Euclidean distance
+ return (abs(screen_point.x - screen_point_old.x) +
+ abs(screen_point.y - screen_point_old.y)) < mindist;
+}
+
+struct z_clip_result{
+ struct coord_3d clipped_coord;
+ int visible;
+ int process_coord_again;
+ int skip_coord;
+};
+
+static struct z_clip_result
+transform_z_clip_if_necessary(struct coord_3d coord, int zlimit, struct z_clip_result clip_result_old)
+{
+ int visibility_changed;
+ struct z_clip_result clip_result={{0,0}, 0, 0, 0};
+ clip_result.visible=(coord.z < zlimit ? 0:1);
+ visibility_changed=(clip_result_old.visible != -1)&&(clip_result.visible != clip_result_old.visible);
+ if (visibility_changed) {
+ clip_result.clipped_coord=transform_z_clip(coord, clip_result_old.clipped_coord, zlimit);
+ } else {
+ clip_result.clipped_coord=coord;
+ }
+ if (clip_result.visible && visibility_changed){
+ // line was clipped, but current point
+ // is visible -> process it again
+ clip_result.process_coord_again=1;
+ }else if (!clip_result.visible && !visibility_changed){
+ clip_result.skip_coord=1;
+ }
+ return clip_result;
+}
+
+int
+transform(struct transformation *t, enum projection required_projection, struct coord *input,
+ struct point *result, int count, int mindist, int width, int *width_result)
+{
+ struct coord projected_coord, shifted_coord;
+ struct coord_3d rotated_coord;
+ struct point screen_point;
int zlimit=t->znear;
- int visible, visibleo=-1;
- int i,j = 0,k=0;
+ struct z_clip_result clip_result, clip_result_old={{0,0}, -1, 0, 0};
+ int i,result_idx = 0,result_idx_last=0;
dbg(3,"count=%d\n", count);
for (i=0; i < count; i++) {
- dbg(3, "input coord %d: (%d, %d)\n", i, c[i].x, c[i].y);
- if (pro == t->pro) {
- xc=c[i].x;
- yc=c[i].y;
- } else {
- transform_to_geo(pro, &c[i], &g);
- transform_from_geo(t->pro, &g, &c1);
- xc=c1.x;
- yc=c1.y;
- }
- xc-=t->map_center.x;
- yc-=t->map_center.y;
- xc >>= t->scale_shift;
- yc >>= t->scale_shift;
-
- xcn=xc*t->m00+yc*t->m01+HOG(*t)*t->m02;
- ycn=xc*t->m10+yc*t->m11+HOG(*t)*t->m12;
+ dbg(3, "input coord %d: (%d, %d)\n", i, input[i].x, input[i].y);
+ projected_coord = transform_correct_projection(t, required_projection, input[i]);
+ shifted_coord = transform_shift_by_center_and_scale(t, projected_coord);
+ rotated_coord = transform_rotate(t, shifted_coord);
if (t->ddd) {
- zc=(xc*t->m20+yc*t->m21+HOG(*t)*t->m22);
- zc+=t->offz << POST_SHIFT;
- dbg(3,"zc(%d)=xc(%d)*m20(%d)+yc(%d)*m21(%d)\n", zc, xc, t->m20, yc, t->m21);
- /* visibility */
- visible=(zc < zlimit ? 0:1);
- if (visible != visibleo && visibleo != -1) {
- if (zco != zc) {
- xcn=xcn+(long long)(xco-xcn)*(zlimit-zc)/(zco-zc);
- ycn=ycn+(long long)(yco-ycn)*(zlimit-zc)/(zco-zc);
- }
- zc=zlimit;
- dbg(3,"clip result: (%d,%d,%d)\n", xcn,ycn,zc);
- xco=xcn;
- yco=ycn;
- zco=zc;
- if (visible)
- i--;
- visibleo=visible;
- } else {
- xco=xcn;
- yco=ycn;
- zco=zc;
- visibleo=visible;
- if (! visible)
- continue;
+ clip_result=transform_z_clip_if_necessary(rotated_coord, zlimit, clip_result_old);
+ clip_result_old=clip_result;
+ if(clip_result.process_coord_again){
+ i--;
+ } else if (clip_result.skip_coord){
+ continue;
}
- xc=(long long)xcn*t->xscale/zc;
- yc=(long long)ycn*t->yscale/zc;
+ screen_point = transform_project_onto_view_plane(t, clip_result.clipped_coord);
} else {
- xc=xcn;
- yc=ycn;
- xc>>=POST_SHIFT;
- yc>>=POST_SHIFT;
+ screen_point.x = rotated_coord.x>>POST_SHIFT;
+ screen_point.y = rotated_coord.y>>POST_SHIFT;
}
- xc+=t->offx;
- yc+=t->offy;
- dbg(3,"result: (%d, %d)\n", xc, yc);
-
- if (i != 0 && i != count-1 && mindist) {
- /* We expect values of mindist to be within 0..5 pixels for nice looking screens.
- That gives difference of about 1 pixel in worst case between abs(dx)+abs(dy) and sqrt(dx*dx+dy*dy).
- We expect significantly bigger values when drawing map while scrolling it. But it anyway will be ugly.
- Should anybody care about that inaccuracy? */
- if ( (abs(xc - p[k].x) + abs(yc - p[k].y)) < mindist &&
- (c[i+1].x != c[0].x || c[i+1].y != c[0].y))
+ screen_point.x+=t->offx;
+ screen_point.y+=t->offy;
+ dbg(3,"result: (%d, %d)\n", screen_point.x, screen_point.y);
+
+ if (i != 0 && i != count-1 &&
+ (input[i+1].x != input[0].x || input[i+1].y != input[0].y)) {
+ if (transform_points_too_close(screen_point, result[result_idx_last], mindist)){
continue;
- k=j;
+ }
}
-
- p[j].x=xc;
- p[j].y=yc;
- if (width_return) {
+ result[result_idx]=screen_point;
+ if (width_result) {
if (t->ddd)
- width_return[j]=width*t->wscale/zc;
+ width_result[result_idx]=width*t->wscale/rotated_coord.z;
else
- width_return[j]=width;
+ width_result[result_idx]=width;
}
- j++;
+ result_idx_last=result_idx;
+ result_idx++;
}
- return j;
+ return result_idx;
}
static void