File: Env_sphere_traits_3.h

package info (click to toggle)
cgal 3.6.1-2
  • links: PTS
  • area: non-free
  • in suites: squeeze
  • size: 62,184 kB
  • ctags: 95,782
  • sloc: cpp: 453,758; ansic: 96,821; sh: 226; makefile: 120; xml: 2
file content (1289 lines) | stat: -rw-r--r-- 46,878 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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
// Copyright (c) 2005  Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.6-branch/Envelope_3/include/CGAL/Env_sphere_traits_3.h $
// $Id: Env_sphere_traits_3.h 51065 2009-08-05 12:44:39Z efif $
//
// Author(s)     : Michal Meyerovitch     <gorgymic@post.tau.ac.il>
//                 Baruch Zukerman        <baruchzu@post.tau.ac.il>
//                 Ron Wein               <wein@post.tau.ac.il>
//                 Efi Fogel              <fogel@post.tau.ac.il>

#ifndef CGAL_ENV_SPHERE_TRAITS_3_H
#define CGAL_ENV_SPHERE_TRAITS_3_H

#include <CGAL/Object.h>
#include <CGAL/enum.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/Sphere_3.h>
#include <CGAL/functions_on_signs.h>
#include <CGAL/Envelope_3/Envelope_base.h>

CGAL_BEGIN_NAMESPACE

template <class ConicTraits_2>
class Env_sphere_traits_3 : public ConicTraits_2
{
public:
  typedef ConicTraits_2                             Traits_2;
  typedef Env_sphere_traits_3<Traits_2>             Self;
  
  typedef typename Traits_2::Point_2                Point_2;
  typedef typename Traits_2::Curve_2                Curve_2;
  typedef typename Traits_2::X_monotone_curve_2     X_monotone_curve_2;

  typedef typename Traits_2::Rat_kernel             Rat_kernel;
  typedef typename Traits_2::Alg_kernel             Alg_kernel;
  typedef typename Traits_2::Nt_traits              Nt_traits;

  typedef typename Rat_kernel::FT                   Rational;
  typedef typename Rat_kernel::Point_2              Rat_point_2;
  typedef typename Rat_kernel::Segment_2            Rat_segment_2;
  typedef typename Rat_kernel::Line_2               Rat_line_2;
  typedef typename Rat_kernel::Circle_2             Rat_circle_2;
  typedef typename Rat_kernel::Point_3              Rat_point_3;

  typedef typename Alg_kernel::FT                   Algebraic;
  typedef typename Alg_kernel::Point_2              Alg_point_2;
  typedef typename Alg_kernel::Circle_2             Alg_circle_2;
  
  typedef typename Rat_kernel::Sphere_3             Surface_3;
  
  // here we refer to the lower part of the sphere only
  typedef Surface_3                                 Xy_monotone_surface_3;
  typedef unsigned int                              Multiplicity;
protected:
  typedef std::pair<X_monotone_curve_2, 
                    Multiplicity>                   Intersection_curve;

public:
  class Make_xy_monotone_3 {
  protected:
    const Self & parent;

  public:
    Make_xy_monotone_3(const Self * p) : parent(*p)
    {}

    // create xy-monotone surfaces from a general surface
    // return a past-the-end iterator
    template <class OutputIterator>
    OutputIterator operator()(const Surface_3& s,
                              bool is_lower,
                              OutputIterator o) const
    {
      // our half sphere is of same type as our full sphere since we always
      // need only the lower/upper part of each sphere
      parent.m_is_lower = is_lower;
      *o++ = s;
      return o;
    }
  };

  /*! Get a Make_xy_monotone_3 functor object. */
  Make_xy_monotone_3
  make_xy_monotone_3_object() const
  {
    return Make_xy_monotone_3(this);
  }

  class Construct_projected_boundary_2
  {
  protected:
    const Self & parent;

  public:
    Construct_projected_boundary_2(const Self * p) : parent(*p)
    {}

    // insert into the OutputIterator all the (2d) curves of the boundary of
    // the vertical projection of the surface on the xy-plane
    // the OutputIterator value type is X_monotone_curve_2
    template <class OutputIterator>
    OutputIterator
    operator()(const Xy_monotone_surface_3& s, OutputIterator o) const
    {
      // the projected boundary in a circle, with a projected center,
      // and same radius
      Rat_point_2 proj_center = parent.project(s.center());
      Rat_circle_2 circ(proj_center, s.squared_radius());
      Curve_2 curve(circ);
      Object objs[2];
      CGAL_assertion_code(Object *p = )
      parent.make_x_monotone_2_object()(curve, objs);
      CGAL_assertion(p == objs + 2);
      
      X_monotone_curve_2 cv1, cv2;
      
      CGAL_assertion(assign(cv1, objs[0]));
      CGAL_assertion(assign(cv2, objs[1]));
      
      assign(cv1, objs[0]);
      assign(cv2, objs[1]);

      if(cv1.is_lower())
      {
        CGAL_assertion(cv2.is_upper());
        *o++ = make_object(std::make_pair(cv1, ON_POSITIVE_SIDE));
        *o++ = make_object(std::make_pair(cv2, ON_NEGATIVE_SIDE));
      }
      else
      {
        CGAL_assertion(cv2.is_lower());
        *o++ = make_object(std::make_pair(cv1, ON_NEGATIVE_SIDE));
        *o++ = make_object(std::make_pair(cv2, ON_POSITIVE_SIDE));
      }

      return o;
    }  
  };  
  
  /*! Get a Construct_projected_boundary_2 functor object. */
  Construct_projected_boundary_2
  construct_projected_boundary_2_object() const
  {
    return Construct_projected_boundary_2(this);
  }

  class Construct_projected_intersections_2
  {
  protected:
    const Self & parent;

  public:
    Construct_projected_intersections_2(const Self * p) : parent(*p)
    {}
    
