| 302 | } |
| 303 | |
| 304 | Contour2f offsetOneDirectionContour( const Contour2f& cont, SingleOffset offset, const OffsetContoursParams& params, |
| 305 | int* shiftMap ) |
| 306 | { |
| 307 | MR_TIMER; |
| 308 | bool isClosed = cont.front() == cont.back(); |
| 309 | |
| 310 | auto contNorm = [&] ( int i ) |
| 311 | { |
| 312 | auto norm = cont[i + 1] - cont[i]; |
| 313 | std::swap( norm.x, norm.y ); |
| 314 | norm.x = -norm.x; |
| 315 | norm = norm.normalized(); |
| 316 | return norm; |
| 317 | }; |
| 318 | |
| 319 | Contour2f res; |
| 320 | res.reserve( 3 * cont.size() ); |
| 321 | if ( shiftMap ) |
| 322 | ++shiftMap[0]; |
| 323 | |
| 324 | res.emplace_back( isClosed ? |
| 325 | cont[0] + offset( 0 ) * contNorm( int( cont.size() ) - 2 ) : |
| 326 | cont[0] + offset( 0 ) * contNorm( 0 ) ); |
| 327 | |
| 328 | CornerParameters cParams; |
| 329 | int lastIndex = int( cont.size() ) - 2; |
| 330 | cParams.rc = isClosed ? cont[lastIndex] + offset( lastIndex ) * contNorm( lastIndex ) : res.back(); |
| 331 | cParams.rn = res.back(); |
| 332 | for ( int i = 0; i + 1 < cont.size(); ++i ) |
| 333 | { |
| 334 | auto norm = contNorm( i ); |
| 335 | auto iOffset = offset( i ); |
| 336 | auto iNextOffset = offset( i + 1 ); |
| 337 | |
| 338 | cParams.org = cont[i]; |
| 339 | cParams.lp = cParams.rc; |
| 340 | cParams.lc = cParams.rn; |
| 341 | cParams.rc = cParams.org + norm * iOffset; |
| 342 | cParams.rn = cont[i + 1] + norm * iNextOffset; |
| 343 | |
| 344 | if ( shiftMap && i > 0 ) |
| 345 | shiftMap[i] += shiftMap[i - 1]; |
| 346 | |
| 347 | // interpolation |
| 348 | cParams.lrAng = findAngle( cParams.lc, cParams.org, cParams.rc ); |
| 349 | bool sameAsPrev = std::abs( cParams.lrAng ) < PI_F / 360.0f; |
| 350 | if ( !sameAsPrev ) |
| 351 | { |
| 352 | bool needCorner = ( cParams.lrAng * iOffset ) < 0.0f; |
| 353 | if ( needCorner ) |
| 354 | { |
| 355 | if ( params.cornerType == OffsetContoursParams::CornerType::Round ) |
| 356 | { |
| 357 | insertRoundCorner( res, cParams, params.minAnglePrecision, shiftMap ? &shiftMap[i] : nullptr ); |
| 358 | } |
| 359 | else if ( params.cornerType == OffsetContoursParams::CornerType::Sharp ) |
| 360 | { |
| 361 | insertSharpCorner( res, cParams, params.maxSharpAngle, shiftMap ? &shiftMap[i] : nullptr ); |
no test coverage detected