Skip to content

Commit 65a3904

Browse files
Add example how to map pixels in floor plans (#102)
Signed-off-by: Teemu Piiroinen <[email protected]>
1 parent 7431c89 commit 65a3904

File tree

3 files changed

+284
-0
lines changed

3 files changed

+284
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.o
2+
*.exe
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
BINNAME = floor_plan_pixel_conversion
2+
CC = gcc
3+
CFLAGS = -g -O2 -Wall -Wextra
4+
5+
OBJECTS = main.o
6+
7+
all: $(OBJECTS)
8+
$(CC) $(CFLAGS) $(OBJECTS) $(LDFLAGS) -o $(BINNAME)
9+
10+
main.o:
11+
$(CC) $(CFLAGS) -c main.c
12+
13+
clean:
14+
rm *.o
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/* Copyright 2020 Wirepas Ltd licensed under Apache License, Version 2.0
2+
*
3+
* See file LICENSE for full license details.
4+
*
5+
*/
6+
#include <math.h>
7+
#include <stdio.h>
8+
#include <string.h>
9+
10+
#ifndef M_PI
11+
#define M_PI acos(-1.0)
12+
#endif
13+
#define MATRIX_ITEM_COUNT (3 * 3)
14+
15+
/** Structure to hold point in 2d */
16+
typedef struct
17+
{
18+
double x;
19+
double y;
20+
} point_2d_t;
21+
22+
/** Structure to hold point in 3d */
23+
typedef struct
24+
{
25+
double x;
26+
double y;
27+
double z;
28+
} point_3d_t;
29+
30+
/** Structure to hold WGS84 coordinates */
31+
typedef struct
32+
{
33+
double latitude;
34+
double longitude;
35+
double altitude;
36+
} location_t;
37+
38+
/**
39+
* \brief Function to convert degrees to radians
40+
* \param deg
41+
* Value in degrees
42+
* \return Value in radians
43+
*/
44+
static double deg_to_rad(double deg)
45+
{
46+
return deg * M_PI / 180.0;
47+
}
48+
49+
/**
50+
* \brief Function to convert radians to degrees
51+
* \param rad
52+
* Value in radians
53+
* \return Value in degrees
54+
*/
55+
static double rad_to_deg(double rad)
56+
{
57+
return rad * 180.0 / M_PI;
58+
}
59+
60+
/**
61+
* \brief Function to convert WGS84 coordinates to ECEF coordinates
62+
* \param location
63+
* WGS84 coordinates
64+
* \return ECEF coordinates
65+
*/
66+
static point_3d_t wgs82_to_ecef(location_t location)
67+
{
68+
const double a = 6378137.0;
69+
const double finv = 298.257223563;
70+
71+
const double f = 1.0 / finv;
72+
double e2 = 1.0 - pow(1.0 - f, 2);
73+
74+
double latitude_rad = deg_to_rad(location.latitude);
75+
double longitude_rad = deg_to_rad(location.longitude);
76+
77+
double v = a / sqrt(1.0 - e2 * sin(latitude_rad) * sin(latitude_rad));
78+
79+
point_3d_t point_ecef;
80+
81+
point_ecef.x = (v + location.altitude) * cos(latitude_rad) * cos(longitude_rad);
82+
point_ecef.y = (v + location.altitude) * cos(latitude_rad) * sin(longitude_rad);
83+
point_ecef.z = (v * (1.0 - e2) + location.altitude) * sin(latitude_rad);
84+
85+
return point_ecef;
86+
}
87+
88+
/**
89+
* \brief Function to convert ECEF coordinates to WGS84 coordinates
90+
* \param ecef_point
91+
* ECEF coordinates
92+
* \return WGS84 coordinates
93+
*/
94+
static location_t ecef_to_wgs84(point_3d_t ecef_point)
95+
{
96+
const double a = 6378137.0;
97+
const double finv = 298.257223563;
98+
99+
const double f = 1.0 / finv;
100+
double e2 = 1.0 - pow(1.0 - f, 2);
101+
102+
double elat = pow(10, -12);
103+
double eht = pow(10, -5);
104+
105+
double p = sqrt(ecef_point.x * ecef_point.x + ecef_point.y * ecef_point.y);
106+
double lat = atan2(ecef_point.z, p * (1.0 - e2));
107+
double h = 0;
108+
double dh = 1;
109+
double dlat = 1;
110+
111+
while (dlat > elat || dh > eht)
112+
{
113+
double lat0 = lat;
114+
double h0 = h;
115+
double v = a / sqrt(1.0 - e2 * sin(lat) * sin(lat));
116+
117+
h = p / cos(lat) - v;
118+
lat = atan2(ecef_point.z, p * (1.0 - e2 * v / (v + h)));
119+
dlat = fabs(lat - lat0);
120+
dh = fabs(h - h0);
121+
}
122+
123+
double lon = atan2(ecef_point.y, ecef_point.x);
124+
125+
location_t location;
126+
127+
location.latitude = rad_to_deg(lat);
128+
location.longitude = rad_to_deg(lon);
129+
location.altitude = h;
130+
131+
return location;
132+
}
133+
134+
/**
135+
* \brief Function to convert floor plan pixel coordinates to WGS84 coordinates
136+
* \param rotation_matrix
137+
* Rotation matrix from WNT backend
138+
* \param reverse_transformation_vector
139+
* Offset vector from WNT backend
140+
* \param scale_pixels_per_meter
141+
* Scale from WNT backend
142+
* \param pixel_position_vector
143+
* Pixel coordinates to map to WGS84 coordinates
144+
* \return WGS84 coordinates
145+
*/
146+
static location_t get_location(double *rotation_matrix, point_3d_t reverse_transformation_vector,
147+
double scale_pixels_per_meter, point_2d_t pixel_position_vector)
148+
{
149+
double transposed_rotation_matrix[MATRIX_ITEM_COUNT] = { 0 };
150+
memcpy(transposed_rotation_matrix, rotation_matrix, sizeof(transposed_rotation_matrix));
151+
152+
transposed_rotation_matrix[1] = rotation_matrix[3];
153+
transposed_rotation_matrix[2] = rotation_matrix[6];
154+
transposed_rotation_matrix[3] = rotation_matrix[1];
155+
transposed_rotation_matrix[5] = rotation_matrix[7];
156+
transposed_rotation_matrix[6] = rotation_matrix[2];
157+
transposed_rotation_matrix[7] = rotation_matrix[5];
158+
159+
point_3d_t pixel_delta_vector;
160+
161+
pixel_delta_vector.x =
162+
transposed_rotation_matrix[0] * pixel_position_vector.x +
163+
transposed_rotation_matrix[1] * pixel_position_vector.y;
164+
165+
pixel_delta_vector.y =
166+
transposed_rotation_matrix[3] * pixel_position_vector.x +
167+
transposed_rotation_matrix[4] * pixel_position_vector.y;
168+
169+
pixel_delta_vector.z =
170+
transposed_rotation_matrix[6] * pixel_position_vector.x +
171+
transposed_rotation_matrix[7] * pixel_position_vector.y;
172+
173+
pixel_delta_vector.x /= scale_pixels_per_meter;
174+
pixel_delta_vector.y /= scale_pixels_per_meter;
175+
pixel_delta_vector.z /= scale_pixels_per_meter;
176+
177+
point_3d_t point_ecef;
178+
point_ecef.x = pixel_delta_vector.x + reverse_transformation_vector.x;
179+
point_ecef.y = pixel_delta_vector.y + reverse_transformation_vector.y;
180+
point_ecef.z = pixel_delta_vector.z + reverse_transformation_vector.z;
181+
182+
return ecef_to_wgs84(point_ecef);
183+
}
184+
185+
/**
186+
* \brief Function to convert WGS84 coordinates to floor plan pixel coordinates
187+
* \param rotation_matrix
188+
* Rotation matrix from WNT backend
189+
* \param reverse_transformation_vector
190+
* Offset vector from WNT backend
191+
* \param scale_pixels_per_meter
192+
* Scale from WNT backend
193+
* \param location
194+
* WGS84 coordinates to map to pixel coordinates
195+
* \return Pixel coordinates
196+
*/
197+
static point_2d_t get_pixel_position(double *rotation_matrix, point_3d_t reverse_transformation_vector,
198+
double scale_pixels_per_meter, location_t location)
199+
{
200+
point_3d_t point_ecef = wgs82_to_ecef(location);
201+
202+
point_ecef.x -= reverse_transformation_vector.x;
203+
point_ecef.y -= reverse_transformation_vector.y;
204+
point_ecef.z -= reverse_transformation_vector.z;
205+
206+
point_2d_t point_pixel;
207+
208+
point_pixel.x =
209+
rotation_matrix[0] * point_ecef.x +
210+
rotation_matrix[1] * point_ecef.y +
211+
rotation_matrix[2] * point_ecef.z;
212+
213+
point_pixel.y =
214+
rotation_matrix[3] * point_ecef.x +
215+
rotation_matrix[4] * point_ecef.y +
216+
rotation_matrix[5] * point_ecef.z;
217+
218+
point_pixel.x *= scale_pixels_per_meter;
219+
point_pixel.y *= scale_pixels_per_meter;
220+
221+
return point_pixel;
222+
}
223+
224+
/**
225+
* \brief Main entry point
226+
* \return Return value
227+
*/
228+
int main()
229+
{
230+
/** Example values from WNT backend start */
231+
double rotation_matrix[] = {
232+
0.7788987921717944, 0.5526683279974951, 0.296436149586675,
233+
0.579597627535213, -0.4538080052202482, -0.6768492332518167,
234+
-0.2395480363285678, 0.6990107392783551, -0.6737957588651434
235+
};
236+
237+
point_3d_t offset_local_to_ecef;
238+
offset_local_to_ecef.x = 1530181.848984246;
239+
offset_local_to_ecef.y = -4465265.612122585;
240+
offset_local_to_ecef.z = 4275385.419786042;
241+
242+
double pixels_per_meter = 35;
243+
/** Example values from WNT backend end */
244+
245+
/** Pixel coordinates to convert to WGS84 coordinates */
246+
point_2d_t point_to_map;
247+
point_to_map.x = 230;
248+
point_to_map.y = 272;
249+
250+
printf("Point to map. X:%.0lf Y:%.0lf\n", point_to_map.x, point_to_map.y);
251+
252+
location_t location =
253+
get_location(rotation_matrix, offset_local_to_ecef, pixels_per_meter, point_to_map);
254+
255+
printf("Calculated location. Latitude:%.6lf Longitude:%.6lf Altitude:%.2lf\n",
256+
location.latitude, location.longitude, location.altitude);
257+
258+
/** Convert the calculated WGS84 coordinates back to pixel coordinates */
259+
point_2d_t point =
260+
get_pixel_position(rotation_matrix, offset_local_to_ecef, pixels_per_meter, location);
261+
262+
printf("Calculated point. X:%.0lf Y:%.0lf\n", point.x, point.y);
263+
printf("Press any key to close\n");
264+
265+
getchar();
266+
267+
return 0;
268+
}

0 commit comments

Comments
 (0)