    // insert into OutputIterator all the (2d) projections on the xy plane of
    // the intersection objects between the 2 surfaces
    // the data type of OutputIterator is Object
    template <class OutputIterator>
    OutputIterator
    operator()(const Xy_monotone_surface_3& s1,
               const Xy_monotone_surface_3& s2,
               OutputIterator o) const
    {      
      Rat_point_3 p1 = s1.center();
      Rat_point_3 p2 = s2.center();
      const Rational a1 = p1.x(), b1 = p1.y(), c1 = p1.z(),
                 a2 = p2.x(), b2 = p2.y(), c2 = p2.z();
      const Rational sqr_r1 = s1.squared_radius(), 
                     sqr_r2 = s2.squared_radius();

//      // the spheres intersect iff d(p1, p2) <= (r1+r2)
//      // squaring this twice, we get the condition
//      // sqr_d^2 + (1-2*sqr_d)(sqr_r1 + sqr_r2) - 2*sqr_r1*sqr_r2 <= 0
//      // with only rational numbers involved.
//      // todo: check if it helps
//      Rat_kernel ratk;
//      Rational sqr_d = ratk.compute_squared_distance_3_object()(p1, p2);
//      Sign do_inter = CGAL_NTS sign(sqr_d*sqr_d + (1-2*sqr_d)*(sqr_r1+sqr_r2)-2*sqr_r1*sqr_r2);
//      if (do_inter == POSITIVE)
//        return o;
        
      Nt_traits nt_traits;

      // we check if the centers of the 2 spheres have same z coordinate -
      // in this case the potential projected intersection is a segment
      // (or point)
      if (CGAL_NTS compare(c1, c2) == EQUAL)
      {
        if (CGAL_NTS compare(b1, b2) == EQUAL)
        {
          if (CGAL_NTS compare(a1, a2) == EQUAL)
            // the same center, we have no intersection
            // (we don't return overlappings as intersections)
          {
            return o;
          }

          // here we have c1 == c2, b1 == b2
          
          // the intersection lies on the plane
          //                m
          //  (1)    x = --------
          //             2(a1-a2)
          // where m = (a1^2 - a2^2 + sqr_r2 - sqr_r1)

          // which is orthogonal to the xy-plane
          // we look at the intersection of this plane with the plane z = c1
          // to get the projected segment of the spheres intersection

          // we get the quadratic equation:
          // A*y^2 + B*y + C = 0, where:
          //    A = 4(a1-a2)^2
          //    B = -8b1(a1-a2)^2
          //    C = m^2 - 4ma1(a1-a2) + 4(a1^2 + b1^2 - sqr_r1)(a1-a2)^2
          // (we multiplied the equation by 4(a1-a2)^2 to get integer
          //  coefficients)
          
          Rational a_diff = a1 - a2;
          Rational sqr_a_diff = a_diff * a_diff;
          Rational sqr_a1 = a1*a1, sqr_a2 = a2*a2;
          Rational sqr_b1 = b1*b1;
          Rational m = sqr_a1 - sqr_a2 + sqr_r2 - sqr_r1;
         
          Rational A = 4*sqr_a_diff;
          Rational B = -8*b1*sqr_a_diff;
          Rational C = 4*sqr_a_diff*(sqr_a1+sqr_b1-sqr_r1) + m*m - 4*m*a1*a_diff;

          
          Algebraic  ys[2];
          Algebraic *ys_end;
          int   n_ys;

          ys_end = nt_traits.solve_quadratic_equation(A, B, C, ys);
          n_ys = ys_end - ys;

          if (n_ys == 0)
          {
            return o; // no intersection
          }

          // the x coordinate of the solution points
          Algebraic xs = m / (2*a_diff);

          if (n_ys == 1)
          {
            // intersection is a point
            Point_2 inter_point(xs , ys[0]);
            *o++ = make_object(inter_point);
            return o;
          }

          CGAL_assertion(n_ys == 2);
          // intersection is a segment, with non-rational endpoints
          // so we construct a COLLINEAR conic (with equation as in (1))
          // with 2 endpoints

          Alg_point_2 end1(xs, ys[0]);
          Alg_point_2 end2(xs, ys[1]);

          // equation (1) is:
          // 2(a1-a2)x - m = 0

          Curve_2 res(0,0,0, 2*a_diff, 0, -m, COLLINEAR, end1, end2);

          parent.add_curve_to_output(res, o);
          //*o++ = make_object(Intersection_curve(res, TRANSVERSAL));
        }
        else
        {
          // here we have c1 == c2, b1 != b2.
          // the intersection lies on the plane
          //             -2(a1-a2)x + m
          //  (1)    y = ----------------
          //                2(b1-b2)
          // where m = (a1^2 + b1^2 - a2^2 - b2^2 + sqr_r2 - sqr_r1)
          
          // which is orthogonal to the xy-plane
          // we look at the intersection of this plane with the plane z = c1
          // to get the projected segment of the spheres intersection

          // we get the quadratic equation:
          // A*x^2 + B*x + C = 0
          // where
          //         (a1-a2)^2                      m(a1-a2)    2b1(a1-a2)
          // A = 1 + ---------          B = -2a1 - ---------- + ----------
          //         (b1-b2)^2                     (b1-b2)^2     (b1-b2)
          // and                                          m^2       b1*m
          //               C = a1^2 + b1^2 - sqr_r1 + ---------- - -------
          //                                          4(b1-b2)^2   (b1-b2)
          
          // since we can solve only equations with integer coefficients we 
          // multiply everything by 4(b1 - b2)^2, and get:
          // D*x^2 + E*x + F = 0 where
          //         D = 4(b1-b2)^2 + 4(a1-a2)^2
          //         E = -8a1(b1-b2)^2 - 4m(a1-a2) + 8b1(a1-a2)(b1-b2)
          //         F = 4(a1^2 + b1^2 - sqr_r1)(b1-b2)^2 + m^2 - 4mb1(b1-b2)
          // TODO: in the new version coefficients can be rationals
          Rational a_diff = a1 - a2;
          Rational b_diff = b1 - b2;
          Rational sqr_a_diff = a_diff * a_diff;
          Rational sqr_b_diff = b_diff * b_diff;
          Rational sqr_a1 = a1*a1, sqr_a2 = a2*a2;
          Rational sqr_b1 = b1*b1, sqr_b2 = b2*b2;
          Rational m = sqr_a1 + sqr_b1 - sqr_a2 - sqr_b2 + sqr_r2 - sqr_r1;

          Rational D = 4*sqr_a_diff + 4*sqr_b_diff;
          Rational E = -8*a1*sqr_b_diff - 4*m*a_diff + 8*b1*a_diff*b_diff;
          Rational F = 4*sqr_b_diff*(sqr_a1+sqr_b1-sqr_r1) + m*m - 4*m*b1*b_diff;
          
          Algebraic  xs[2];
          Algebraic *xs_end;
          int   n_xs;

          xs_end = nt_traits.solve_quadratic_equation(D, E, F, xs);
          n_xs = xs_end - xs;

          if (n_xs == 0)
          {
            return o; // no intersection
          }
          if (n_xs == 1)
          {
            // intersection is a point
            Point_2 inter_point(xs[0], (-2*a_diff*xs[0] + m)/(2*b_diff) );
            *o++ = make_object(inter_point);
            return o;
          }

          CGAL_assertion(n_xs == 2);
          // intersection is a segment, with non-rational endpoints
          // so we construct a COLLINEAR conic (with equation as in (1))
          // with 2 endpoints
          Algebraic ys[2];
          ys[0] = (-2*a_diff*xs[0] + m)/(2*b_diff);
          ys[1] = (-2*a_diff*xs[1] + m)/(2*b_diff);                

          Alg_point_2 end1(xs[0], ys[0]);
          Alg_point_2 end2(xs[1], ys[1]);
                              
          // equation (1) is:
          // 2(a1-a2)x + 2(b1-b2)y - m = 0
          Curve_2 res(0,0,0, 2*a_diff, 2*b_diff, -m, COLLINEAR, end1, end2);
          parent.add_curve_to_output(res, o);
          //*o++ = make_object(Intersection_curve(res, TRANSVERSAL));
        }
        
      }
      // now the potential intersection is (a part of) a circle,
      // and the projection is (a part of) an ellipse
      else
      {
        // here we have c1 != c2.
        // the intersection lies on the plane:
        //           -2(a1-a2)x -2(b1-b2)y + m
        // (*)   z = --------------------------
        //                 2(c1-c2)
        // where m = a1^2 + b1^2 + c1^2 - a2^2 - b2^2 - c2^2 + sqr_r2 - sqr_r1
        //
        // (**) since we deal with only half sphere we are interested 
        //      in the part below min(c1, c2) in the case of lower envelope
        //  and in the part above max(c1, c2) in the case of upper envelope
        //
        // substituting z in the sphere equation we get the ellipse equation:
        // r*x^2 + s*y^2 + t*x*y + u*x + v*y + w = 0 where:
        //
        //         (a1-a2)^2            (b1-b2)^2       2(a1-a2)(b1-b2)
        // r = 1 + ---------    s = 1 + ---------   t = ---------------
        //         (c1-c2)^2            (c1-c2)^2          (c1-c2)^2
        //
        //            2c1(a1-a2)    m(a1-a2)
        // u = -2a1 + ---------- - ----------
        //             (c1-c2)     (c1-c2)^2
        //
        //            2c1(b1-b2)    m(b1-b2)
        // v = -2b1 + ---------- - ----------          // here we have c1 != c2
        //             (c1-c2)     (c1-c2)^2
        //
        //                                    m*c1        m^2
        // w = a1^2 + b1^2 + c1^2 - sqr_r1 - ------- + ----------
        //                                   (c1-c2)   4(c1-c2)^2

        // since we can solve only equations with integer coefficients we
        // multiply everything by 4(c1-c2)^2, and get:
        // R*x^2 + S*y^2 + T*x*y + U*x + V*y + W = 0 where:
        //    R = 4(c1-c2)^2 + 4(a1-a2)^2
        //    S = 4(c1-c2)^2 + 4(b1-b2)^2
        //    T = 8(a1-a2)(b1-b2)
        //    U = -8a1(c1-c2)^2 + 8c1(a1-a2)(c1-c2) - 4m(a1-a2)
        //    V = -8b1(c1-c2)^2 + 8c1(b1-b2)(c1-c2) - 4m(b1-b2)
        //    W = 4(a1^2 + b1^2 + c1^2 - sqr_r1)(c1-c2)^2 - 4mc1(c1-c2) + m^2
        // TODO: in the new version coefficients can be rationals
        Rational a_diff = a1 - a2;
        Rational b_diff = b1 - b2;
        Rational c_diff = c1 - c2;
        
        Rational sqr_a_diff = a_diff * a_diff;
        Rational sqr_b_diff = b_diff * b_diff;
        Rational sqr_c_diff = c_diff * c_diff;

        Rational sqr_a1 = a1*a1, sqr_a2 = a2*a2;
        Rational sqr_b1 = b1*b1, sqr_b2 = b2*b2;
        Rational sqr_c1 = c1*c1, sqr_c2 = c2*c2;
        
        Rational m = sqr_a1 + sqr_b1 + sqr_c1 -
                 sqr_a2 - sqr_b2 - sqr_c2 + sqr_r2 - sqr_r1;

        Rational R = 4*sqr_c_diff + 4*sqr_a_diff;
        Rational S = 4*sqr_c_diff + 4*sqr_b_diff;
        Rational T = 8*a_diff*b_diff;
        Rational U = -8*a1*sqr_c_diff + 8*c1*c_diff*a_diff - 4*m*a_diff;
        Rational V = -8*b1*sqr_c_diff + 8*c1*c_diff*b_diff - 4*m*b_diff;
        Rational W = 4*sqr_c_diff*(sqr_a1+sqr_b1+sqr_c1-sqr_r1) -
                 4*m*c1*c_diff + m*m;

        // if the full spheres do not intersect, the equation we get has no
        // real solution, so we should check it:
        bool ellipse_is_point = false;  
        if (!parent.is_valid_conic_equation(R, S, T, U, V, W, 
                                            ellipse_is_point))
        {
          return o;
        }
        
        // we need only a part of the ellipse (as stated in (**)) so we
        // construct the cutting line, which is:
        //    equation (*) <= min(c1,c2)    -- for lower envelope
        //    equation (*) >= max(c1,c2)    -- for upper envelope
        Rational z_plane;
        if (parent.m_is_lower)
          z_plane = ((c1 < c2) ? c1 : c2);
        else
          z_plane = ((c1 > c2) ? c1 : c2);


        // we get (for lower envelope)
        //           -2(a1-a2)x -2(b1-b2)y + m
        // (*)   z = -------------------------- <= z_plane
        //                 2(c1-c2)
        // and since we need integer coefficients, and also need to be in the
        // positive side of the line (i.e., our halfplane equation should be of
        // type ax+by+c >= 0), we have:
        // sign_c_diff* [2(a1-a2)x + 2(b1-b2)y - m + 2(c1-c2)*z_plane] >= 0

        // for upper envelope, we should multiply the line equation by -1
        int envelope_coef = 1;
        if (!parent.m_is_lower)
          envelope_coef = -1;
        
        Sign sign_c_diff = CGAL_NTS sign(c_diff);
        Rational la = envelope_coef*2*a_diff*sign_c_diff;
        Rational lb = envelope_coef*2*b_diff*sign_c_diff;
        Rational lc = envelope_coef*sign_c_diff*(2*c_diff*z_plane - m);

      	if (ellipse_is_point)
      	{
      	  // as specified in the is_valid_conic_equation method, the
          // intersection point is:
          //
      	  Rational px = S*(4*U - T*V)/(T*T - 4*S*R);
          px = px / 2;
      	  Rational py = -(T*px + V)/(2*S);
          // should check if the point is in the non-negative side of the
          // line
      	  if (CGAL_NTS sign(la*px + lb*py +lc) != NEGATIVE)
          {
      	    *o++ = make_object(Point_2(px, py));
          }
          return o;
      	}

        // if (a1==a2) and (b1==b2) (*) is a plane parallel to the xy-plane
        // and either all ellipse (which should be a circle) is the
        // intersection - in which case lc >= 0
        // or there is no intersection at all between the 2 half spheres -
        // in which case lc < 0
        if (CGAL_NTS compare(a_diff, 0) == EQUAL &&
            CGAL_NTS compare(b_diff, 0) == EQUAL)
        {
          Sign sign_lc = CGAL_NTS sign(lc);
          if (sign_lc != NEGATIVE)
          {
            Curve_2 res(R, S, T, U, V, W);
            parent.add_curve_to_output(res, o);
            //*o++ = make_object(Intersection_curve(res, TRANSVERSAL));
          }
          return o;
        }

        // find the intersection of the line
        //    la * x + lb * y + lc = 0
        // with the conic
        //    R*x^2 + S*y^2 + T*xy + U*x + V*y + W = 0
        Alg_point_2 source, target, pmid;
        int n_inter_points;
        if (CGAL_NTS compare(lb, 0) != EQUAL)
        {
          // Find the x-coordinates of the intersection points of the conic 
          // curve and the line y = -(la*x + lc) / lb:
          // we get a quadratic equation Ax^2 + Bx + C = 0
          // where A = lb*lb*R + la*(la*S - lb*T)
          //       B = 2*la*lc*S - lb*(lc*T + la*V - lb*U)
          //       C = S*lc*lc + lb*(lb*W - lc*V)
          Rational A = lb*lb*R + la*(la*S - lb*T),
                   B = 2*la*lc*S - lb*(lc*T + la*V - lb*U),
                   C = S*lc*lc + lb*(lb*W - lc*V);
                   
          Algebraic      inter_xs[2];
          Algebraic     *inter_xs_end;

          inter_xs_end = nt_traits.solve_quadratic_equation(A, B, C, inter_xs);
          n_inter_points = inter_xs_end - inter_xs;
                            
          if (n_inter_points > 0)
            source = Alg_point_2(inter_xs[0],
                             -(la*inter_xs[0] + lc) / Algebraic(lb));
          if (n_inter_points == 2)
          {
            target = Alg_point_2(inter_xs[1],
                             -(la*inter_xs[1] + lc) / Algebraic(lb));

            // Get the conic points whose x-coordinate are in the middle of the
            // two endpoints.
            // since inter_xs[0] and inter_xs[1] are the roots of a quadratic
            // equation Ax^2 + Bx + C = 0, their sum is -B/A which is rational
            Algebraic x_mid = Algebraic(Rational(-B/(2*A)));
            //Algebraic x_mid = (inter_xs[0] + inter_xs[1]) / 2;
            Alg_point_2 x_mid_point(x_mid, 0);
            
            CGAL_precondition_code(int  x_mid_n_y_points;);
            Alg_point_2 x_mid_y_points[2];

            Curve_2 inter_cv(R, S, T, U, V, W);

            CGAL_precondition_code(x_mid_n_y_points = )
              inter_cv.points_at_x(x_mid_point, x_mid_y_points);
            
            CGAL_precondition(x_mid_n_y_points > 0);

            Algebraic y1 = x_mid_y_points[0].y(), y2 = x_mid_y_points[1].y();
            if (CGAL_NTS compare (
                    Algebraic(la)*x_mid + Algebraic(lb)*y1 + Algebraic(lc),
                    0) == LARGER)
            {
              pmid = Alg_point_2(x_mid, y1);
            }
            else
            {
              CGAL_assertion(CGAL_NTS compare 
                     (Algebraic(la)*x_mid + Algebraic(lb)*y2 + Algebraic(lc),
                      0) == LARGER);
              pmid = Alg_point_2(x_mid, y2);
            }
          }
        }
        else
        { // lb == 0
          CGAL_assertion(CGAL_NTS compare(la, 0) != EQUAL);

          // Find the intersection of the vertical line x = -lc / la:
          Rational inter_x = -lc/la;
          // we should solve the quadratic equation A*y^2 + B*y + C = 0
          // where A = S
          //       B = T*inter_x + V
          //       C = R*inter_x^2 + U*inter_x + W
          Rational A = S,
                   B = T*inter_x + V,
                   C = R*inter_x*inter_x + U*inter_x + W;
                   
          Algebraic  inter_points[2];
          Algebraic *inter_points_end;

          inter_points_end =
                nt_traits.solve_quadratic_equation(A, B, C, inter_points);
          n_inter_points = inter_points_end - inter_points;

          if (n_inter_points > 0)
            source = Alg_point_2(Algebraic(inter_x), inter_points[0]);
          if (n_inter_points == 2)
          {
            target = Alg_point_2(Algebraic(inter_x), inter_points[1]);
            
            // Get the conic points whose y-coordinate are in the middle of the
            // two endpoints.
            // since inter_points[0] & inter_points[1] are roots of quadratic
            // equation, their sum is -B/A, and mid_y is -B/2A
            Algebraic y_mid = Algebraic(Rational(-B/(2*A)));

            Alg_point_2 y_mid_point(0, y_mid);
            Alg_point_2 y_mid_x_points[2];
            Curve_2 inter_cv(R, S, T, U, V, W);

            CGAL_precondition_code(int  y_mid_n_x_points =)
              inter_cv.points_at_y(y_mid_point, y_mid_x_points);

            CGAL_precondition(y_mid_n_x_points > 0);

            Algebraic x1 = y_mid_x_points[0].x(), x2 = y_mid_x_points[1].x();
            if (CGAL_NTS compare(
                        Algebraic(la)*x1 + Algebraic(lb)*y_mid + Algebraic(lc),
                        0) == LARGER)
            {
              pmid = Alg_point_2(x1, y_mid);
            }
            else
            {
              CGAL_assertion(CGAL_NTS compare (
                        Algebraic(la)*x2 + Algebraic(lb)*y_mid + Algebraic(lc),
                        0) == LARGER);
              pmid = Alg_point_2(x2, y_mid);
            }
          }
        }

        if (n_inter_points < 2)
        {          
          // we should check whether the ellipse is in the positive side of the
          // line - in which case we return the full ellipse
          // or not - in which case there is no intersection if
          // n_inter_points = 0, and a point intersection (equal to source)
          // if n_inter_points = 1

          // for this, we find a point inside the ellipse and substitute
          // its coordinates in the line equation

          Curve_2 inter_cv(R, S, T, U, V, W);
          Alg_point_2 vtan_ps[2];

          CGAL_assertion_code(int         n_vtan_ps =)
            inter_cv.vertical_tangency_points(vtan_ps);
          
          
          CGAL_assertion(n_vtan_ps == 2);

          Algebraic lval = Algebraic(la)*vtan_ps[0].x() +
                           Algebraic(lb)*vtan_ps[0].y() + Algebraic(lc);
          Sign lval_sign = CGAL_NTS sign(lval);
          if (lval_sign == POSITIVE)
          {
            // the full ellipse is in the positive side
            parent.add_curve_to_output(inter_cv, o);
            //*o++ = make_object(Intersection_curve(inter_cv, TRANSVERSAL));
            return o;
          }
          else if (lval_sign == NEGATIVE)
          {
            // the full ellipse is in the negative side, except maybe the point
            // source in the case n_inter_points = 1 (which lies on the line)
            if (n_inter_points == 1)
              *o++ = make_object(Point_2(source));
            return o;
          }

          CGAL_assertion(lval_sign == ZERO);
          // in this case lval_sign lies on the line, so it must be that
          // n_inter_points == 1 and source = vtan_ps[0]
          CGAL_assertion(n_inter_points == 1 && source == vtan_ps[0]);
          // so we try the other vertical tangency point
          lval = Algebraic(la)*vtan_ps[1].x() +
                           Algebraic(lb)*vtan_ps[1].y() + Algebraic(lc);
          lval_sign = CGAL_NTS sign(lval);
          CGAL_assertion(lval_sign != ZERO);
          
          if (lval_sign == POSITIVE)
            parent.add_curve_to_output(inter_cv, o);
            //*o++ = make_object(Intersection_curve(inter_cv, TRANSVERSAL));
          else
            *o++ = make_object(Point_2(source));

          return o;          
        }

        CGAL_assertion(n_inter_points == 2);

        // find the correct orientation of the conic between the 2 endpoints
        // it should lie on the positive side of line
        // If the mid-point forms a left-turn with the source and the target
        // points, the orientation is positive (going counterclockwise).
        // Otherwise, it is negative (going clockwise).
        static Alg_kernel k;
        typename Alg_kernel::Orientation_2 orient_f = k.orientation_2_object();
        Orientation orient;
        if (orient_f(source, pmid, target) == LEFT_TURN)
          orient = CGAL::COUNTERCLOCKWISE;
        else
          orient = CGAL::CLOCKWISE;

        Curve_2 res(R, S, T, U, V, W, orient, source, target);
        CGAL_assertion(res.is_valid());
        parent.add_curve_to_output(res, o);
        //*o++ = make_object(Intersection_curve(res, TRANSVERSAL));  
      }
      
      return o;
    }  
  };  

