text: // Copyright (c) 2013  INRIA Sophia Antipolis -  Mediterranee (France).
  // All rights reserved.
  //
  // This file is part of CGAL (www.cgal.org)
  //
  // $URL$
  // $Id$
  // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
  //
  //
  // Author(s)     : Olivier Devillers
  
  #include <CGAL/Cartesian.h>
  #include <CGAL/CGAL_Ipelet_base.h>
  #include <CGAL/Object.h>
  
  #include "include/CGAL_ipelets/pencils.h"
  
  
  namespace CGAL_pencils{
  
  typedef CGAL::Cartesian<double>                                               Kernel;
  // --------------------------------------------------------------------
  
  const std::string sublabel[] = {
    "Circle in pencil, orthogonal to circle", "Circle  orthogonal to three circles", "Help"
  };
  
  const std::string helpmsg[] = {
    "Draw the circle orthogonal to a circle (primary selection) in the pencil generated by two circles",
    "Draw the circle orthogonal to three circles"
  };
  
  class pencilIpelet
    : public CGAL::Ipelet_base<Kernel,3> {
  public:
    pencilIpelet()
      :CGAL::Ipelet_base<Kernel,3>("Pencils of circles",sublabel,helpmsg){}
    void protected_run(int);
  };
  // --------------------------------------------------------------------
  
  void pencilIpelet::protected_run(int fn)
  {
    Circle_2 circ;     //constructed circle:
  
    if (fn==2) {
      show_help();
      return;
    }
  
    Circle_2  c,c0,c1,c2;
    std::list<Point_2> pt_list,pt_list1;
    std::list<Circle_2> cir_list,cir_list1;
  
  
    int i=get_IpePage()->primarySelection();
  
    if (i<0) {
      print_error_message(("No mark or circle selected"));
      return;
    }
  
    read_one_active_object(get_IpePage()->object(i),CGAL::dispatch_or_drop_output<Point_2,Circle_2>(
         std::back_inserter(pt_list1),
         std::back_inserter(cir_list1)));
  
    std::list<Point_2>::iterator it1=pt_list1.begin();
    std::list<Circle_2>::iterator cit1=cir_list1.begin();
  
    if (pt_list1.empty() && cir_list1.empty()){
    print_error_message(("Primary selection must be a mark or a circle"));
      return;
    }
    if (it1!=pt_list1.end())  {c=Circle_2(*it1,0);} else c=*cit1;
  
    Iso_rectangle_2 bbox=
    read_active_objects(
                        CGAL::dispatch_or_drop_output<Point_2,Circle_2>(
        std::back_inserter(pt_list),
        std::back_inserter(cir_list)
      )
    );
  
    std::list<Point_2>::iterator it=pt_list.begin();
    std::list<Circle_2>::iterator cit=cir_list.begin();
  
  
    // read c0
    if (it!=pt_list.end())  { c0=Circle_2(*it,0); ++it;}
    else if (cit!=cir_list.end())  { c0=*cit; ++cit;}
    else {print_error_message(("Not enough marks or circles selected")); return;}
    // read c1
    if (it!=pt_list.end())  { c1=Circle_2(*it,0); ++it;}
    else if (cit!=cir_list.end())  { c1=*cit; ++cit;}
    else {print_error_message(("Not enough marks or circles selected")); return;}
    // read c2
    if (it!=pt_list.end())  { c2=Circle_2(*it,0); ++it;}
    else if (cit!=cir_list.end())  { c2=*cit; ++cit;}
    else {print_error_message(("Not enough marks or circles selected")); return;}
    if ((it!=pt_list.end())||(cit!=cir_list.end()))
      {print_error_message(("Warning: more than three marks or circles selected"));}
  
    // c is the primary selection
    if (c==c1) c1=c0;
    if (c==c2) c2=c0;
  
  
    switch(fn){
    case 0:
      // Circle orthogonal to circle c in pencil generated by c1 c2
      circ = compute_circle_in_pencil<Kernel>(c,c1,c2);
      break;
    case 1:
      // Circle orthogonal to three circles
      circ = compute_circle_orthogonal<Kernel>(c,c1,c2);
      break;
  
    }     //end of switch
  
  
    // detect degenerate case
    if (circ==Circle_2()){
      Kernel::Vector_2  v;
      if(fn==0)
        v=Kernel::Vector_2(
            c2.center().y()-c1.center().y(),c2.center().x()-c1.center().x());
      else v=c2.center()-c1.center();
        Kernel::FT sqr_length= 1 / v.squared_length();
        double length = 600 * sqrt( sqr_length);
        v = Kernel::FT(length)*v;
        Point_2 q1=c.center()+ v;
        Point_2 q2=c.center()- v;
        print_error_message(
           "degenerate case, circle is a line");
        Kernel::Segment_2 s(q1,q2);
        draw_in_ipe(s);
        return;
    }
  
    if (circ.squared_radius()>0){
      draw_in_ipe(circ);
    }else{
      print_error_message(("Computed circle is imaginary"));
    }
  }
  }
  
  CGAL_IPELET(CGAL_pencils::pencilIpelet)
  