File: Transform2D.cpp

package info (click to toggle)
rdkit 201203-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 37,840 kB
  • sloc: cpp: 93,902; python: 51,897; java: 5,192; ansic: 3,497; xml: 2,499; sql: 1,641; yacc: 1,518; lex: 1,076; makefile: 325; fortran: 183; sh: 153; cs: 51
file content (122 lines) | stat: -rw-r--r-- 3,101 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//  $Id: Transform2D.cpp 1528 2010-09-26 17:04:37Z glandrum $
// 
//   Copyright (C) 2003-2006 Rational Discovery LLC
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include <RDGeneral/Invariant.h>
#include <cstring>
#include "Transform.h"
#include "Transform2D.h"
#include <math.h>
#include "point.h"

namespace RDGeom {
  
  void Transform2D::setToIdentity() {
    unsigned int i, id;
    double *data = d_data.get();
    memset(static_cast<void *>(data),0,d_dataSize*sizeof(double));
    for (i = 0; i < DIM_2D; i++) {
      id = i*(DIM_2D+1);
      data[id] = 1.0;
    }
  }
  
  void Transform2D::TransformPoint(Point2D &pt) const {
    double x, y;
    double *data = d_data.get();
    x = data[0]*pt.x + data[1]*pt.y + data[2];
    y = data[3]*pt.x + data[4]*pt.y + data[5];
        
    pt.x = x;
    pt.y = y;
  }

  void Transform2D::SetTranslation(const Point2D &pt) {
    unsigned int i = DIM_2D -1;
    double *data = d_data.get();
    data[i] = pt.x; i += DIM_2D;
    data[i] = pt.y; i += DIM_2D;
    data[i] = 1.0; i += DIM_2D;
  }

  void Transform2D::SetTransform(const Point2D &pt, double angle) {
    this->setToIdentity();
    
    Transform2D trans1;
    trans1.SetTranslation(-pt);
    double *data = d_data.get();
    // set the rotation
    data[0] = cos(angle);
    data[1] = -sin(angle);
    data[3] = sin(angle);
    data[4] = cos(angle);
    
    (*this) *= trans1;

    // translation back to the orignal coordinate
    Transform2D trans2;
    trans2.SetTranslation(pt);
    trans2 *= (*this);

    // now combine them
    this->assign(trans2);
  }
    
    
  void Transform2D::SetTransform(const Point2D &ref1, const Point2D &ref2,
                                 const Point2D &pt1, const Point2D &pt2) {
    // compute the angle between the two vectors
    Point2D rvec = ref2 - ref1;
    Point2D pvec = pt2 - pt1;

    double dp = rvec.dotProduct(pvec);
    double lp = (rvec.length())*(pvec.length());
    if(lp<=0.0){
      this->setToIdentity();
      return;
    }

    double cval = dp/lp;
    if (cval < -1.0) {
      cval = -1.0;
    } else if (cval > 1.0) {
      cval = 1.0;
    }

    double ang = acos(cval);
    
    // figure out if we have to do clock wise or anti clock wise rotation
    double cross = (pvec.x)*(rvec.y) - (pvec.y)*(rvec.x);
    
    if (cross < 0.0) { 
      ang *= -1.0;
    }
    this->setToIdentity();
    // set the rotation 
    double *data = d_data.get();
    data[0] = cos(ang);
    data[1] = -sin(ang);
    data[3] = sin(ang);
    data[4] = cos(ang);
    
    // apply this rotation to pt1 and compute the translation
    Point2D npt1 = pt1;
    this->TransformPoint(npt1);
    data[DIM_2D-1] = ref1.x - npt1.x;
    data[2*DIM_2D-1] = ref1.y - npt1.y;
    
  }
  
}

RDGeom::Transform2D operator* (const RDGeom::Transform2D &t1, const RDGeom::Transform2D &t2) {
  RDGeom::Transform2D res;
  RDNumeric::multiply(t1, t2, res);
  return res;
};