  /*! Get a Construct_projected_intersections_2 functor object. */
  Construct_projected_intersections_2
  construct_projected_intersections_2_object() const
  {                                                                
    return Construct_projected_intersections_2(this);
  }
   
  class Compare_z_at_xy_3
  {
  protected:
    const Self & parent;

  public:
    Compare_z_at_xy_3(const Self * p) : parent(*p)
    {}

    // check which of the surfaces is closer to the envelope at the xy
    // coordinates of point (i.e. lower if computing the lower envelope, or
    // upper if computing the upper envelope)
    // precondition: the surfaces are defined in point
    Comparison_result operator()(const Point_2& p,
                                 const Xy_monotone_surface_3& s1,
                                 const Xy_monotone_surface_3& s2) const
    {
      Comparison_result c2 = compare_in_point_second_method(p, s1, s2);

      CGAL_expensive_assertion_code(
        Comparison_result c1 = compare_in_point_first_method(p, s1, s2);
      );
      CGAL_expensive_assertion(c1 == c2);
      
      return c2;
    }

    // check which of the surfaces is closer to the envelope at the xy
    // coordinates of cv (i.e. lower if computing the lower envelope, or upper
    // if computing the upper envelope)
    // precondition: the surfaces are defined in all points of cv, and the 
    //               answer is the same for each of these points
    Comparison_result operator()(const X_monotone_curve_2& cv,
                                 const Xy_monotone_surface_3& s1,
                                 const Xy_monotone_surface_3& s2) const
    {
      // we compute a middle point on cv and use the previous function
      Point_2 mid = parent.construct_middle_point(cv);
      Comparison_result res = 
                   parent.compare_z_at_xy_3_object()(mid, s1, s2);
      return res;
    }

