| | 136 | template <typename Transform,typename Geometry> struct MAPNIK_DECL coord_transform4 { |
| | 137 | |
| | 138 | /** |
| | 139 | * Creates a new coord_transform4. |
| | 140 | */ |
| | 141 | coord_transform4(Transform const& t, Geometry const& geom, proj_transform const& prj_trans ) |
| | 142 | : t_(t), |
| | 143 | geom_(geom), |
| | 144 | prj_trans_(prj_trans), |
| | 145 | offset_(0.0), |
| | 146 | m_status(initial) {} |
| | 147 | |
| | 148 | // Enum representing the status or the tranformation process. |
| | 149 | enum status |
| | 150 | { |
| | 151 | initial, |
| | 152 | start, |
| | 153 | first, |
| | 154 | process, |
| | 155 | last_vertex, |
| | 156 | angle_joint, |
| | 157 | end |
| | 158 | }; |
| | 159 | |
| | 160 | double get_offset() const |
| | 161 | { |
| | 162 | return offset_; |
| | 163 | } |
| | 164 | |
| | 165 | void set_offset(double offset) |
| | 166 | { |
| | 167 | offset_ = offset; |
| | 168 | } |
| | 169 | |
| | 170 | bool is_acute(double x0,double y0,double x1,double y1,double x2,double y2) |
| | 171 | { |
| | 172 | double dx0 = x0 - x1; |
| | 173 | double dy0 = y0 - y1; |
| | 174 | double dx1 = x2 - x1; |
| | 175 | double dy1 = y2 - y1; |
| | 176 | double product = dx0 * dx1 + dy0 * dy1; |
| | 177 | return product > 0; |
| | 178 | } |
| | 179 | |
| | 180 | /** |
| | 181 | * Reads the x and y values of the next vertex and assigns the |
| | 182 | * values of the locations of the x and y parameters to them. |
| | 183 | * Returns the next command associated with the vertex based |
| | 184 | * from where in the line the point is read. |
| | 185 | */ |
| | 186 | /* |
| | 187 | * Basically copied out of mapservers line offset algorithm |
| | 188 | * (msOffsetPolyline). |
| | 189 | */ |
| | 190 | unsigned vertex(double * x , double * y) |
| | 191 | { |
| | 192 | double z=0; |
| | 193 | |
| | 194 | if (offset_==0.0) |
| | 195 | { |
| | 196 | unsigned command = geom_.vertex(x,y); |
| | 197 | prj_trans_.backward(*x,*y,z); |
| | 198 | t_.forward(x,y); |
| | 199 | return command; |
| | 200 | } |
| | 201 | else |
| | 202 | { |
| | 203 | while(true){ |
| | 204 | switch(m_status) |
| | 205 | { |
| | 206 | case end: |
| | 207 | return SEG_END; |
| | 208 | break; |
| | 209 | case initial: |
| | 210 | m_pre_cmd = geom_.vertex(x,y); |
| | 211 | prj_trans_.backward(*x,*y,z); |
| | 212 | t_.forward(x,y); |
| | 213 | m_pre_x = *x; |
| | 214 | m_pre_y = *y; |
| | 215 | case start: |
| | 216 | m_cur_cmd = geom_.vertex(&m_cur_x, &m_cur_y); |
| | 217 | prj_trans_.backward(m_cur_x,m_cur_y,z); |
| | 218 | t_.forward(&m_cur_x,&m_cur_y); |
| | 219 | case first: |
| | 220 | angle_a = atan2((m_pre_y-m_cur_y),(m_pre_x-m_cur_x)); |
| | 221 | dx_pre = cos(angle_a + M_PI/2); |
| | 222 | dy_pre = sin(angle_a + M_PI/2); |
| | 223 | #ifdef MAPNIK_DEBUG |
| | 224 | std::clog << "offsetting line by: " << offset_ << "\n"; |
| | 225 | std::clog << "initial dx=" << (dx_pre * offset_) << " dy=" << (dy_pre * offset_) << "\n"; |
| | 226 | #endif |
| | 227 | *x = m_pre_x + (dx_pre * offset_); |
| | 228 | *y = m_pre_y + (dy_pre * offset_); |
| | 229 | m_status = process; |
| | 230 | return SEG_MOVETO; |
| | 231 | case process: |
| | 232 | switch(m_cur_cmd) |
| | 233 | { |
| | 234 | case SEG_LINETO: |
| | 235 | m_next_cmd = geom_.vertex(&m_next_x, &m_next_y); |
| | 236 | prj_trans_.backward(m_next_x,m_next_y,z); |
| | 237 | t_.forward(&m_next_x,&m_next_y); |
| | 238 | switch(m_next_cmd) |
| | 239 | { |
| | 240 | case SEG_LINETO: |
| | 241 | m_status = angle_joint; |
| | 242 | break; |
| | 243 | default: |
| | 244 | m_status = last_vertex; |
| | 245 | break; |
| | 246 | } |
| | 247 | break; |
| | 248 | case SEG_END: |
| | 249 | m_status = end; |
| | 250 | return SEG_END; |
| | 251 | } |
| | 252 | break; |
| | 253 | case last_vertex: |
| | 254 | dx_curr = cos(angle_a + M_PI/2); |
| | 255 | dy_curr = sin(angle_a + M_PI/2); |
| | 256 | *x = m_cur_x + (dx_curr * offset_); |
| | 257 | *y = m_cur_y + (dy_curr * offset_); |
| | 258 | m_status = end; |
| | 259 | return m_cur_cmd; |
| | 260 | case angle_joint: |
| | 261 | dx_curr = cos(angle_a + M_PI/2); |
| | 262 | dy_curr = sin(angle_a + M_PI/2); |
| | 263 | |
| | 264 | sin_curve = dx_curr*dy_pre-dy_curr*dx_pre; |
| | 265 | cos_curve = -dx_pre*dx_curr-dy_pre*dy_curr; |
| | 266 | |
| | 267 | #ifdef MAPNIK_DEBUG |
| | 268 | std::clog << "sin_curve value: " << sin_curve << "\n"; |
| | 269 | #endif |
| | 270 | if(-0.3 < sin_curve && sin_curve < 0.3) { |
| | 271 | angle_b = atan2((m_cur_y-m_next_y),(m_cur_x-m_next_x)); |
| | 272 | h = tan((angle_b - angle_a)/2.0); |
| | 273 | *x = m_cur_x + dx_curr * offset_ - h * dy_curr * offset_; |
| | 274 | *y = m_cur_y + dy_curr * offset_ + h * dx_curr * offset_; |
| | 275 | } else { |
| | 276 | base_shift = -1.0*(1.0+cos_curve)/sin_curve; |
| | 277 | *x = m_cur_x + (dx_curr + base_shift*dy_curr)*offset_; |
| | 278 | *y = m_cur_y + (dy_curr - base_shift*dx_curr)*offset_; |
| | 279 | } |
| | 280 | |
| | 281 | // Save old shit |
| | 282 | m_cur_x = m_next_x; |
| | 283 | m_cur_y = m_next_y; |
| | 284 | angle_a = angle_b; |
| | 285 | m_pre_cmd = m_cur_cmd; |
| | 286 | m_cur_cmd = m_next_cmd; |
| | 287 | m_status = process; |
| | 288 | return m_pre_cmd; |
| | 289 | } |
| | 290 | } |
| | 291 | } |
| | 292 | } |
| | 293 | |
| | 294 | void rewind (unsigned pos) |
| | 295 | { |
| | 296 | geom_.rewind(pos); |
| | 297 | m_status = initial; |
| | 298 | } |
| | 299 | |
| | 300 | private: |
| | 301 | Transform const& t_; |
| | 302 | Geometry const& geom_; |
| | 303 | proj_transform const& prj_trans_; |
| | 304 | int offset_; |
| | 305 | double dx_pre; |
| | 306 | double dy_pre; |
| | 307 | double dx_curr; |
| | 308 | double dy_curr; |
| | 309 | double base_shift; |
| | 310 | double sin_curve; |
| | 311 | double cos_curve; |
| | 312 | double angle_a; |
| | 313 | double angle_b; |
| | 314 | double h; |
| | 315 | // processing state |
| | 316 | status m_status; |
| | 317 | // source vertex lookahead queue |
| | 318 | unsigned m_pre_cmd; |
| | 319 | double m_pre_x; |
| | 320 | double m_pre_y; |
| | 321 | unsigned m_cur_cmd; |
| | 322 | double m_cur_x; |
| | 323 | double m_cur_y; |
| | 324 | unsigned m_next_cmd; |
| | 325 | double m_next_x; |
| | 326 | double m_next_y; |
| | 327 | |
| | 328 | |
| | 329 | |
| | 330 | }; |
| | 331 | |