1 | /* |
---|---|

2 | * Copyright 2006 The Android Open Source Project |

3 | * |

4 | * Use of this source code is governed by a BSD-style license that can be |

5 | * found in the LICENSE file. |

6 | */ |

7 | |

8 | #ifndef SkPoint_DEFINED |

9 | #define SkPoint_DEFINED |

10 | |

11 | #include "include/private/base/SkAPI.h" |

12 | #include "include/private/base/SkAssert.h" |

13 | #include "include/private/base/SkSafe32.h" |

14 | |

15 | #include <cmath> |

16 | #include <cstdint> |

17 | |

18 | struct SkIPoint; |

19 | |

20 | /** SkIVector provides an alternative name for SkIPoint. SkIVector and SkIPoint |

21 | can be used interchangeably for all purposes. |

22 | */ |

23 | typedef SkIPoint SkIVector; |

24 | |

25 | /** \struct SkIPoint |

26 | SkIPoint holds two 32-bit integer coordinates. |

27 | */ |

28 | struct SkIPoint { |

29 | int32_t fX; //!< x-axis value |

30 | int32_t fY; //!< y-axis value |

31 | |

32 | /** Sets fX to x, fY to y. |

33 | |

34 | @param x integer x-axis value of constructed SkIPoint |

35 | @param y integer y-axis value of constructed SkIPoint |

36 | @return SkIPoint (x, y) |

37 | */ |

38 | static constexpr SkIPoint Make(int32_t x, int32_t y) { |

39 | return {.fX: x, .fY: y}; |

40 | } |

41 | |

42 | /** Returns x-axis value of SkIPoint. |

43 | |

44 | @return fX |

45 | */ |

46 | constexpr int32_t x() const { return fX; } |

47 | |

48 | /** Returns y-axis value of SkIPoint. |

49 | |

50 | @return fY |

51 | */ |

52 | constexpr int32_t y() const { return fY; } |

53 | |

54 | /** Returns true if fX and fY are both zero. |

55 | |

56 | @return true if fX is zero and fY is zero |

57 | */ |

58 | bool isZero() const { return (fX | fY) == 0; } |

59 | |

60 | /** Sets fX to x and fY to y. |

61 | |

62 | @param x new value for fX |

63 | @param y new value for fY |

64 | */ |

65 | void set(int32_t x, int32_t y) { |

66 | fX = x; |

67 | fY = y; |

68 | } |

69 | |

70 | /** Returns SkIPoint changing the signs of fX and fY. |

71 | |

72 | @return SkIPoint as (-fX, -fY) |

73 | */ |

74 | SkIPoint operator-() const { |

75 | return {.fX: -fX, .fY: -fY}; |

76 | } |

77 | |

78 | /** Offsets SkIPoint by ivector v. Sets SkIPoint to (fX + v.fX, fY + v.fY). |

79 | |

80 | @param v ivector to add |

81 | */ |

82 | void operator+=(const SkIVector& v) { |

83 | fX = Sk32_sat_add(a: fX, b: v.fX); |

84 | fY = Sk32_sat_add(a: fY, b: v.fY); |

85 | } |

86 | |

87 | /** Subtracts ivector v from SkIPoint. Sets SkIPoint to: (fX - v.fX, fY - v.fY). |

88 | |

89 | @param v ivector to subtract |

90 | */ |

91 | void operator-=(const SkIVector& v) { |

92 | fX = Sk32_sat_sub(a: fX, b: v.fX); |

93 | fY = Sk32_sat_sub(a: fY, b: v.fY); |

94 | } |

95 | |

96 | /** Returns true if SkIPoint is equivalent to SkIPoint constructed from (x, y). |

97 | |

98 | @param x value compared with fX |

99 | @param y value compared with fY |

100 | @return true if SkIPoint equals (x, y) |

101 | */ |

102 | bool equals(int32_t x, int32_t y) const { |

103 | return fX == x && fY == y; |

104 | } |

105 | |

106 | /** Returns true if a is equivalent to b. |

107 | |

108 | @param a SkIPoint to compare |

109 | @param b SkIPoint to compare |

110 | @return true if a.fX == b.fX and a.fY == b.fY |

111 | */ |

112 | friend bool operator==(const SkIPoint& a, const SkIPoint& b) { |

113 | return a.fX == b.fX && a.fY == b.fY; |

114 | } |

115 | |

116 | /** Returns true if a is not equivalent to b. |

117 | |

118 | @param a SkIPoint to compare |

119 | @param b SkIPoint to compare |

120 | @return true if a.fX != b.fX or a.fY != b.fY |

121 | */ |

122 | friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { |

123 | return a.fX != b.fX || a.fY != b.fY; |

124 | } |

125 | |

126 | /** Returns ivector from b to a; computed as (a.fX - b.fX, a.fY - b.fY). |

127 | |

128 | Can also be used to subtract ivector from ivector, returning ivector. |

129 | |

130 | @param a SkIPoint or ivector to subtract from |

131 | @param b ivector to subtract |

132 | @return ivector from b to a |

133 | */ |

134 | friend SkIVector operator-(const SkIPoint& a, const SkIPoint& b) { |

135 | return { .fX: Sk32_sat_sub(a: a.fX, b: b.fX), .fY: Sk32_sat_sub(a: a.fY, b: b.fY) }; |

136 | } |

137 | |

138 | /** Returns SkIPoint resulting from SkIPoint a offset by ivector b, computed as: |

139 | (a.fX + b.fX, a.fY + b.fY). |

140 | |

141 | Can also be used to offset SkIPoint b by ivector a, returning SkIPoint. |

142 | Can also be used to add ivector to ivector, returning ivector. |

143 | |

144 | @param a SkIPoint or ivector to add to |

145 | @param b SkIPoint or ivector to add |

146 | @return SkIPoint equal to a offset by b |

147 | */ |

148 | friend SkIPoint operator+(const SkIPoint& a, const SkIVector& b) { |

149 | return { .fX: Sk32_sat_add(a: a.fX, b: b.fX), .fY: Sk32_sat_add(a: a.fY, b: b.fY) }; |

150 | } |

151 | }; |