  protected:
    // first method of compare in point, calculates the z value of both
    // surfaces, and compares them
    Comparison_result
    compare_in_point_first_method(const Point_2& p,
                                  const Xy_monotone_surface_3& s1,
                                  const Xy_monotone_surface_3& s2) const
    {
      // find the z coordinates of surface 1 over p
      Algebraic z1 = parent.compute_envelope_z_in_point(p, s1);
      // find the z coordinates of surface 2 over p
      Algebraic z2 = parent.compute_envelope_z_in_point(p, s2);

      Sign res = CGAL_NTS sign(z1 - z2);
      if (parent.m_is_lower)
        return res;
      else
        return -res;
    }

    // second method of compare in point
    //    p = (x1, y1)
    //    s1: (x-a1)^2 + (y-b1)^2 + (z-c1)^2 = r1^2
    //    s2: (x-a2)^2 + (y-b2)^2 + (z-c2)^2 = r2^2
    // (both lower parts or upper parts)
    // then in point p we get:
    //    s1(p): (z-c1)^2 = r1^2 - (x1-a1)^2 - (y1-b1)^2 = A1
    //    s2(p): (z-c2)^2 = r2^2 - (x1-a2)^2 - (y1-b2)^2 = A2
    // so we get  z - ci = +- sqrt(Ai) where -sqrt(Ai) is for the lower part
    // and +sqrt(Ai) is for the upper part
    // we now need to compute the sign of:
    //    c1 - sqrt(A1) - (c2 - sqrt(A2))  - for lower envelope
    //    c1 + sqrt(A1) - (c2 + sqrt(A2))  - for upper envelope    
    Comparison_result
    compare_in_point_second_method(const Point_2& p,
                                   const Xy_monotone_surface_3& s1,
                                   const Xy_monotone_surface_3& s2) const
    {
      Rat_point_3 p1 = s1.center();
      Rat_point_3 p2 = s2.center();
      const Rational a1 = p1.x(), b1 = p1.y(), c1 = p1.z(),
                 a2 = p2.x(), b2 = p2.y(), c2 = p2.z();
      const Rational sqr_r1 = s1.squared_radius(), 
                     sqr_r2 = s2.squared_radius();
      const Algebraic x1 = p.x(), y1 = p.y();

      Rational c_diff = c1 - c2;
      Algebraic x_diff1 = x1 - a1, y_diff1 = y1 - b1;
      Algebraic x_diff2 = x1 - a2, y_diff2 = y1 - b2;
      
      Algebraic A1 = sqr_r1 - x_diff1*x_diff1 - y_diff1*y_diff1;
      Algebraic A2 = sqr_r2 - x_diff2*x_diff2 - y_diff2*y_diff2;

      if (CGAL_NTS sign(A1) == NEGATIVE)
        std::cout << "A1 = " << A1 << std::endl;
      if (CGAL_NTS sign(A2) == NEGATIVE)
        std::cout << "A2 = " << A2 << std::endl;
        
      Sign res;
      // sign_a_plus_b_x_sqrt_e_plus_c_x_sqrt_f is a CGAL method which
      // computes the sign of quantity: a + b * sqrt(e) + c * sqrt(f)

      res = CGAL::sign_a_plus_b_x_sqrt_e_plus_c_x_sqrt_f(Algebraic(c_diff),
                                                           Algebraic(-1),
                                                           Algebraic(1),
                                                           A1,
                                                           A2);
      return res;    
    }  
  };
   
