~ubuntu-branches/ubuntu/oneiric/kig/oneiric

« back to all changes in this revision

Viewing changes to objects/conic_imp.cc

  • Committer: Bazaar Package Importer
  • Author(s): Harald Sitter
  • Date: 2011-07-10 11:57:38 UTC
  • Revision ID: james.westby@ubuntu.com-20110710115738-gdjnn1kctr49lmy9
Tags: upstream-4.6.90+repack
ImportĀ upstreamĀ versionĀ 4.6.90+repack

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (C)  2003  Dominique Devriese <devriese@kde.org>
 
2
 
 
3
// This program is free software; you can redistribute it and/or
 
4
// modify it under the terms of the GNU General Public License
 
5
// as published by the Free Software Foundation; either version 2
 
6
// of the License, or (at your option) any later version.
 
7
 
 
8
// This program is distributed in the hope that it will be useful,
 
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
// GNU General Public License for more details.
 
12
 
 
13
// You should have received a copy of the GNU General Public License
 
14
// along with this program; if not, write to the Free Software
 
15
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
16
// 02110-1301, USA.
 
17
 
 
18
#include "conic_imp.h"
 
19
 
 
20
#include <math.h>
 
21
 
 
22
#include "bogus_imp.h"
 
23
#include "point_imp.h"
 
24
 
 
25
#include "../misc/kigpainter.h"
 
26
#include "../misc/common.h"
 
27
#include "../misc/coordinate_system.h"
 
28
 
 
29
#include "../kig/kig_document.h"
 
30
#include "../kig/kig_view.h"
 
31
 
 
32
#include <klocale.h>
 
33
 
 
34
ObjectImp* ConicImp::transform( const Transformation& t ) const
 
35
{
 
36
  bool valid = true;
 
37
  ConicCartesianData d = calcConicTransformation( cartesianData(), t, valid );
 
38
  if ( ! valid ) return new InvalidImp;
 
39
  else return new ConicImpCart( d );
 
40
}
 
41
 
 
42
void ConicImp::draw( KigPainter& p ) const
 
43
{
 
44
  p.drawCurve( this );
 
45
}
 
46
 
 
47
bool ConicImp::valid() const
 
48
{
 
49
  return true;
 
50
}
 
51
 
 
52
bool ConicImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
 
53
{
 
54
  return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
 
55
}
 
56
 
 
57
bool ConicImp::inRect( const Rect&, int, const KigWidget& ) const
 
58
{
 
59
  // TODO
 
60
  return false;
 
61
}
 
62
 
 
63
int ConicImp::numberOfProperties() const
 
64
{
 
65
  return Parent::numberOfProperties() + 6;
 
66
}
 
67
 
 
68
const QByteArrayList ConicImp::propertiesInternalNames() const
 
69
{
 
70
  QByteArrayList l = Parent::propertiesInternalNames();
 
71
  l << "type";
 
72
  l << "center";
 
73
  l << "first-focus";
 
74
  l << "second-focus";
 
75
  l << "cartesian-equation";
 
76
  l << "polar-equation";
 
77
  assert( l.size() == ConicImp::numberOfProperties() );
 
78
  return l;
 
79
}
 
80
 
 
81
const QByteArrayList ConicImp::properties() const
 
82
{
 
83
  QByteArrayList l = Parent::properties();
 
84
  l << I18N_NOOP( "Conic Type" );
 
85
  l << I18N_NOOP( "Center" );
 
86
  l << I18N_NOOP( "First Focus" );
 
87
  l << I18N_NOOP( "Second Focus" );
 
88
  l << I18N_NOOP( "Cartesian Equation" );
 
89
  l << I18N_NOOP( "Polar Equation" );
 
90
  assert( l.size() == ConicImp::numberOfProperties() );
 
91
  return l;
 
92
}
 
93
 
 
94
const ObjectImpType* ConicImp::impRequirementForProperty( int which ) const
 
95
{
 
96
  if ( which < Parent::numberOfProperties() )
 
97
    return Parent::impRequirementForProperty( which );
 
98
  else return ConicImp::stype();
 
99
}
 
