2
|
1 /*! \brief Implement coordination tranform mechanism.
|
|
2 * \file
|
|
3 * This file implements coordination transforming for containers.
|
|
4 */
|
1
|
5 #include <stdio.h>
|
|
6 #include <string.h>
|
|
7
|
2
|
8 typedef float co_aix;
|
|
9 /*! \brief A coordination system.
|
|
10 *
|
|
11 * It have a transform function defined by matrix to transform
|
|
12 * coordination from source space to target space.
|
|
13 * Source space is where the contained is drawed, and target space
|
|
14 * is where the coordination of parent container of the element
|
|
15 * represented by this coord object.
|
|
16 */
|
1
|
17 typedef struct coord {
|
|
18 int seq;
|
2
|
19 co_aix matrix[6];
|
|
20 co_aix aggr_matrix[6];
|
1
|
21 struct coord *parent;
|
|
22 struct coord *children, *sibling;
|
|
23 } coord_t;
|
|
24
|
2
|
25 #define MUL(a, b) ((a) * (b))
|
|
26 #define ADD(a, b) ((a) + (b))
|
|
27 #define DIV(a, b) ((a) / (b))
|
|
28 #define SUB(a, b) ((a) - (b))
|
|
29
|
|
30 static void mul_matrix(co_aix *m1, co_aix *m2, co_aix *dst) {
|
|
31 dst[0] = ADD(MUL(m1[0], m2[0]), MUL(m1[1], m2[3]));
|
|
32 dst[1] = ADD(MUL(m1[0], m2[1]), MUL(m1[1], m2[4]));
|
|
33 dst[2] = ADD(ADD(MUL(m1[0], m2[2]), MUL(m1[1], m2[5])), m1[2]);
|
|
34 dst[3] = ADD(MUL(m1[3], m2[0]), MUL(m1[4], m2[3]));
|
|
35 dst[4] = ADD(MUL(m1[3], m2[1]), MUL(m1[4], m2[4]));
|
|
36 dst[5] = ADD(ADD(MUL(m1[3], m2[2]), MUL(m1[4], m2[5])), m1[5]);
|
1
|
37 }
|
|
38
|
2
|
39 /*! \brief Compute agrregated transform function.
|
|
40 *
|
|
41 * Base on parent's aggregated matrix if it is existed, or use transform
|
|
42 * matrix as aggregated matrix.
|
|
43 */
|
1
|
44 static void compute_transform_function(coord_t *visit) {
|
|
45 if(visit->parent)
|
|
46 mul_matrix(visit->parent->aggr_matrix,
|
|
47 visit->matrix, visit->aggr_matrix);
|
|
48 else
|
|
49 memcpy(visit->aggr_matrix, visit->matrix, sizeof(visit->matrix));
|
|
50 }
|
|
51
|
|
52 /*! \brief Update aggregate matrices of elements under a sub-tree.
|
|
53 *
|
|
54 * A subtree is specified by the root of it. All elements in the subtree
|
|
55 * are effected by that changes of matrix of the subtree root.
|
|
56 */
|
|
57 void update_aggr_matrix(coord_t *start) {
|
|
58 coord_t *visit, *child, *next;
|
|
59
|
|
60 compute_transform_function(start);
|
|
61
|
|
62 visit = start;
|
|
63 while(visit) {
|
|
64 child = visit->children;
|
|
65 while(child) {
|
|
66 compute_transform_function(child);
|
|
67 child = child->sibling;
|
|
68 }
|
|
69
|
|
70 if(visit->children)
|
|
71 visit = visit->children;
|
|
72 else if(visit->sibling)
|
|
73 visit = visit->sibling;
|
|
74 else {
|
|
75 next = NULL;
|
|
76 while(visit->parent && visit->parent != start) {
|
|
77 visit = visit->parent;
|
|
78 if(visit->sibling) {
|
|
79 next = visit->sibling;
|
|
80 break;
|
|
81 }
|
|
82 }
|
|
83 visit = next;
|
|
84 }
|
|
85 }
|
|
86 }
|
|
87
|
|
88 void coord_init(coord_t *co, coord_t *parent) {
|
|
89 memset(co, 0, sizeof(coord_t));
|
|
90 if(parent) {
|
|
91 co->parent = parent;
|
|
92 co->sibling = parent->children;
|
|
93 parent->children = co;
|
|
94 }
|
|
95 co->matrix[0] = 1;
|
|
96 co->matrix[4] = 1;
|
|
97 }
|
|
98
|
2
|
99 void coord_trans_pos(coord_t *co, co_aix *x, co_aix *y) {
|
|
100 co_aix nx, ny;
|
|
101
|
|
102 nx = ADD(ADD(MUL(co->aggr_matrix[0], *x),
|
|
103 MUL(co->aggr_matrix[1], *y)),
|
|
104 co->aggr_matrix[2]);
|
|
105 ny = ADD(ADD(MUL(co->aggr_matrix[3], *x),
|
|
106 MUL(co->aggr_matrix[4], *y)),
|
|
107 co->aggr_matrix[5]);
|
|
108 *x = nx;
|
|
109 *y = ny;
|
|
110 }
|
|
111
|
1
|
112 #ifdef UNITTEST
|
|
113
|
|
114 #include <CUnit/Basic.h>
|
|
115
|
|
116 void test_update_aggr_matrix(void) {
|
|
117 coord_t elms[6];
|
2
|
118 co_aix x, y;
|
1
|
119
|
|
120 coord_init(elms, NULL);
|
|
121 coord_init(elms + 1, elms);
|
|
122 coord_init(elms + 2, elms);
|
|
123 coord_init(elms + 3, elms + 1);
|
|
124 coord_init(elms + 4, elms + 1);
|
|
125 coord_init(elms + 5, elms + 2);
|
|
126
|
|
127 /* | 2 -1 0 |
|
|
128 * | 0 1 0 |
|
|
129 * | 0 0 1 |
|
|
130 */
|
|
131 elms[0].matrix[0] = 2;
|
|
132 elms[0].matrix[1] = -1;
|
|
133
|
|
134 /* | 1 3 0 |
|
|
135 * | 5 1 0 |
|
|
136 * | 0 0 1 |
|
|
137 */
|
|
138 elms[1].matrix[1] = 3;
|
|
139 elms[1].matrix[3] = 5;
|
|
140
|
|
141 update_aggr_matrix(elms);
|
|
142
|
|
143 /* | -3 5 0 |
|
|
144 * | 5 1 0 |
|
|
145 * | 0 0 1 |
|
|
146 */
|
|
147 CU_ASSERT(elms[3].aggr_matrix[0] == -3);
|
|
148 CU_ASSERT(elms[3].aggr_matrix[1] == 5);
|
|
149 CU_ASSERT(elms[3].aggr_matrix[2] == 0);
|
|
150 CU_ASSERT(elms[3].aggr_matrix[3] == 5);
|
|
151 CU_ASSERT(elms[3].aggr_matrix[4] == 1);
|
|
152 CU_ASSERT(elms[3].aggr_matrix[5] == 0);
|
|
153
|
|
154 CU_ASSERT(elms[4].aggr_matrix[0] == -3);
|
|
155 CU_ASSERT(elms[4].aggr_matrix[1] == 5);
|
|
156 CU_ASSERT(elms[4].aggr_matrix[2] == 0);
|
|
157 CU_ASSERT(elms[4].aggr_matrix[3] == 5);
|
|
158 CU_ASSERT(elms[4].aggr_matrix[4] == 1);
|
|
159 CU_ASSERT(elms[4].aggr_matrix[5] == 0);
|
|
160
|
|
161 CU_ASSERT(elms[5].aggr_matrix[0] == 2);
|
|
162 CU_ASSERT(elms[5].aggr_matrix[1] == -1);
|
|
163 CU_ASSERT(elms[5].aggr_matrix[2] == 0);
|
|
164 CU_ASSERT(elms[5].aggr_matrix[3] == 0);
|
|
165 CU_ASSERT(elms[5].aggr_matrix[4] == 1);
|
|
166 CU_ASSERT(elms[5].aggr_matrix[5] == 0);
|
2
|
167
|
|
168 x = 50;
|
|
169 y = 99;
|
|
170 coord_trans_pos(elms + 5, &x, &y);
|
|
171 CU_ASSERT(x == 1);
|
|
172 CU_ASSERT(y == 99);
|
1
|
173 }
|
|
174
|
|
175 CU_pSuite get_coord_suite(void) {
|
|
176 CU_pSuite suite;
|
|
177
|
|
178 suite = CU_add_suite("Suite_coord", NULL, NULL);
|
|
179 CU_ADD_TEST(suite, test_update_aggr_matrix);
|
|
180
|
|
181 return suite;
|
|
182 }
|
|
183
|
|
184 #endif
|