  /*! Get a Compare_z_at_xy_3 functor object. */
  Compare_z_at_xy_3
  compare_z_at_xy_3_object() const
  {
    return Compare_z_at_xy_3(this);
  }

  class Compare_z_at_xy_above_3
  {
  protected:
    const Self & parent;

  public:
    Compare_z_at_xy_above_3(const Self * p) : parent(*p)
    {}

    // check which of the surfaces is closer to the envelope on the points above
    // the curve cv (i.e. lower if computing the lower envelope, or upper if
    // computing the upper envelope)
    // precondition: the surfaces are defined above cv
    //               the choise between s1 and s2 for the envelope is the same
    //               for every point in the infinitesimal region above cv
    //               the surfaces are EQUAL over the curve cv
    Comparison_result
    operator()(const X_monotone_curve_2& cv,
               const Xy_monotone_surface_3& s1,
               const Xy_monotone_surface_3& s2) const
    {
      Comparison_result res = parent.compare_on_side(cv, s1, s2, false);
      return res;
    }  
  };

  /*! Get a Compare_z_at_xy_above_3 functor object. */
  Compare_z_at_xy_above_3
  compare_z_at_xy_above_3_object() const
  {
    return Compare_z_at_xy_above_3(this);
  }

  class Compare_z_at_xy_below_3
  {
  protected:
    const Self & parent;