100
 
 
101
const char* ConicImp::iconForProperty( int which ) const
 
102
{
 
103
  int pnum = 0;
 
104
  if ( which < Parent::numberOfProperties() )
 
105
    return Parent::iconForProperty( which );
 
106
  if ( which == Parent::numberOfProperties() + pnum++ )
 
107
    return "kig_text"; // conic type string
 
108
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
109
    return ""; // center
 
110
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
111
    return ""; // focus1
 
112
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
113
    return ""; // focus2
 
114
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
115
    return "kig_text"; // cartesian equation string
 
116
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
117
    return "kig_text"; // polar equation string
 
118
  else assert( false );
 
119
  return "";
 
120
}
 
121
 
 
122
ObjectImp* ConicImp::property( int which, const KigDocument& w ) const
 
123
{
 
124
  int pnum = 0;
 
125
 
 
126
  if ( which < Parent::numberOfProperties() )
 
127
    return Parent::property( which, w );
 
128
  if ( which == Parent::numberOfProperties() + pnum++ )
 
129
    return new StringImp( conicTypeString() );
 
130
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
131
    return new PointImp( coniccenter() );
 
132
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
133
    return new PointImp( focus1() );
 
134
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
135
    return new PointImp( focus2() );
 
136
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
137
    return new StringImp( cartesianEquationString( w ) );
 
138
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
139
    return new StringImp( polarEquationString( w ) );
 
140
  else assert( false );
 
141
  return new InvalidImp;
 
142
}
 
143
 
 
144
double ConicImp::getParam( const Coordinate& p, const KigDocument& ) const
 
145
{
 
146
  return getParam( p );
 
147
}
 
148
 
 
149
double ConicImp::getParam( const Coordinate& p ) const
 
150
{
 
151
  const ConicPolarData d = polarData();
 
152
  Coordinate tmp = p - d.focus1;
 
153
  double l = tmp.length();
 
154
  double theta = atan2(tmp.y, tmp.x);
 
155
  double costheta = cos(theta);
 
156
  double sintheta = sin(theta);
 
157
  double ecosthetamtheta0 = costheta*d.ecostheta0 + sintheta*d.esintheta0;
 
158
  double esinthetamtheta0 = sintheta*d.ecostheta0 - costheta*d.esintheta0;
 
159
  double oneplus = 1.0 + d.ecostheta0*d.ecostheta0 + d.esintheta0*d.esintheta0;
 
160
  double fact = esinthetamtheta0*(1.0 - ecosthetamtheta0)/(oneplus - 2*ecosthetamtheta0);
 
161
// fact is sin(a)*cos(a) where a is the angle between the ray from the first
 
162
// focus and the normal to the conic.  We need it in order to adjust the
 
163
// angle according to the projection onto the conic of our point
 
164
  double rho1 = d.pdimen / (1 - ecosthetamtheta0);
 
165
  double rho2 = - d.pdimen / (1 + ecosthetamtheta0);
 
166
  if (fabs(rho1 - l) < fabs(rho2 - l))
 
167
  {
 
168
    theta += (rho1 - l)*fact/rho1;
 
169
    return fmod(theta / ( 2 * M_PI ) + 1, 1);
 
170
  } else {
 
171
    theta += (rho2 - l)*fact/rho2;
 
172
    return fmod(theta / ( 2 * M_PI ) + 0.5, 1);
 
173
  }
 
174
}
 
175
 
 
176
const Coordinate ConicImp::getPoint( double p, const KigDocument& ) const
 
177
{
 
178
  return getPoint( p );
 
179
}
 
180
 
 
181
const Coordinate ConicImp::getPoint( double p ) const
 
182
{
 
183
  const ConicPolarData d = polarData();
 
184
 
 
185
  double costheta = cos(p * 2 * M_PI);
 
186
  double sintheta = sin(p * 2 * M_PI);
 
187
  double rho = d.pdimen / (1 - costheta* d.ecostheta0 - sintheta* d.esintheta0);
 
188
  return d.focus1 + Coordinate (costheta, sintheta) * rho;
 
189
}
 
190
 
 
191
int ConicImp::conicType() const
 
