RDKit
Open-source cheminformatics and machine learning.
Loading...
Searching...
No Matches
point.h
Go to the documentation of this file.
1//
2// Copyright (C) 2003-2025 Greg Landrum and other RDKit contributors
3//
4// @@ All Rights Reserved @@
5// This file is part of the RDKit.
6// The contents are covered by the terms of the BSD license
7// which is included in the file license.txt, found at the root
8// of the RDKit source tree.
9//
10
11#include <RDGeneral/export.h>
12#ifndef RD_POINT_H
13#define RD_POINT_H
14#include <cmath>
15#include <vector>
16#include <map>
17
18#ifndef M_PI
19#define M_PI 3.14159265358979323846
20#endif
21
22#include <RDGeneral/Invariant.h>
23#include <Numerics/Vector.h>
24#include <boost/smart_ptr.hpp>
25
26namespace RDGeom {
27
29 // this is the virtual base class, mandating certain functions
30 public:
31 constexpr virtual ~Point() {}
32
33 virtual double operator[](unsigned int i) const = 0;
34 virtual double &operator[](unsigned int i) = 0;
35
36 virtual void normalize() = 0;
37 virtual double length() const = 0;
38 virtual double lengthSq() const = 0;
39 virtual unsigned int dimension() const = 0;
40
41 [[nodiscard]] virtual Point *copy() const = 0;
42};
43#ifndef _MSC_VER
44// g++ (at least as of v9.3.0) generates some spurious warnings from here.
45// disable them
46#if !defined(__clang__) && defined(__GNUC__)
47#pragma GCC diagnostic push
48#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
49#endif
50#endif
51
52// typedef class Point3D Point;
54 public:
55 double x{0.0};
56 double y{0.0};
57 double z{0.0};
58
59 constexpr Point3D() {}
60 constexpr Point3D(double xv, double yv, double zv) : x(xv), y(yv), z(zv) {}
61
62 constexpr ~Point3D() override {};
63
64 constexpr Point3D(const Point3D &other)
65 : Point(other), x(other.x), y(other.y), z(other.z) {}
66
67 [[nodiscard]] constexpr Point *copy() const override {
68 return new Point3D(*this);
69 }
70
71 constexpr unsigned int dimension() const override { return 3; }
72
73 constexpr double operator[](unsigned int i) const override {
74 switch (i) {
75 case 0:
76 return x;
77 case 1:
78 return y;
79 case 2:
80 return z;
81 default:
82 throw ValueErrorException("Invalid index on Point3D");
83 break;
84 }
85 }
86
87 constexpr double &operator[](unsigned int i) override {
88 switch (i) {
89 case 0:
90 return x;
91 case 1:
92 return y;
93 case 2:
94 return z;
95 default:
96 throw ValueErrorException("Invalid index on Point3D");
97 break;
98 }
99 }
100
101 constexpr Point3D &operator=(const Point3D &other) {
102 if (&other == this) {
103 return *this;
104 }
105 x = other.x;
106 y = other.y;
107 z = other.z;
108 return *this;
109 }
110
111 constexpr Point3D &operator+=(const Point3D &other) {
112 x += other.x;
113 y += other.y;
114 z += other.z;
115 return *this;
116 }
117
118 constexpr Point3D &operator-=(const Point3D &other) {
119 x -= other.x;
120 y -= other.y;
121 z -= other.z;
122 return *this;
123 }
124
125 constexpr Point3D &operator*=(double scale) {
126 x *= scale;
127 y *= scale;
128 z *= scale;
129 return *this;
130 }
131
132 constexpr Point3D &operator/=(double scale) {
133 x /= scale;
134 y /= scale;
135 z /= scale;
136 return *this;
137 }
138
139 constexpr Point3D operator-() const {
140 Point3D res(x, y, z);
141 res.x *= -1.0;
142 res.y *= -1.0;
143 res.z *= -1.0;
144 return res;
145 }
146
147 constexpr void normalize() override {
148 double l = this->length();
149 if (l < zero_tolerance) {
150 throw std::runtime_error("Cannot normalize a zero length vector");
151 }
152
153 x /= l;
154 y /= l;
155 z /= l;
156 }
157
158 double length() const override {
159 double res = x * x + y * y + z * z;
160 return sqrt(res);
161 }
162
163 constexpr double lengthSq() const override {
164 // double res = pow(x,2) + pow(y,2) + pow(z,2);
165 double res = x * x + y * y + z * z;
166 return res;
167 }
168
169 constexpr double dotProduct(const Point3D &other) const {
170 double res = x * (other.x) + y * (other.y) + z * (other.z);
171 return res;
172 }
173
174 /*! \brief determines the angle between a vector to this point
175 * from the origin and a vector to the other point.
176 *
177 * The angle is unsigned: the results of this call will always
178 * be between 0 and M_PI
179 */
180 double angleTo(const Point3D &other) const {
181 double lsq = lengthSq() * other.lengthSq();
182 double dotProd = dotProduct(other);
183 dotProd /= sqrt(lsq);
184
185 // watch for roundoff error:
186 if (dotProd <= -1.0) {
187 return M_PI;
188 }
189 if (dotProd >= 1.0) {
190 return 0.0;
191 }
192
193 return acos(dotProd);
194 }
195
196 /*! \brief determines the signed angle between a vector to this point
197 * from the origin and a vector to the other point.
198 *
199 * The results of this call will be between 0 and M_2_PI
200 */
201 double signedAngleTo(const Point3D &other) const {
202 double res = this->angleTo(other);
203 // check the sign of the z component of the cross product:
204 if ((this->x * other.y - this->y * other.x) < -zero_tolerance) {
205 res = 2.0 * M_PI - res;
206 }
207 return res;
208 }
209
210 /*! \brief Returns a normalized direction vector from this
211 * point to another.
212 *
213 */
214 Point3D directionVector(const Point3D &other) const {
215 Point3D res;
216 res.x = other.x - x;
217 res.y = other.y - y;
218 res.z = other.z - z;
219 res.normalize();
220 return res;
221 }
222
223 /*! \brief Cross product of this point with the another point
224 *
225 * The order is important here
226 * The result is "this" cross with "other" not (other x this)
227 */
228 constexpr Point3D crossProduct(const Point3D &other) const {
229 Point3D res;
230 res.x = y * (other.z) - z * (other.y);
231 res.y = -x * (other.z) + z * (other.x);
232 res.z = x * (other.y) - y * (other.x);
233 return res;
234 }
235
236 /*! \brief Get a unit perpendicular from this point (treating it as a vector):
237 *
238 */
240 Point3D res(0.0, 0.0, 0.0);
241 if (x) {
242 if (y) {
243 res.y = -1 * x;
244 res.x = y;
245 } else if (z) {
246 res.z = -1 * x;
247 res.x = z;
248 } else {
249 res.y = 1;
250 }
251 } else if (y) {
252 if (z) {
253 res.z = -1 * y;
254 res.y = z;
255 } else {
256 res.x = 1;
257 }
258 } else if (z) {
259 res.x = 1;
260 }
261 double l = res.length();
262 res /= l;
263 return res;
264 }
265};
266
267// given a set of four pts in 3D compute the dihedral angle between the
268// plane of the first three points (pt1, pt2, pt3) and the plane of the
269// last three points (pt2, pt3, pt4)
270// the computed angle is between 0 and PI
272 const Point3D &pt2,
273 const Point3D &pt3,
274 const Point3D &pt4);
275
276// given a set of four pts in 3D compute the signed dihedral angle between the
277// plane of the first three points (pt1, pt2, pt3) and the plane of the
278// last three points (pt2, pt3, pt4)
279// the computed angle is between -PI and PI
281 const Point3D &pt1, const Point3D &pt2, const Point3D &pt3,
282 const Point3D &pt4);
283
285 public:
286 double x{0.0};
287 double y{0.0};
288
289 constexpr Point2D() {}
290 constexpr Point2D(double xv, double yv) : x(xv), y(yv) {}
291 constexpr ~Point2D() override {};
292
293 constexpr Point2D(const Point2D &other)
294 : Point(other), x(other.x), y(other.y) {}
295 //! construct from a Point3D (ignoring the z coordinate)
296 constexpr Point2D(const Point3D &p3d) : Point(p3d), x(p3d.x), y(p3d.y) {}
297
298 [[nodiscard]] constexpr Point *copy() const override {
299 return new Point2D(*this);
300 }
301
302 constexpr unsigned int dimension() const override { return 2; }
303
304 constexpr double operator[](unsigned int i) const override {
305 switch (i) {
306 case 0:
307 return x;
308 case 1:
309 return y;
310 default:
311 throw ValueErrorException("Invalid index on Point2D");
312 break;
313 }
314 }
315
316 constexpr double &operator[](unsigned int i) override {
317 switch (i) {
318 case 0:
319 return x;
320 case 1:
321 return y;
322 default:
323 throw ValueErrorException("Invalid index on Point2D");
324 break;
325 }
326 }
327
328 constexpr Point2D &operator=(const Point2D &other) {
329 x = other.x;
330 y = other.y;
331 return *this;
332 }
333
334 constexpr Point2D &operator+=(const Point2D &other) {
335 x += other.x;
336 y += other.y;
337 return *this;
338 }
339
340 constexpr Point2D &operator-=(const Point2D &other) {
341 x -= other.x;
342 y -= other.y;
343 return *this;
344 }
345
346 constexpr Point2D &operator*=(double scale) {
347 x *= scale;
348 y *= scale;
349 return *this;
350 }
351
352 constexpr Point2D &operator/=(double scale) {
353 x /= scale;
354 y /= scale;
355 return *this;
356 }
357
358 constexpr Point2D operator-() const {
359 Point2D res(x, y);
360 res.x *= -1.0;
361 res.y *= -1.0;
362 return res;
363 }
364
365 void normalize() override {
366 double ln = this->length();
367 if (ln < zero_tolerance) {
368 throw std::runtime_error("Cannot normalize a zero length vector");
369 }
370
371 x /= ln;
372 y /= ln;
373 }
374
375 constexpr void rotate90() {
376 double temp = x;
377 x = -y;
378 y = temp;
379 }
380
381 double length() const override {
382 // double res = pow(x,2) + pow(y,2);
383 double res = x * x + y * y;
384 return sqrt(res);
385 }
386
387 constexpr double lengthSq() const override {
388 double res = x * x + y * y;
389 return res;
390 }
391
392 constexpr double dotProduct(const Point2D &other) const {
393 double res = x * (other.x) + y * (other.y);
394 return res;
395 }
396
397 double angleTo(const Point2D &other) const {
398 auto t1 = *this;
399 auto t2 = other;
400 t1.normalize();
401 t2.normalize();
402 double dotProd = t1.dotProduct(t2);
403 // watch for roundoff error:
404 if (dotProd < -1.0) {
405 dotProd = -1.0;
406 } else if (dotProd > 1.0) {
407 dotProd = 1.0;
408 }
409 return acos(dotProd);
410 }
411
412 double signedAngleTo(const Point2D &other) const {
413 double res = this->angleTo(other);
414 if ((this->x * other.y - this->y * other.x) < -zero_tolerance) {
415 res = 2.0 * M_PI - res;
416 }
417 return res;
418 }
419
420 Point2D directionVector(const Point2D &other) const {
421 Point2D res;
422 res.x = other.x - x;
423 res.y = other.y - y;
424 res.normalize();
425 return res;
426 }
427};
428
430 public:
431 typedef boost::shared_ptr<RDNumeric::Vector<double>> VECT_SH_PTR;
432
433 PointND(unsigned int dim) {
435 dp_storage.reset(nvec);
436 }
437
438 PointND(const PointND &other) : Point(other) {
440 new RDNumeric::Vector<double>(*other.getStorage());
441 dp_storage.reset(nvec);
442 }
443
444 Point *copy() const override { return new PointND(*this); }
445
446 ~PointND() override = default;
447
448 inline double operator[](unsigned int i) const override {
449 return dp_storage.get()->getVal(i);
450 }
451
452 inline double &operator[](unsigned int i) override {
453 return (*dp_storage.get())[i];
454 }
455
456 inline void normalize() override { dp_storage.get()->normalize(); }
457
458 inline double length() const override { return dp_storage.get()->normL2(); }
459
460 inline double lengthSq() const override {
461 return dp_storage.get()->normL2Sq();
462 }
463
464 unsigned int dimension() const override { return dp_storage.get()->size(); }
465
466 PointND &operator=(const PointND &other) {
467 if (this == &other) {
468 return *this;
469 }
470
472 new RDNumeric::Vector<double>(*other.getStorage());
473 dp_storage.reset(nvec);
474 return *this;
475 }
476
477 PointND &operator+=(const PointND &other) {
478 (*dp_storage.get()) += (*other.getStorage());
479 return *this;
480 }
481
482 PointND &operator-=(const PointND &other) {
483 (*dp_storage.get()) -= (*other.getStorage());
484 return *this;
485 }
486
487 PointND &operator*=(double scale) {
488 (*dp_storage.get()) *= scale;
489 return *this;
490 }
491
492 PointND &operator/=(double scale) {
493 (*dp_storage.get()) /= scale;
494 return *this;
495 }
496
498 PRECONDITION(this->dimension() == other.dimension(),
499 "Point dimensions do not match");
500 PointND np(other);
501 np -= (*this);
502 np.normalize();
503 return np;
504 }
505
506 double dotProduct(const PointND &other) const {
507 return dp_storage.get()->dotProduct(*other.getStorage());
508 }
509
510 double angleTo(const PointND &other) const {
511 double dp = this->dotProduct(other);
512 double n1 = this->length();
513 double n2 = other.length();
514 if ((n1 > 1.e-8) && (n2 > 1.e-8)) {
515 dp /= (n1 * n2);
516 }
517 if (dp < -1.0) {
518 dp = -1.0;
519 } else if (dp > 1.0) {
520 dp = 1.0;
521 }
522 return acos(dp);
523 }
524
525 private:
526 VECT_SH_PTR dp_storage;
527 inline const RDNumeric::Vector<double> *getStorage() const {
528 return dp_storage.get();
529 }
530};
531#ifndef _MSC_VER
532#if !defined(__clang__) && defined(__GNUC__)
533#pragma GCC diagnostic pop
534#endif
535#endif
536
537typedef std::vector<RDGeom::Point *> PointPtrVect;
538typedef PointPtrVect::iterator PointPtrVect_I;
539typedef PointPtrVect::const_iterator PointPtrVect_CI;
540
541typedef std::vector<RDGeom::Point3D *> Point3DPtrVect;
542typedef std::vector<RDGeom::Point2D *> Point2DPtrVect;
543typedef Point3DPtrVect::iterator Point3DPtrVect_I;
544typedef Point3DPtrVect::const_iterator Point3DPtrVect_CI;
545typedef Point2DPtrVect::iterator Point2DPtrVect_I;
546typedef Point2DPtrVect::const_iterator Point2DPtrVect_CI;
547
548typedef std::vector<const RDGeom::Point3D *> Point3DConstPtrVect;
549typedef Point3DConstPtrVect::iterator Point3DConstPtrVect_I;
550typedef Point3DConstPtrVect::const_iterator Point3DConstPtrVect_CI;
551
552typedef std::vector<Point3D> POINT3D_VECT;
553typedef std::vector<Point3D>::iterator POINT3D_VECT_I;
554typedef std::vector<Point3D>::const_iterator POINT3D_VECT_CI;
555
556typedef std::map<int, Point2D> INT_POINT2D_MAP;
557typedef INT_POINT2D_MAP::iterator INT_POINT2D_MAP_I;
558typedef INT_POINT2D_MAP::const_iterator INT_POINT2D_MAP_CI;
559
560RDKIT_RDGEOMETRYLIB_EXPORT std::ostream &operator<<(std::ostream &target,
561 const RDGeom::Point &pt);
562
564 const RDGeom::Point3D &p2);
566 const RDGeom::Point3D &p2);
568 double v);
570 double v);
571
573 const RDGeom::Point2D &p2);
575 const RDGeom::Point2D &p2);
577 double v);
579 double v);
580
582 const RDGeom::PointND &p2);
584 const RDGeom::PointND &p2);
586 double v);
588 double v);
589} // namespace RDGeom
590
591#endif
#define PRECONDITION(expr, mess)
Definition Invariant.h:108
#define M_PI
Definition MMFF/Params.h:25
static constexpr double zero_tolerance
Definition Vector.h:24
constexpr Point2D()
Definition point.h:289
constexpr Point2D operator-() const
Definition point.h:358
constexpr double dotProduct(const Point2D &other) const
Definition point.h:392
Point2D directionVector(const Point2D &other) const
Definition point.h:420
constexpr Point * copy() const override
Definition point.h:298
constexpr Point2D(const Point3D &p3d)
construct from a Point3D (ignoring the z coordinate)
Definition point.h:296
constexpr Point2D()
Definition point.h:289
constexpr Point2D & operator=(const Point2D &other)
Definition point.h:328
constexpr ~Point2D() override
Definition point.h:291
constexpr Point2D(const Point2D &other)
Definition point.h:293
constexpr Point2D & operator-=(const Point2D &other)
Definition point.h:340
constexpr Point2D & operator*=(double scale)
Definition point.h:346
constexpr Point2D & operator/=(double scale)
Definition point.h:352
constexpr Point2D(double xv, double yv)
Definition point.h:290
constexpr Point2D & operator+=(const Point2D &other)
Definition point.h:334
constexpr double lengthSq() const override
Definition point.h:387
constexpr double & operator[](unsigned int i) override
Definition point.h:316
void normalize() override
Definition point.h:365
constexpr double operator[](unsigned int i) const override
Definition point.h:304
constexpr unsigned int dimension() const override
Definition point.h:302
double length() const override
Definition point.h:381
constexpr void rotate90()
Definition point.h:375
double signedAngleTo(const Point2D &other) const
Definition point.h:412
double angleTo(const Point2D &other) const
Definition point.h:397
constexpr Point3D & operator+=(const Point3D &other)
Definition point.h:111
constexpr Point3D & operator-=(const Point3D &other)
Definition point.h:118
constexpr Point3D & operator/=(double scale)
Definition point.h:132
constexpr Point3D(double xv, double yv, double zv)
Definition point.h:60
double signedAngleTo(const Point3D &other) const
determines the signed angle between a vector to this point from the origin and a vector to the other ...
Definition point.h:201
double angleTo(const Point3D &other) const
determines the angle between a vector to this point from the origin and a vector to the other point.
Definition point.h:180
constexpr ~Point3D() override
Definition point.h:62
constexpr double & operator[](unsigned int i) override
Definition point.h:87
constexpr Point * copy() const override
Definition point.h:67
double length() const override
Definition point.h:158
constexpr Point3D(const Point3D &other)
Definition point.h:64
constexpr double lengthSq() const override
Definition point.h:163
double y
Definition point.h:56
double x
Definition point.h:55
double z
Definition point.h:57
constexpr Point3D & operator=(const Point3D &other)
Definition point.h:101
constexpr Point3D operator-() const
Definition point.h:139
constexpr unsigned int dimension() const override
Definition point.h:71
constexpr Point3D & operator*=(double scale)
Definition point.h:125
constexpr Point3D crossProduct(const Point3D &other) const
Cross product of this point with the another point.
Definition point.h:228
constexpr double dotProduct(const Point3D &other) const
Definition point.h:169
Point3D directionVector(const Point3D &other) const
Returns a normalized direction vector from this point to another.
Definition point.h:214
constexpr Point3D()
Definition point.h:59
constexpr double operator[](unsigned int i) const override
Definition point.h:73
constexpr void normalize() override
Definition point.h:147
Point3D getPerpendicular() const
Get a unit perpendicular from this point (treating it as a vector):
Definition point.h:239
PointND & operator+=(const PointND &other)
Definition point.h:477
PointND & operator/=(double scale)
Definition point.h:492
double & operator[](unsigned int i) override
Definition point.h:452
double length() const override
Definition point.h:458
unsigned int dimension() const override
Definition point.h:464
boost::shared_ptr< RDNumeric::Vector< double > > VECT_SH_PTR
Definition point.h:431
double dotProduct(const PointND &other) const
Definition point.h:506
~PointND() override=default
PointND & operator=(const PointND &other)
Definition point.h:466
double lengthSq() const override
Definition point.h:460
PointND(const PointND &other)
Definition point.h:438
void normalize() override
Definition point.h:456
double angleTo(const PointND &other) const
Definition point.h:510
PointND & operator*=(double scale)
Definition point.h:487
PointND & operator-=(const PointND &other)
Definition point.h:482
double operator[](unsigned int i) const override
Definition point.h:448
Point * copy() const override
Definition point.h:444
PointND(unsigned int dim)
Definition point.h:433
PointND directionVector(const PointND &other)
Definition point.h:497
virtual double lengthSq() const =0
virtual Point * copy() const =0
virtual double length() const =0
virtual void normalize()=0
virtual unsigned int dimension() const =0
virtual constexpr ~Point()
Definition point.h:31
virtual double operator[](unsigned int i) const =0
virtual double & operator[](unsigned int i)=0
A class to represent vectors of numbers.
Definition Vector.h:30
Class to allow us to throw a ValueError from C++ and have it make it back to Python.
Definition Exceptions.h:40
#define RDKIT_RDGEOMETRYLIB_EXPORT
Definition export.h:449
Point3DPtrVect::iterator Point3DPtrVect_I
Definition point.h:543
std::vector< RDGeom::Point * > PointPtrVect
Definition point.h:537
RDKIT_RDGEOMETRYLIB_EXPORT RDGeom::Point3D operator/(const RDGeom::Point3D &p1, double v)
PointPtrVect::const_iterator PointPtrVect_CI
Definition point.h:539
std::vector< const RDGeom::Point3D * > Point3DConstPtrVect
Definition point.h:548
std::map< int, Point2D > INT_POINT2D_MAP
Definition point.h:556
RDKIT_RDGEOMETRYLIB_EXPORT RDGeom::Point3D operator*(const RDGeom::Point3D &p1, double v)
Point3DConstPtrVect::iterator Point3DConstPtrVect_I
Definition point.h:549
std::vector< Point3D >::iterator POINT3D_VECT_I
Definition point.h:553
Point3DPtrVect::const_iterator Point3DPtrVect_CI
Definition point.h:544
std::vector< RDGeom::Point3D * > Point3DPtrVect
Definition point.h:541
RDKIT_RDGEOMETRYLIB_EXPORT RDGeom::Point3D operator-(const RDGeom::Point3D &p1, const RDGeom::Point3D &p2)
Point3DConstPtrVect::const_iterator Point3DConstPtrVect_CI
Definition point.h:550
Point2DPtrVect::iterator Point2DPtrVect_I
Definition point.h:545
RDKIT_RDGEOMETRYLIB_EXPORT std::ostream & operator<<(std::ostream &target, const RDGeom::Point &pt)
INT_POINT2D_MAP::const_iterator INT_POINT2D_MAP_CI
Definition point.h:558
RDKIT_RDGEOMETRYLIB_EXPORT double computeDihedralAngle(const Point3D &pt1, const Point3D &pt2, const Point3D &pt3, const Point3D &pt4)
std::vector< Point3D >::const_iterator POINT3D_VECT_CI
Definition point.h:554
INT_POINT2D_MAP::iterator INT_POINT2D_MAP_I
Definition point.h:557
std::vector< RDGeom::Point2D * > Point2DPtrVect
Definition point.h:542
Point2DPtrVect::const_iterator Point2DPtrVect_CI
Definition point.h:546
std::vector< Point3D > POINT3D_VECT
Definition point.h:552
RDKIT_RDGEOMETRYLIB_EXPORT double computeSignedDihedralAngle(const Point3D &pt1, const Point3D &pt2, const Point3D &pt3, const Point3D &pt4)
RDKIT_RDGEOMETRYLIB_EXPORT RDGeom::Point3D operator+(const RDGeom::Point3D &p1, const RDGeom::Point3D &p2)
PointPtrVect::iterator PointPtrVect_I
Definition point.h:538