  public:
    Compare_z_at_xy_below_3(const Self * p) : parent(*p)
    {}

    Comparison_result
    operator()(const X_monotone_curve_2& cv,
               const Xy_monotone_surface_3& s1,
               const Xy_monotone_surface_3& s2) const
    {
      Comparison_result res = parent.compare_on_side(cv, s1, s2, true);
      return res;      
    }  
  };

  /*! Get a Compare_z_at_xy_below_3 functor object. */
  Compare_z_at_xy_below_3
  compare_z_at_xy_below_3_object() const
  {
    return Compare_z_at_xy_below_3(this);
  }

  /***************************************************************************/

  // public method needed for testing

  // checks if point is in the xy-range of surf
  class Is_defined_over
  {
  protected:
    const Self & parent;

  public:
    Is_defined_over(const Self * p) : parent(*p)
    {}
    
    // checks if point is in the xy-range of surf
    bool operator()(const Point_2& p, const Xy_monotone_surface_3& s) const
    {
      // project the surface on the plane
      Rat_point_2 proj_center = parent.project(s.center());
      Rat_circle_2 boundary(proj_center, s.squared_radius());

      Nt_traits nt_traits;
      Alg_kernel k;
      Alg_point_2 aproj_center(proj_center.x(), proj_center.y());
      Alg_circle_2 aboundary(aproj_center, nt_traits.convert(s.squared_radius()));

      // check if the projected point is inside the projected boundary
      return (!k.has_on_unbounded_side_2_object()(aboundary, p));
    }
  };

  /*! Get a Is_defined_over functor object. */
  Is_defined_over is_defined_over_object() const
  {
    return Is_defined_over(this);
  }

  /***************************************************************************/

  // helper methods
    