192
{
 
193
  const ConicPolarData d = polarData();
 
194
  double ec = d.ecostheta0;
 
195
  double es = d.esintheta0;
 
196
  double esquare = ec*ec + es*es;
 
197
  const double parabolamiss = 1e-3;  // don't know what a good value could be
 
198
 
 
199
  if (esquare < 1.0 - parabolamiss) return 1;
 
200
  if (esquare > 1.0 + parabolamiss) return -1;
 
201
 
 
202
  return 0;
 
203
}
 
204
 
 
205
QString ConicImp::conicTypeString() const
 
206
{
 
207
  switch (conicType())
 
208
  {
 
209
  case 1:
 
210
    return i18n("Ellipse");
 
211
  case -1:
 
212
    return i18n("Hyperbola");
 
213
  case 0:
 
214
    return i18n("Parabola");
 
215
  default:
 
216
    assert( false );
 
217
    return "";
 
218
  }
 
219
}
 
220
 
 
221
QString ConicImp::cartesianEquationString( const KigDocument& ) const
 
222
{
 
223
  ConicCartesianData data = cartesianData();
 
224
  EquationString ret = EquationString( "" );
 
225
  bool needsign = false;
 
226
  if ( isVerticalParabola( data ) )
 
227
  {
 
228
    double f = - 1.0/data.coeffs[4];
 
229
    ret.addTerm( - f*data.coeffs[4], ret.y(), needsign );
 
230
    ret.append( " = " );
 
231
    needsign = false;
 
232
    ret.addTerm( f*data.coeffs[0], ret.x2(), needsign );
 
233
    ret.addTerm( f*data.coeffs[1], ret.y2(), needsign );
 
234
    ret.addTerm( f*data.coeffs[2], ret.xy(), needsign );
 
235
    ret.addTerm( f*data.coeffs[3], ret.x(), needsign );
 
236
    ret.addTerm( f*data.coeffs[5], "", needsign );
 
237
    return ret;
 
238
  }
 
239
  ret.addTerm( data.coeffs[0], ret.x2(), needsign );
 
240
  ret.addTerm( data.coeffs[1], ret.y2(), needsign );
 
241
  ret.addTerm( data.coeffs[2], ret.xy(), needsign );
 
242
  ret.addTerm( data.coeffs[3], ret.x(), needsign );
 
243
  ret.addTerm( data.coeffs[4], ret.y(), needsign );
 
244
  ret.addTerm( data.coeffs[5], "", needsign );
 
245
  ret.append( " = 0" );
 
246
  return ret;
 
247
 
 
248
//  QString ret = i18n( "%1 xĀ² + %2 yĀ² + %3 xy + %4 x + %5 y + %6 = 0" );
 
249
//  ConicCartesianData data = cartesianData();
 
250
//  ret = ret.arg( data.coeffs[0], 0, 'g', 3 );
 
251
//  ret = ret.arg( data.coeffs[1], 0, 'g', 3 );
 
252
//  ret = ret.arg( data.coeffs[2], 0, 'g', 3 );
 
253
//  ret = ret.arg( data.coeffs[3], 0, 'g', 3 );
 
254
//  ret = ret.arg( data.coeffs[4], 0, 'g', 3 );
 
255
//  ret = ret.arg( data.coeffs[5], 0, 'g', 3 );
 
256
//  return ret;
 
257
}
 
258
 
 
259
QString ConicImp::polarEquationString( const KigDocument& w ) const
 
260
{
 
261
//  QString ret = i18n( "rho = %1/(1 + %2 cos theta + %3 sin theta)\n    [centered at %4]" );
 
262
  const ConicPolarData data = polarData();
 
263
 
 
264
  EquationString ret = EquationString( i18n( "rho" ) );
 
265
  ret.append( " = " );
 
266
  if ( data.pdimen < 0 ) ret.append( "- " );
 
267
  bool needsign = false;
 
268
  ret.addTerm( fabs( data.pdimen ), "", needsign );
 
269
  ret.append( "/(1" );
 
270
  needsign = true;
 
271
  ret.addTerm( -data.ecostheta0, i18n( "cos theta" ), needsign );
 
272
  ret.addTerm( -data.esintheta0, i18n( "sin theta" ), needsign );
 
273
  ret.append( ")\n" );
 
274
  ret.append( ki18n( "[centered at %1]" )
 
275
                   .subs( w.coordinateSystem().fromScreen( data.focus1, w ) )
 
276
//                   .subs( data.pdimen, 0, 'g', 3 );
 
277
//                   .subs( -data.ecostheta0, 0, 'g', 3 );
 
278
//                   .subs( -data.esintheta0, 0, 'g', 3 );
 
279
                   .toString() );
 
280
 
 
281
  ret.prettify();
 
282
  return ret;
 
283
}
 