152 | |

153 | struct SkPoint; |

154 | |

155 | /** SkVector provides an alternative name for SkPoint. SkVector and SkPoint can |

156 | be used interchangeably for all purposes. |

157 | */ |

158 | typedef SkPoint SkVector; |

159 | |

160 | /** \struct SkPoint |

161 | SkPoint holds two 32-bit floating point coordinates. |

162 | */ |

163 | struct SK_API SkPoint { |

164 | float fX; //!< x-axis value |

165 | float fY; //!< y-axis value |

166 | |

167 | /** Sets fX to x, fY to y. Used both to set SkPoint and vector. |

168 | |

169 | @param x float x-axis value of constructed SkPoint or vector |

170 | @param y float y-axis value of constructed SkPoint or vector |

171 | @return SkPoint (x, y) |

172 | */ |

173 | static constexpr SkPoint Make(float x, float y) { |

174 | return {.fX: x, .fY: y}; |

175 | } |

176 | |

177 | /** Returns x-axis value of SkPoint or vector. |

178 | |

179 | @return fX |

180 | */ |

181 | constexpr float x() const { return fX; } |

182 | |

183 | /** Returns y-axis value of SkPoint or vector. |

184 | |

185 | @return fY |

186 | */ |

187 | constexpr float y() const { return fY; } |

188 | |

189 | /** Returns true if fX and fY are both zero. |

190 | |

191 | @return true if fX is zero and fY is zero |

192 | */ |

193 | bool isZero() const { return (0 == fX) & (0 == fY); } |

194 | |

195 | /** Sets fX to x and fY to y. |

196 | |

197 | @param x new value for fX |

198 | @param y new value for fY |

199 | */ |

200 | void set(float x, float y) { |

201 | fX = x; |

202 | fY = y; |

203 | } |

204 | |

205 | /** Sets fX to x and fY to y, promoting integers to float values. |

206 | |

207 | Assigning a large integer value directly to fX or fY may cause a compiler |

208 | error, triggered by narrowing conversion of int to float. This safely |

209 | casts x and y to avoid the error. |

210 | |

211 | @param x new value for fX |

212 | @param y new value for fY |

213 | */ |

214 | void iset(int32_t x, int32_t y) { |

215 | fX = static_cast<float>(x); |

216 | fY = static_cast<float>(y); |

217 | } |

218 | |

219 | /** Sets fX to p.fX and fY to p.fY, promoting integers to float values. |

220 | |

221 | Assigning an SkIPoint containing a large integer value directly to fX or fY may |

222 | cause a compiler error, triggered by narrowing conversion of int to float. |

223 | This safely casts p.fX and p.fY to avoid the error. |

224 | |

225 | @param p SkIPoint members promoted to float |

226 | */ |

227 | void iset(const SkIPoint& p) { |

228 | fX = static_cast<float>(p.fX); |

229 | fY = static_cast<float>(p.fY); |

230 | } |

231 | |

232 | /** Sets fX to absolute value of pt.fX; and fY to absolute value of pt.fY. |

233 | |

234 | @param pt members providing magnitude for fX and fY |

235 | */ |

236 | void setAbs(const SkPoint& pt) { |

237 | fX = std::abs(lcpp_x: pt.fX); |

238 | fY = std::abs(lcpp_x: pt.fY); |

239 | } |

240 | |

241 | /** Adds offset to each SkPoint in points array with count entries. |

242 | |

243 | @param points SkPoint array |

244 | @param count entries in array |

245 | @param offset vector added to points |

246 | */ |

247 | static void Offset(SkPoint points[], int count, const SkVector& offset) { |

248 | Offset(points, count, dx: offset.fX, dy: offset.fY); |

249 | } |

250 | |

251 | /** Adds offset (dx, dy) to each SkPoint in points array of length count. |

252 | |

253 | @param points SkPoint array |

254 | @param count entries in array |

255 | @param dx added to fX in points |

256 | @param dy added to fY in points |

257 | */ |

258 | static void Offset(SkPoint points[], int count, float dx, float dy) { |

259 | for (int i = 0; i < count; ++i) { |

260 | points[i].offset(dx, dy); |

261 | } |

262 | } |

263 | |

264 | /** Adds offset (dx, dy) to SkPoint. |

265 | |

266 | @param dx added to fX |

267 | @param dy added to fY |

268 | */ |

269 | void offset(float dx, float dy) { |

270 | fX += dx; |

271 | fY += dy; |

272 | } |

273 | |

274 | /** Returns the Euclidean distance from origin, computed as: |

275 | |

276 | sqrt(fX * fX + fY * fY) |

277 | |

278 | . |

279 | |

280 | @return straight-line distance to origin |

281 | */ |

282 | float length() const { return SkPoint::Length(x: fX, y: fY); } |

283 | |

284 | /** Returns the Euclidean distance from origin, computed as: |

285 | |

286 | sqrt(fX * fX + fY * fY) |

287 | |

288 | . |

289 | |

290 | @return straight-line distance to origin |

291 | */ |

292 | float distanceToOrigin() const { return this->length(); } |

293 | |

294 | /** Scales (fX, fY) so that length() returns one, while preserving ratio of fX to fY, |

295 | if possible. If prior length is nearly zero, sets vector to (0, 0) and returns |

296 | false; otherwise returns true. |

297 | |

298 | @return true if former length is not zero or nearly zero |

299 | |

300 | example: https://fiddle.skia.org/c/@Point_normalize_2 |

301 | */ |

302 | bool normalize(); |

303 | |

304 | /** Sets vector to (x, y) scaled so length() returns one, and so that |

305 | (fX, fY) is proportional to (x, y). If (x, y) length is nearly zero, |

306 | sets vector to (0, 0) and returns false; otherwise returns true. |

307 | |

308 | @param x proportional value for fX |

309 | @param y proportional value for fY |

310 | @return true if (x, y) length is not zero or nearly zero |

311 | |

312 | example: https://fiddle.skia.org/c/@Point_setNormalize |

313 | */ |

314 | bool setNormalize(float x, float y); |

315 | |

316 | /** Scales vector so that distanceToOrigin() returns length, if possible. If former |

317 | length is nearly zero, sets vector to (0, 0) and return false; otherwise returns |

318 | true. |

319 | |

320 | @param length straight-line distance to origin |

321 | @return true if former length is not zero or nearly zero |

322 | |

323 | example: https://fiddle.skia.org/c/@Point_setLength |

324 | */ |

325 | bool setLength(float length); |

326 | |

327 | /** Sets vector to (x, y) scaled to length, if possible. If former |

328 | length is nearly zero, sets vector to (0, 0) and return false; otherwise returns |

329 | true. |

330 | |

331 | @param x proportional value for fX |

332 | @param y proportional value for fY |

333 | @param length straight-line distance to origin |

334 | @return true if (x, y) length is not zero or nearly zero |

335 | |

336 | example: https://fiddle.skia.org/c/@Point_setLength_2 |

337 | */ |

338 | bool setLength(float x, float y, float length); |

339 | |

340 | /** Sets dst to SkPoint times scale. dst may be SkPoint to modify SkPoint in place. |

341 | |

342 | @param scale factor to multiply SkPoint by |

343 | @param dst storage for scaled SkPoint |

344 | |

345 | example: https://fiddle.skia.org/c/@Point_scale |

346 | */ |

347 | void scale(float scale, SkPoint* dst) const; |

348 | |

349 | /** Scales SkPoint in place by scale. |

350 | |

351 | @param value factor to multiply SkPoint by |

352 | */ |

353 | void scale(float value) { this->scale(scale: value, dst: this); } |

354 | |

355 | /** Changes the sign of fX and fY. |

356 | */ |

357 | void negate() { |

358 | fX = -fX; |

359 | fY = -fY; |

360 | } |

361 | |

362 | /** Returns SkPoint changing the signs of fX and fY. |

363 | |

364 | @return SkPoint as (-fX, -fY) |

365 | */ |

366 | SkPoint operator-() const { |

367 | return {.fX: -fX, .fY: -fY}; |

368 | } |

369 | |

370 | /** Adds vector v to SkPoint. Sets SkPoint to: (fX + v.fX, fY + v.fY). |

371 | |

372 | @param v vector to add |

373 | */ |

374 | void operator+=(const SkVector& v) { |

375 | fX += v.fX; |

376 | fY += v.fY; |

377 | } |

378 | |

379 | /** Subtracts vector v from SkPoint. Sets SkPoint to: (fX - v.fX, fY - v.fY). |

380 | |

381 | @param v vector to subtract |

382 | */ |

383 | void operator-=(const SkVector& v) { |

384 | fX -= v.fX; |

385 | fY -= v.fY; |

386 | } |

387 | |

388 | /** Returns SkPoint multiplied by scale. |

389 | |

390 | @param scale float to multiply by |

391 | @return SkPoint as (fX * scale, fY * scale) |

392 | */ |

393 | SkPoint operator*(float scale) const { |

394 | return {.fX: fX * scale, .fY: fY * scale}; |

395 | } |

396 | |

397 | /** Multiplies SkPoint by scale. Sets SkPoint to: (fX * scale, fY * scale). |

398 | |

399 | @param scale float to multiply by |

400 | @return reference to SkPoint |

401 | */ |

402 | SkPoint& operator*=(float scale) { |

403 | fX *= scale; |

404 | fY *= scale; |

405 | return *this; |

406 | } |

407 | |

408 | /** Returns true if both fX and fY are measurable values. |

409 | |

410 | @return true for values other than infinities and NaN |

411 | */ |

412 | bool isFinite() const { |

413 | float accum = 0; |

414 | accum *= fX; |

415 | accum *= fY; |

416 | |

417 | // accum is either NaN or it is finite (zero). |

418 | SkASSERT(0 == accum || std::isnan(accum)); |

419 | |

420 | // value==value will be true iff value is not NaN |

421 | // TODO: is it faster to say !accum or accum==accum? |

422 | return !std::isnan(lcpp_x: accum); |

423 | } |

424 | |

425 | /** Returns true if SkPoint is equivalent to SkPoint constructed from (x, y). |

426 | |

427 | @param x value compared with fX |

428 | @param y value compared with fY |

429 | @return true if SkPoint equals (x, y) |

430 | */ |

431 | bool equals(float x, float y) const { |

432 | return fX == x && fY == y; |

433 | } |

434 | |

435 | /** Returns true if a is equivalent to b. |

436 | |

437 | @param a SkPoint to compare |

438 | @param b SkPoint to compare |

439 | @return true if a.fX == b.fX and a.fY == b.fY |

440 | */ |

441 | friend bool operator==(const SkPoint& a, const SkPoint& b) { |

442 | return a.fX == b.fX && a.fY == b.fY; |

443 | } |

444 | |

445 | /** Returns true if a is not equivalent to b. |

446 | |

447 | @param a SkPoint to compare |

448 | @param b SkPoint to compare |

449 | @return true if a.fX != b.fX or a.fY != b.fY |

450 | */ |

451 | friend bool operator!=(const SkPoint& a, const SkPoint& b) { |

452 | return a.fX != b.fX || a.fY != b.fY; |

453 | } |

454 | |

455 | /** Returns vector from b to a, computed as (a.fX - b.fX, a.fY - b.fY). |

456 | |

457 | Can also be used to subtract vector from SkPoint, returning SkPoint. |

458 | Can also be used to subtract vector from vector, returning vector. |

459 | |

460 | @param a SkPoint to subtract from |

461 | @param b SkPoint to subtract |

462 | @return vector from b to a |

463 | */ |

464 | friend SkVector operator-(const SkPoint& a, const SkPoint& b) { |

465 | return {.fX: a.fX - b.fX, .fY: a.fY - b.fY}; |

466 | } |

467 | |

468 | /** Returns SkPoint resulting from SkPoint a offset by vector b, computed as: |

469 | (a.fX + b.fX, a.fY + b.fY). |

470 | |

471 | Can also be used to offset SkPoint b by vector a, returning SkPoint. |

472 | Can also be used to add vector to vector, returning vector. |

473 | |

474 | @param a SkPoint or vector to add to |

475 | @param b SkPoint or vector to add |

476 | @return SkPoint equal to a offset by b |

477 | */ |

478 | friend SkPoint operator+(const SkPoint& a, const SkVector& b) { |

479 | return {.fX: a.fX + b.fX, .fY: a.fY + b.fY}; |

480 | } |

481 | |

482 | /** Returns the Euclidean distance from origin, computed as: |

483 | |

484 | sqrt(x * x + y * y) |

485 | |

486 | . |

487 | |

488 | @param x component of length |

489 | @param y component of length |

490 | @return straight-line distance to origin |

491 | |

492 | example: https://fiddle.skia.org/c/@Point_Length |

493 | */ |

494 | static float Length(float x, float y); |

495 | |

496 | /** Scales (vec->fX, vec->fY) so that length() returns one, while preserving ratio of vec->fX |

497 | to vec->fY, if possible. If original length is nearly zero, sets vec to (0, 0) and returns |

498 | zero; otherwise, returns length of vec before vec is scaled. |

499 | |

500 | Returned prior length may be INFINITY if it can not be represented by float. |

501 | |

502 | Note that normalize() is faster if prior length is not required. |

503 | |

504 | @param vec normalized to unit length |

505 | @return original vec length |

506 | |

507 | example: https://fiddle.skia.org/c/@Point_Normalize |

508 | */ |

509 | static float Normalize(SkVector* vec); |

510 | |

511 | /** Returns the Euclidean distance between a and b. |

512 | |

513 | @param a line end point |

514 | @param b line end point |

515 | @return straight-line distance from a to b |

516 | */ |

517 | static float Distance(const SkPoint& a, const SkPoint& b) { |

518 | return Length(x: a.fX - b.fX, y: a.fY - b.fY); |

519 | } |

520 | |

521 | /** Returns the dot product of vector a and vector b. |

522 | |

523 | @param a left side of dot product |

524 | @param b right side of dot product |

525 | @return product of input magnitudes and cosine of the angle between them |

526 | */ |

527 | static float DotProduct(const SkVector& a, const SkVector& b) { |

528 | return a.fX * b.fX + a.fY * b.fY; |

529 | } |

530 | |

531 | /** Returns the cross product of vector a and vector b. |

532 | |

533 | a and b form three-dimensional vectors with z-axis value equal to zero. The |

534 | cross product is a three-dimensional vector with x-axis and y-axis values equal |

535 | to zero. The cross product z-axis component is returned. |

536 | |

537 | @param a left side of cross product |

538 | @param b right side of cross product |

539 | @return area spanned by vectors signed by angle direction |

540 | */ |

541 | static float CrossProduct(const SkVector& a, const SkVector& b) { |

542 | return a.fX * b.fY - a.fY * b.fX; |

543 | } |

544 | |

545 | /** Returns the cross product of vector and vec. |

546 | |

547 | Vector and vec form three-dimensional vectors with z-axis value equal to zero. |

548 | The cross product is a three-dimensional vector with x-axis and y-axis values |

549 | equal to zero. The cross product z-axis component is returned. |

550 | |

551 | @param vec right side of cross product |

552 | @return area spanned by vectors signed by angle direction |

553 | */ |

554 | float cross(const SkVector& vec) const { |

555 | return CrossProduct(a: *this, b: vec); |

556 | } |

557 | |

558 | /** Returns the dot product of vector and vector vec. |

559 | |

560 | @param vec right side of dot product |

561 | @return product of input magnitudes and cosine of the angle between them |

562 | */ |

563 | float dot(const SkVector& vec) const { |

564 | return DotProduct(a: *this, b: vec); |

565 | } |

566 | |

567 | }; |

568 | |

569 | #endif |

570 |