  // compare the surfaces over the side (as specified in the compare_on_right
  // parameter) of the curve, assuming they are defined there
  Comparison_result compare_on_side(const X_monotone_curve_2& cv,
                                    const Xy_monotone_surface_3& s1,
                                    const Xy_monotone_surface_3& s2,
                                    bool compare_on_right) const
  {
    // cv(x,y) : r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0
    // let p be the leftmost endpoint of cv, p=(x0, y0)
    // the tangence of cv at p is a line. on the infinitesimal region
    // near p the relation between the surfaces to the right of cv is
    // the same as the relation between the tangences of the surfaces
    // in p to the right of this line (unless the tangence of the surface
    // is vertical)

    // we take a point in the internal of the curve, not an endpoint
    // since we assume that such point represents better what is going
    // on all internal curve points
    Point_2 cv_point = construct_middle_point(cv);
    Algebraic x0 = cv_point.x(), y0 = cv_point.y();

    // d(cv)/dx : 2r*x + 2s*y*dy/dx + t*y + t*x*dy/dx +u + v*dy/dx = 0
    // in point p=(x0,y0) we get
    // dy         m
    // --  = y' = -    where m = -2rx0 -ty0 - u
    // dx         n          n = 2sy0 + tx0 + v
    // if n != 0 (if n = 0 we have a vertical line).
    //
    // So the tangence equation (in p) is:
    //    n =  0:    x = x0
    //    n != 0:    y - y0 = y'(x-x0) ==> -y'x + y + (y'x0 - y0) = 0
    // and in general we have:
    //    -m*x + n*y + (m*x0 -n*y0) = 0 (with integer coordinates)
    const Rational r = cv.r(), s = cv.s(), t = cv.t(),
               u = cv.u(), v = cv.v(), w = cv.w();
    Algebraic m = -1 * (2*r*x0 + t*y0 + u);
    Algebraic n = 2*s*y0 + t*x0 + v;
    // line coefficients: A3, B3, C3
    Algebraic A3 = -1*m, B3 = n, C3 = m*x0 - n*y0;

    // the tangences of the spheres (in point (x0,y0,z0)):
    Algebraic z0 = compute_envelope_z_in_point(cv_point, s1);

    // we assume the surfaces are equal over cv:
    CGAL_expensive_precondition_code(
      Algebraic z0_2 = compute_envelope_z_in_point(cv_point, s2);
    )
    // this test can be very time consuming ...
    CGAL_expensive_precondition(CGAL_NTS compare(z0, z0_2) == EQUAL);

    // the sphere i : fi(x,y,z) = (x-ai)^2 + (y-bi)^2 + (z-ci)^2 - ri^2 = 0
    // dfi / dx = 2(x-ai) + 2(z-ci)*dz/dx = 0
    // dfi / dy = 2(y-bi) + 2(z-ci)*dz/dy = 0
    // if z = ci the tangent plane is vertical - if only one of the tangent
    // planes is vertical, them its sphere wins (i.e. is on envelope).
    // we assume not both are tangent, since this means that they are the
    // same sphere
    // if z != ci the tangent plane is:

    //      z-z0 = dz/dx (x-x0) + dz/dy (y-y0)
    // ==>
    //      (x0-ai)(x-x0) + (y0-bi)(y-y0) + (z0-ci)(z-z0) = 0
    //      Ai*x + Bi*y + Ci*z + Di = 0
    // where  Ai = (x0-ai)
    //        Bi = (y0-bi)
    //        Ci = (z0-ci)
    //        Di = -(x0-ai)x0 - (y0-bi)y0 - (z0-ci)z0
    //
    // and we solve the problem as for triangles
    Rat_point_3 p1 = s1.center();
    Rat_point_3 p2 = s2.center();
    const Rational a1 = p1.x(), b1 = p1.y(), c1 = p1.z(),
               a2 = p2.x(), b2 = p2.y(), c2 = p2.z();
    Algebraic A1 = x0 - a1, B1 = y0 - b1, C1 = z0 - c1;
    Algebraic A2 = x0 - a2, B2 = y0 - b2, C2 = z0 - c2;
    if (C1 != 0 && C2 != 0)
    {
      Sign sign1 = CGAL_NTS sign((A2*A3+B2*B3)/C2-(A1*A3+B1*B3)/C1);
      // to make sure the direction is correct, we take a second point on the
      // line: for vertical line we take (x0, y0+1)
      //       otherwise we take (x0+1, y0+ m/n)
      Algebraic x1, y1;
      if (n == 0)
      {
        x1 = x0;
        y1 = y0+1;
      }
      else
      {
        x1 = x0+1;
        y1 = y0 + (m/n);
      }
      Sign sign2 = CGAL_NTS sign(-B3*x1+A3*y1-(-B3*x0+A3*y0));

      // the answer negates according to the side of the line we ask of
      Sign sign3 = (compare_on_right ? (CGAL_NTS sign(1)) :
                                       (CGAL_NTS sign(-1)));

      return sign1 * sign2 * sign3;

    }
    else if (C1 != 0 && C2 == 0)
    {
      // sphere 2 is on the envelope (both lower & upper)
      return LARGER;
    }
    else if (C1 == 0 && C2 != 0)

    {
      // sphere 1 is on the envelope (both lower & upper)
      return SMALLER;
    }
    else
      CGAL_error();

    return EQUAL;
  }

  Rat_point_2 project(const Rat_point_3& p) const
  {
    return Rat_point_2(p.x(), p.y());
  }

  // compute the z coordinate of the surface s in point p on the envelope
  // (i.e. take lower point if lower envelope, upper otherwise)
  // precondition: s is defined at p
  Algebraic compute_envelope_z_in_point(const Point_2& p,
                                   const Xy_monotone_surface_3& s) const
  {
    Algebraic res;
   
    // the point coordinates
    const Algebraic x1 = p.x(), y1 = p.y();

    // the surface equations
    Rat_point_3 center = s.center();
    const Rational a = center.x(), b = center.y(), c = center.z();
    const Rational sqr_r = s.squared_radius();
    
    // we substitute x1 and y1 in the equation of s
    // (x-a)^2 + (y-b)^2 + (z-c)^2 = r^2
    // and get a quadratic equation of z:
    // z^2 - 2cz + [(x1-a)^2 + (y1-b)^2 + c^2 - r^2] = 0
    Algebraic x_diff = x1 - a, y_diff = y1 - b;
    // the coefficients are:
    Algebraic A = 1,
              B = -2*c,
              C = x_diff*x_diff + y_diff*y_diff + c*c - sqr_r;
    
    Algebraic  zs[2];
    Algebraic *zs_end;
    int   n_zs;

    Nt_traits nt_traits;
    zs_end = nt_traits.solve_quadratic_equation(A, B, C, zs);
    n_zs = zs_end - zs;

    CGAL_precondition(n_zs > 0);

    if (n_zs == 1)
      // only one point is defined at p, this is the result
      return zs[0];
    CGAL_assertion(n_zs == 2);

    Comparison_result comp = CGAL_NTS compare(zs[0], zs[1]);
    if (m_is_lower)
      res = ((comp == SMALLER) ? zs[0] : zs[1]);
    else
      res = ((comp == LARGER) ? zs[0] : zs[1]);

    return res;
  }