284
 
 
285
const ConicCartesianData ConicImp::cartesianData() const
 
286
{
 
287
  return ConicCartesianData( polarData() );
 
288
}
 
289
 
 
290
Coordinate ConicImp::focus1() const
 
291
{
 
292
  return polarData().focus1;
 
293
}
 
294
 
 
295
Coordinate ConicImp::coniccenter() const
 
296
{
 
297
  const ConicPolarData d = polarData();
 
298
  double ec = d.ecostheta0;
 
299
  double es = d.esintheta0;
 
300
 
 
301
  double fact = d.pdimen/(1 - ec*ec - es*es);
 
302
 
 
303
  return d.focus1 + fact*Coordinate(ec, es);
 
304
}
 
305
 
 
306
Coordinate ConicImp::focus2() const
 
307
{
 
308
  const ConicPolarData d = polarData();
 
309
  double ec = d.ecostheta0;
 
310
  double es = d.esintheta0;
 
311
 
 
312
  double fact = 2*d.pdimen/(1 - ec*ec - es*es);
 
313
 
 
314
  return d.focus1 + fact*Coordinate(ec, es);
 
315
}
 
316
 
 
317
const ConicPolarData ConicImpCart::polarData() const
 
318
{
 
319
  return mpolardata;
 
320
}
 
321
 
 
322
const ConicCartesianData ConicImpCart::cartesianData() const
 
323
{
 
324
  return mcartdata;
 
325
}
 
326
 
 
327
ConicImpCart::ConicImpCart( const ConicCartesianData& data )
 
328
  : ConicImp(), mcartdata( data ), mpolardata( data )
 
329
{
 
330
  //assert( data.valid() );
 
331
}
 
332
 
 
333
ConicImpPolar::ConicImpPolar( const ConicPolarData& data )
 
334
  : ConicImp(), mdata( data )
 
335
{
 
336
}
 
337
 
 
338
ConicImpPolar::~ConicImpPolar()
 
339
{
 
340
}
 
341
 
 
342
const ConicPolarData ConicImpPolar::polarData() const
 
343
{
 
344
  return mdata;
 
345
}
 
346
 
 
347
ConicImpCart* ConicImpCart::copy() const
 
348
{
 
349
  return new ConicImpCart( mcartdata );
 
350
}
 
351
 
 
352
ConicImpPolar* ConicImpPolar::copy() const
 
353
{
 
354
  return new ConicImpPolar( mdata );
 
355
}
 
356
 
 
357
ConicImp::ConicImp()
 
358
{
 
359
}
 
360
 
 
361
ConicImp::~ConicImp()
 
362
{
 
363
}
 
364
 
 
365
ConicImpCart::~ConicImpCart()
 
366
{
 
367
}
 
368
 
 
369
void ConicImp::visit( ObjectImpVisitor* vtor ) const
 
370
{
 
371
  vtor->visit( this );
 
372
}
 
373
 
 
374
bool ConicImp::equals( const ObjectImp& rhs ) const
 
375
{
 
376
  return rhs.inherits( ConicImp::stype() ) &&
 
377
    static_cast<const ConicImp&>( rhs ).polarData() == polarData();
 
378
}
 
379
 
 
380
const ObjectImpType* ConicImp::stype()
 
