~ubuntu-branches/ubuntu/precise/ipe/precise

« back to all changes in this revision

Viewing changes to src/ipelets/euclid/euclid.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2009-12-11 21:22:35 UTC
  • mfrom: (4.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20091211212235-5iio4nzpra64snab
Tags: 7.0.10-1
* New upstream.  Closes: #551192.
  - New build-depends: libcairo2-dev, liblua5.1-0-dev, gsfonts
  - patches/config.diff: Remove.  Upstream build system replaced.
  - Runtime lib package changed to libipe7.0.10 from libipe1c2a
  - Devel package renamed to libipe-dev (from libipe1-dev)
  - Package ipe depends on lua5.1 due to ipe-update-master.

* rules: Re-write to use dh.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// --------------------------------------------------------------------
2
 
// incircle.cpp: Ipelet for computing the incircle of a triangle
3
 
//
4
 
// Author: Jari Lappalainen
5
 
// Date: April 14th 2006
6
 
//
7
 
// Description: Finds the incircle of a triangle and adds it to the page.
8
 
// Algorithm is based on the geometric observation that the angle bisectors
9
 
// intersect at the incentre.
10
 
//
11
 
// This ipelet is based on the smallest-circle ipelet by Chris Gray.
12
 
// --------------------------------------------------------------------
13
 
/*
14
 
 
15
 
    This file is part of the extensible drawing editor Ipe.
16
 
    Copyright (C) 1993-2007  Otfried Cheong
17
 
 
18
 
    Ipe is free software; you can redistribute it and/or modify it
19
 
    under the terms of the GNU General Public License as published by
20
 
    the Free Software Foundation; either version 2 of the License, or
21
 
    (at your option) any later version.
22
 
 
23
 
    As a special exception, you have permission to link Ipe with the
24
 
    CGAL library and distribute executables, as long as you follow the
25
 
    requirements of the Gnu General Public License in regard to all of
26
 
    the software in the executable aside from CGAL.
27
 
 
28
 
    Ipe is distributed in the hope that it will be useful, but WITHOUT
29
 
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
30
 
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
31
 
    License for more details.
32
 
 
33
 
    You should have received a copy of the GNU General Public License
34
 
    along with Ipe; if not, you can find it at
35
 
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
36
 
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37
 
 
38
 
*/
39
 
 
40
 
#include "ipelet.h"
41
 
#include "ipepath.h"
42
 
#include "ipepage.h"
43
 
#include "ipevisitor.h"
44
 
#include "ipemark.h"
45
 
 
46
 
#include <set>
47
 
#include <sstream>
48
 
 
49
 
using namespace std;
50
 
 
51
 
static const char *aboutText =
52
 
"Written by Jari Lappalainen";
53
 
 
54
 
class EuclidIpelet : public Ipelet {
55
 
public:
56
 
  virtual int IpelibVersion() const { return IPELIB_VERSION; }
57
 
  int NumFunctions() const { return 2; }
58
 
  virtual const char* Label() const { return "Euclidean Geometry"; }
59
 
  const char* SubLabel(int fCount) const
60
 
  {
61
 
    switch (fCount) {
62
 
      case 0:
63
 
        return "Incircle of Triangle";
64
 
      case 1:
65
 
        return "Excircles of Triangle";
66
 
    }
67
 
    return ""; // Never get here
68
 
  }
69
 
  virtual void Run(int, IpePage *page, IpeletHelper *helper);
70
 
  virtual const char *About() const { return aboutText; }
71
 
};
72
 
 
73
 
namespace {
74
 
  struct vector_comparator :
75
 
    public binary_function<IpeVector,IpeVector,bool> {
76
 
    bool operator()(const IpeVector& v1, const IpeVector& v2) const {
77
 
      if (v1.iX == v2.iX) {
78
 
        return v1.iY < v2.iY;
79
 
      }
80
 
      return v1.iX < v2.iX;
81
 
    }
82
 
  };
83
 
 
84
 
  typedef set<IpeVector,vector_comparator> VS_t;
85
 
 
86
 
  VS_t collect_vertices(IpePage* page)
87
 
  {
88
 
    VS_t points;
89
 
    for (IpePage::iterator it = page->begin(); it != page->end(); ++it) {
90
 
      if (it->Select() && it->Object()) {
91
 
        IpeMatrix m = it->Object()->Matrix();
92
 
        if (it->Object()->AsMark()) {
93
 
          points.insert(m * it->Object()->AsMark()->Position());
94
 
        }
95
 
        else if (it->Object()->AsPath()) {
96
 
          for (int j = 0; j<it->Object()->AsPath()->NumSubPaths(); ++j) {
97
 
            const IpeSubPath* sp = it->Object()->AsPath()->SubPath(j);
98
 
            if (sp->AsSegs()) {
99
 
              for (int k = 0; k<sp->AsSegs()->NumSegments(); k++) {
100
 
                points.insert(m * sp->AsSegs()->Segment(k).CP(0));
101
 
                points.insert(m * sp->AsSegs()->Segment(k).CP(1));
102
 
              }
103
 
            }
104
 
          }
105
 
        }
106
 
      }
107
 
    }
108
 
    return points;
109
 
  }
110
 
 
111
 
  IpeLine angle_bisector(const IpeVector& origin,
112
 
                         const IpeVector& dir1,
113
 
                         const IpeVector& dir2)
114
 
  {
115
 
    assert(dir1.SqLen() > 0);
116
 
    assert(dir2.SqLen() > 0);
117
 
    IpeVector bisector = dir1.Normalized() + dir2.Normalized();
118
 
    if (bisector.Len() == 0) {
119
 
      bisector = dir1.Orthogonal();
120
 
    }
121
 
    return IpeLine::Through(origin, origin + bisector);
122
 
  }
123
 
 
124
 
  void incircle(const IpeVector& a, const IpeVector& b,
125
 
                const IpeVector& c, IpeScalar& inradius, IpeVector& incentre)
126
 
  {
127
 
    IpeLine b1 = angle_bisector(a, b - a, c - a);
128
 
    IpeLine b2 = angle_bisector(b, c - b, a - b);
129
 
    if (b1.Intersects(b2, incentre)) {
130
 
      IpeLine AB = IpeLine::Through(a, b);
131
 
      inradius = AB.Distance(incentre);
132
 
    }
133
 
    else {
134
 
      inradius = 0;
135
 
      incentre = c;
136
 
    }
137
 
  }
138
 
 
139
 
  void excircle(const IpeVector& a, const IpeVector& b,
140
 
                const IpeVector& c, IpeScalar& radius, IpeVector& centre)
141
 
  {
142
 
    IpeLine b1 = angle_bisector(a, b - a, c - a);
143
 
    IpeLine b2 = angle_bisector(b, c - b, a - b);
144
 
    IpeVector n1 = b1.Normal();
145
 
    IpeVector n2 = b2.Normal();
146
 
    IpeLine nl1 = IpeLine::Through(a, a + n1);
147
 
    IpeLine nl2 = IpeLine::Through(b, b + n2);
148
 
    if (nl1.Intersects(nl2, centre)) {
149
 
      IpeLine AB = IpeLine::Through(a, b);
150
 
      radius = AB.Distance(centre);
151
 
    }
152
 
    else {
153
 
      // Should really be a line through a, b and c
154
 
      centre = c;
155
 
      radius = 0;
156
 
    }
157
 
  }
158
 
 
159
 
  void add_circle(IpeScalar radius, const IpeVector& centre, IpePage* page,
160
 
                  IpeletHelper* helper)
161
 
  {
162
 
    // Protect against ipe crash
163
 
    const double IpeLimit(10000);
164
 
    if (radius > IpeLimit
165
 
        && fabs(centre.iX) > IpeLimit
166
 
        && fabs(centre.iY) > IpeLimit) {
167
 
      return;
168
 
    }
169
 
 
170
 
    IpeMatrix m(radius, 0.0, 0.0, radius, centre.iX, centre.iY);
171
 
    IpeEllipse* ellipse = new IpeEllipse(m);
172
 
    IpePath* path = new IpePath(helper->Attributes());
173
 
    path->AddSubPath(ellipse);
174
 
    page->push_back(IpePgObject(IpePgObject::EPrimary,
175
 
                                helper->CurrentLayer(), path));
176
 
  }
177
 
 
178
 
  void RunIncircle(IpePage *page, IpeletHelper *helper)
179
 
  {
180
 
    VS_t vertices = collect_vertices(page);
181
 
    if (vertices.size() != 3) {
182
 
      ostringstream ost;
183
 
      ost << "selection with " << vertices.size()
184
 
          << " points is not a triangle";
185
 
      helper->Message(ost.str().c_str());
186
 
    }
187
 
    else {
188
 
      IpeVector a = *(vertices.begin());
189
 
      IpeVector b = *(++vertices.begin());
190
 
      IpeVector c = *(++++vertices.begin());
191
 
      IpeScalar inradius(0);
192
 
      IpeVector incentre;
193
 
      incircle(a, b, c, inradius, incentre);
194
 
      add_circle(inradius, incentre, page, helper);
195
 
 
196
 
      ostringstream ost;
197
 
      ost << "Created incircle with radius " << inradius
198
 
          << " and centre " << incentre.iX << "," << incentre.iY;
199
 
      helper->Message(ost.str().c_str());
200
 
    }
201
 
  }
202
 
 
203
 
  void RunExcircles(IpePage *page, IpeletHelper *helper)
204
 
  {
205
 
    VS_t vertices = collect_vertices(page);
206
 
    if (vertices.size() != 3) {
207
 
      ostringstream ost;
208
 
      ost << "selection with " << vertices.size()
209
 
          << " vertices is not a triangle";
210
 
      helper->Message(ost.str().c_str());
211
 
    }
212
 
    else {
213
 
      IpeVector a = *(vertices.begin());
214
 
      IpeVector b = *(++vertices.begin());
215
 
      IpeVector c = *(++++vertices.begin());
216
 
      IpeScalar radius(0);
217
 
      IpeVector centre;
218
 
      excircle(a, b, c, radius, centre);
219
 
      add_circle(radius, centre, page, helper);
220
 
      excircle(b, c, a, radius, centre);
221
 
      add_circle(radius, centre, page, helper);
222
 
      excircle(c, a, b, radius, centre);
223
 
      add_circle(radius, centre, page, helper);
224
 
 
225
 
      ostringstream ost;
226
 
      ost << "Created excircles";
227
 
      helper->Message(ost.str().c_str());
228
 
    }
229
 
  }
230
 
}
231
 
 
232
 
void EuclidIpelet::Run(int fCount, IpePage *page, IpeletHelper *helper)
233
 
{
234
 
  switch (fCount) {
235
 
  case 0:
236
 
    RunIncircle(page, helper);
237
 
    break;
238
 
  case 1:
239
 
    RunExcircles(page, helper);
240
 
    break;
241
 
  }
242
 
}
243
 
 
244
 
// --------------------------------------------------------------------
245
 
 
246
 
IPELET_DECLARE Ipelet *NewIpelet()
247
 
{
248
 
  return new EuclidIpelet;
249
 
}
250
 
 
251
 
// --------------------------------------------------------------------