  // construct the point in the middle of cv
  Point_2 construct_middle_point(const X_monotone_curve_2& cv) const
  {
    // get the x-value of the middle point
    Alg_kernel k;
    Alg_point_2 mid_x = k.construct_midpoint_2_object()(cv.source(), 
                                                        cv.target());

// TODO_NEW_DESIGN - this is not implemented in X_monotone_curve_2, but maybe we want it there?
//    if (cv.is_segment())
//      return mid_x;
    if (cv.is_vertical())
      return Point_2(mid_x);

    return Point_2(cv.point_at_x(mid_x));
  }


  // for the test
  Point_2 construct_middle_point(const Point_2& p1, const Point_2& p2) const
  {
    Alg_kernel k;
    return Point_2(k.construct_midpoint_2_object()(p1, p2));
  }

  // check if the equation
  // r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0
  // has real solutions
  // is_point is set to true if the equation represents just one point
  template <class NT> 
  bool is_valid_conic_equation(const NT& r, const NT& s, const NT& t,
                               const NT& u, const NT& v, const NT& w,
                               bool &is_point) const
  {
    // initialize is_point to false, and will change it when we detect
    // that the equation represents a point
    is_point = false; 
    // (*)  r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0
    // we fix x, and get a 1-variable quadratic equation:
    // (**) s*y^2 + (tx + v)*y + (rx^2 + ux + w) = 0
    // (*) has real solution (x,y) iff there exists x such that (**) has a
    // solution y, i.e. discriminant(**) >= 0
    // discriminant(**) = f(x) = (tx + v)^2 -4s(rx^2 + ux + w) 
    //                         = (t^2 - 4sr)*x^2 + (stv - 4su)*x + (v^2 - 4sw)
    //                         = A*x^2 + B*x + C >= 0
    // where A = t^2 - 4sr
    //       B = stv - 4su
    //       C = v^2 - 4sw
    // so we should check if there exists x such that f(x) >= 0
    // if A > 0 we have a smiling parabula, and a positive answer
    // (the conic equation in this case represents hyperbola or 2 
    // intersecting lines)
    Sign sign_A = CGAL_NTS sign(t*t - 4*s*r);
    if (sign_A == POSITIVE)
      return true;
    // if A < 0 we have a sad parabula, so we should check if it crosses the
    //          x-axis, i.e. if the equation f(x) = 0 has a real solution x.
    //          this means that discriminant(f(x)) >= 0
    //          discriminant(f(x)) = B^2 - 4AC 
    //                             = (2tv-4su)^2 - 4(t^2-4sr)(v^2-4sw)
    //                             = s(-tvu + su^2 + wt^2 + rv^2 - 4srw)
    if (sign_A == NEGATIVE)
    {
      // (in this case the conic equation represents ellipse, circle, point 
      // or no curve)
      Sign sign_s = CGAL_NTS sign(s);
      Sign sign_eq = CGAL_NTS sign(-t*v*u + s*u*u + w*t*t + r*v*v - 4*s*r*w);
      // if sign_eq = 0 then discriminant(f(x))=0, and so we have only one x
      // solution for f(x), say x0. since we get f(x0)=0 and f(x)<0 forall 
      // x!=x0, we have only one solution for (**). So the equation represents
      // a point with coordinates x0=-B/2A, y0=-(tx0 + v)/2s
      if (sign_eq == ZERO)
	      is_point = true;

      Sign sign_disc = CGAL_NTS sign(int(sign_s * sign_eq));
      return (sign_disc != NEGATIVE);
    }
    // if A = 0 we get (***) f(x) = (stv - 4su)*x + (v^2 - 4sw) = B*x + C
    //          if B != 0 we get a line equation, which always has x
    //                    such that f(x) >= 0
    //          if B = 0  then f(x) = v^2 - 4sw = C and should check its sign
    CGAL_assertion(sign_A == ZERO);
    // (in this case the conic equation represents parabola, 2 parallel lines,
    // 1 line or no curve)
    Sign sign_B = CGAL_NTS sign(s*(t*v - 4*u));
    if (sign_B != ZERO)
      return true;

    Sign sign_C = CGAL_NTS sign(v*v - 4*s*w);

    return (sign_C != NEGATIVE);
  }

  // for the test:
  Point_2 vertical_ray_shoot_2(const Point_2& pt,
                               const X_monotone_curve_2& cv) const
  {
    if (cv.is_vertical())
    {
      Alg_kernel k;
      if (!k.less_y_2_object()(cv.left(), pt))
        return cv.left();
      else
      {
        CGAL_assertion(k.less_y_2_object()(cv.right(), pt));
        return cv.right();
      }
    }
    else
      return cv.point_at_x(pt);
  }

  template <class OutputIterator>
  OutputIterator add_curve_to_output(const Curve_2& c, OutputIterator oi) const
  {
    Object objs[2];
    Object* p_obj = this->make_x_monotone_2_object()(c, objs);
    for(Object* o = objs; o != p_obj; ++o)
    {
      X_monotone_curve_2 cv;
      if(assign(cv, *o))
      {
        *oi++ = make_object(Intersection_curve(cv, 1));
      }
      else
      {
        Point_2 pt;
        CGAL_assertion(assign(pt, *o));
        assign(pt, *o);
        *oi++ = make_object(pt);
      }
    }
    return oi;
  }

  /*! Default constructor. */
  Env_sphere_traits_3() : m_is_lower(true)
  {}

protected:
  mutable bool m_is_lower;
};

/*!
 * Compare two spheres: first compare their center points in an
 * xyz-lexicographic order, then by their radii.
 */
template <class Kernel>
bool operator< (const CGAL::Sphere_3<Kernel> & a,
                const CGAL::Sphere_3<Kernel> & b)
{
  Kernel            k;
  Comparison_result res = k.compare_xyz_3_object()(a.center(), b.center());

  if (res == EQUAL)
  {
    res = CGAL::compare (a.squared_radius(), b.squared_radius());
  }

  return (res == SMALLER);
}

/*!
 * Compare two spheres for equality.
 */
template <class Kernel>
bool operator== (const typename Kernel::Sphere_3& a,
                 const typename Kernel::Sphere_3& b)
{
  Kernel            k;

  if (! k.equal_3_object() (a.center(), b.center()))
    return (false);

  return (CGAL::compare (a.squared_radius(), b.squared_radius()) == EQUAL);
}

CGAL_END_NAMESPACE

#endif // ENVELOPE_SPHERES_TRAITS_3_H