381
{
 
382
  static const ObjectImpType t(
 
383
    Parent::stype(), "conic",
 
384
    I18N_NOOP( "conic" ),
 
385
    I18N_NOOP( "Select this conic" ),
 
386
    I18N_NOOP( "Select conic %1" ),
 
387
    I18N_NOOP( "Remove a Conic" ),
 
388
    I18N_NOOP( "Add a Conic" ),
 
389
    I18N_NOOP( "Move a Conic" ),
 
390
    I18N_NOOP( "Attach to this conic" ),
 
391
    I18N_NOOP( "Show a Conic" ),
 
392
    I18N_NOOP( "Hide a Conic" )
 
393
    );
 
394
  return &t;
 
395
}
 
396
 
 
397
const ObjectImpType* ConicImp::type() const
 
398
{
 
399
  return ConicImp::stype();
 
400
}
 
401
 
 
402
bool ConicImp::containsPoint( const Coordinate& p, const KigDocument& ) const
 
403
{
 
404
  const ConicPolarData d = polarData();
 
405
 
 
406
// the threshold is relative to the size of the conic (mp)
 
407
  return internalContainsPoint( p, test_threshold*d.pdimen );
 
408
}
 
409
 
 
410
bool ConicImp::internalContainsPoint( const Coordinate& p, double threshold ) const
 
411
{
 
412
  const ConicPolarData d = polarData();
 
413
 
 
414
  Coordinate focus1 = d.focus1;
 
415
  double ecostheta0 = d.ecostheta0;
 
416
  double esintheta0 = d.esintheta0;
 
417
  double pdimen = d.pdimen;
 
418
 
 
419
  Coordinate pos = p - focus1;
 
420
  double len = pos.length();
 
421
  double costheta = pos.x / len;
 
422
  double sintheta = pos.y / len;
 
423
 
 
424
  double ecosthetamtheta0 = costheta*ecostheta0 + sintheta*esintheta0;
 
425
  double rho = pdimen / (1.0 - ecosthetamtheta0);
 
426
 
 
427
  double oneplus = 1.0 + ecostheta0*ecostheta0 + esintheta0*esintheta0;
 
428
 
 
429
// fact is the cosine of the angle between the ray from the first focus
 
430
// and the normal to the conic, so that we compute the real distance
 
431
 
 
432
  double fact = (1.0 - ecosthetamtheta0)/sqrt(oneplus - 2*ecosthetamtheta0);
 
433
  if ( fabs((len - rho)*fact) <= threshold ) return true;
 
434
  rho = - pdimen / ( 1.0 + ecosthetamtheta0 );
 
435
  fact = (1.0 + ecosthetamtheta0)/sqrt(oneplus + 2*ecosthetamtheta0);
 
436
  return fabs(( len - rho )*fact) <= threshold;
 
437
}
 
438
 
 
439
bool ConicImp::isPropertyDefinedOnOrThroughThisImp( int which ) const
 
440
{
 
441
  if ( which < Parent::numberOfProperties() )
 
442
    return Parent::isPropertyDefinedOnOrThroughThisImp( which );
 
443
  return false;
 
444
}
 
445
 
 
446
bool ConicImp::isVerticalParabola( ConicCartesianData& data ) const
 
447
{
 
448
  return (
 
449
           fabs( data.coeffs[1] ) < 1e-12 &&     // y^2
 
450
           fabs( data.coeffs[2] ) < 1e-12 &&     // xy
 
451
           fabs( data.coeffs[4] ) > 1e-5 );      // y
 
452
}
 
453
 
 
454
Rect ConicImp::surroundingRect() const
 
455
{
 
456
  // it's prolly possible to calculate this ( in the case that the
 
457
  // conic is limited in size ), but for now we don't.
 
458
 
 
459
  return Rect::invalidRect();
 
460
}
 
461
 
 
462
/* An arc of a conic is identified by a startangle and a size (angle);
 
463
 * both angles are measured with respect to the first focus of the conic
 
464
 * (the one used for the conic polar equation
 
465
 */
 
466
 
 
467
ConicArcImp::ConicArcImp( const ConicCartesianData& data,
 
468
                  const double startangle, const double angle )
 
469
  : ConicImpCart( data ), msa( startangle ), ma( angle )
 
470
{
 
471
}
 
472
 
 
473
ConicArcImp::~ConicArcImp()
 
474
{
 
475
}
 
476
 
 
477
ConicArcImp* ConicArcImp::copy() const
 
478
{
 
479
  return new ConicArcImp( mcartdata, msa, ma );
 
480
}
 
481
 
 
482
ObjectImp* ConicArcImp::transform( const Transformation& t ) const
 
483
{
 
484
  bool valid = true;
 
485
  ConicCartesianData d = calcConicTransformation( cartesianData(), t, valid );
 
486
  if ( ! valid ) return new InvalidImp;
 
487
  ConicArcImp* result = new ConicArcImp( d, 0.0, 2*M_PI );
 
488
 
 
489
  Coordinate a = t.apply( getPoint ( 0. ) );
 
490
  Coordinate b = t.apply( getPoint( 0.5 ) );
 
491
  Coordinate c = t.apply( getPoint( 1. ) );
 
492
  double anglea = 2*M_PI*result->getParam( a );
 
493
  double angleb = 2*M_PI*result->getParam( b );
 
494
  double anglec = 2*M_PI*result->getParam( c );
 
495
  double startangle = 0.;
 
496
  double angle = 2*M_PI;
 
497
  // anglea should be smaller than anglec
 
498
  if ( anglea > anglec )
 
499
  {
 
500
    double t = anglea;
 
501
    anglea = anglec;
 
502
    anglec = t;
 
503
  };
 
504
  if ( angleb > anglec || angleb < anglea )
 
505
  {
 
506
    startangle = anglec;
 
507
    angle = 2 * M_PI + anglea - startangle;
 
508
  }
 
509
  else
 
510
  {
 
511
    startangle = anglea;
 
512
    angle = anglec - anglea;
 
513
  };
 
514
 
 
515
  result->setStartAngle( startangle );
 
516
  result->setAngle( angle );
 
517
  return result;
 
518
}
 
519
 
 
520
bool ConicArcImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
 
521
{
 
522
  return internalContainsPoint( o, w.screenInfo().normalMiss( width ),
 
523
     w.document() );
 
524
}
 
525
 
 
526
int ConicArcImp::numberOfProperties() const
 
527
{
 
528
  return Parent::numberOfProperties() + 3;
 
529
}
 
530
 
 
531
const QByteArrayList ConicArcImp::properties() const
 
532
{
 
533
  QByteArrayList ret = Parent::properties();
 
534
  ret << I18N_NOOP( "Supporting Conic" );
 
535
  ret << I18N_NOOP( "First End Point" );
 
536
  ret << I18N_NOOP( "Second End Point" );
 
537
  assert( ret.size() == ConicArcImp::numberOfProperties() );
 
538
  return ret;
 
539
}
 
540
 
 
541
const QByteArrayList ConicArcImp::propertiesInternalNames() const
 
542
{
 
543
  QByteArrayList ret = Parent::propertiesInternalNames();
 
544
  ret << "support";
 
545
  ret << "end-point-A";
 
546
  ret << "end-point-B";
 
547
  return ret;
 
548
}
 
549
 
 
550
const char* ConicArcImp::iconForProperty( int which ) const
 
551
{
 
552
  int numprop = 0;
 
553
  if ( which < Parent::numberOfProperties() )
 
554
    return Parent::iconForProperty( which );
 
555
  else if ( which == Parent::numberOfProperties() + numprop++ )
 
556
    return "";
 
557
  else if ( which == Parent::numberOfProperties() + numprop++ )
 
558
    return "";
 
559
  else if ( which == Parent::numberOfProperties() + numprop++ )
 
560
    return "";
 
561
  else assert( false );
 
562
  return "";
 
563
}
 
564
 
 
565
ObjectImp* ConicArcImp::property( int which, const KigDocument& d ) const
 
566
{
 
567
  int numprop = 0;
 
568
  if ( which < Parent::numberOfProperties() )
 
569
    return Parent::property( which, d );
 
570
  else if ( which == Parent::numberOfProperties() + numprop++ )
 
571
    return new ConicImpCart( cartesianData() );
 
572
  else if ( which == Parent::numberOfProperties() + numprop++ )
 
573
    return new PointImp( firstEndPoint());
 
574
  else if ( which == Parent::numberOfProperties() + numprop++ )
 
575
    return new PointImp( secondEndPoint());
 
576
  else return new InvalidImp;
 
577
  return new InvalidImp;
 
578
}
 
579
 
 
580
bool ConicArcImp::isPropertyDefinedOnOrThroughThisImp( int which ) const
 
581
{
 
582
  int pnum = 0;
 
583
 
 
584
  if ( which < Parent::numberOfProperties() )
 
585
    return Parent::isPropertyDefinedOnOrThroughThisImp( which );
 
586
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
587
    return false;  // support
 
588
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
589
    return true;   // first end-point
 
590
  else if ( which == Parent::numberOfProperties() + pnum++ )
 
591
    return true;   // second end-point
 
592
  else return false;
 
593
  return false;
 
594
}
 
595
 
 
596
Coordinate ConicArcImp::firstEndPoint() const
 
597
{
 
598
  return getPoint( 0. );
 
599
}
 
600
 
 
601
Coordinate ConicArcImp::secondEndPoint() const
 
602
{
 
603
  return getPoint( 1. );
 
604
}
 
605
 
 
606
const ObjectImpType* ConicArcImp::stype()
 
607
{
 
608
  static const ObjectImpType t(
 
609
    Parent::stype(), "conic arc",
 
610
    I18N_NOOP( "conic arc" ),
 
611
    I18N_NOOP( "Select this conic arc" ),
 
612
    I18N_NOOP( "Select conic arc %1" ),
 
613
    I18N_NOOP( "Remove a Conic Arc" ),
 
614
    I18N_NOOP( "Add a Conic Arc" ),
 
615
    I18N_NOOP( "Move a Conic Arc" ),
 
616
    I18N_NOOP( "Attach to this conic arc" ),
 
617
    I18N_NOOP( "Show a Conic Arc" ),
 
618
    I18N_NOOP( "Hide a Conic Arc" )
 
619
    );
 
620
  return &t;
 
621
}
 
622
 
 
623
const ObjectImpType* ConicArcImp::type() const
 
624
{
 
625
  return ConicArcImp::stype();
 
626
}
 
627
 
 
628
bool ConicArcImp::containsPoint( const Coordinate& p, const KigDocument& doc) const
 
629
{
 
630
  const ConicPolarData d = polarData();
 
631
 
 
632
// the threshold is relative to the size of the conic (mp)
 
633
  return internalContainsPoint( p, test_threshold*d.pdimen, doc );
 
634
}
 
635
 
 
636
bool ConicArcImp::internalContainsPoint( const Coordinate& p, double threshold,
 
637
    const KigDocument& doc ) const
 
638
{
 
639
  // this is directly stolen from locus code...
 
640
  double param = getParam( p, doc );
 
641
  Coordinate p1 = getPoint( param, doc );
 
642
  double dist = (p1 - p).length();
 
643
  return fabs( dist ) <= threshold;
 
644
}
 
645
 
 
646
double ConicArcImp::getParam( const Coordinate& p, const KigDocument& ) const
 
647
{
 
648
  return getParam( p );
 
649
}
 
650
 
 
651
double ConicArcImp::getParam( const Coordinate& p ) const
 
652
{
 
653
  double thetarel = 2 * M_PI * ConicImpCart::getParam( p ) - msa;
 
654
  while ( thetarel < 0 ) thetarel += 2 * M_PI;
 
655
  if ( thetarel <= ma ) return ( thetarel / ma );
 
656
 
 
657
  double antipodo = ( 2 * M_PI + ma )/2;
 
658
  if ( thetarel < antipodo ) return (1.0);
 
659
  return (0.0);
 
660
}
 
661
 
 
662
const Coordinate ConicArcImp::getPoint( double p, const KigDocument& ) const
 
663
{
 
664
  return getPoint( p );
 
665
}
 
666
 
 
667
const Coordinate ConicArcImp::getPoint( double p ) const
 
668
{
 
669
  double pwide = ( p * ma + msa )/ (2*M_PI);
 
670
  return ConicImpCart::getPoint( pwide );
 
671
}
 
672