From b4932453d59af9ef03332f3927be351e5b6298d1 Mon Sep 17 00:00:00 2001
From: mdinger <mdinger.bugzilla@gmail.com>
Date: Wed, 5 Mar 2014 22:04:17 -0500
Subject: [PATCH 1/4] Initial commit to make a 3 point arc.  Includes a new
 icon and cursor.  Just copies create point.

---
 src/Mod/Complete/Gui/Workbench.cpp                 |    2 +
 src/Mod/Sketcher/Gui/CommandCreateGeo.cpp          |  128 ++++++++++++++++++++
 src/Mod/Sketcher/Gui/Resources/Makefile.am         |    1 +
 src/Mod/Sketcher/Gui/Resources/Sketcher.qrc        |    1 +
 .../Resources/icons/Sketcher_Create3PointArc.svg   |   99 +++++++++++++++
 src/Mod/Sketcher/Gui/Workbench.cpp                 |    2 +
 6 files changed, 233 insertions(+), 0 deletions(-)
 create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create3PointArc.svg

diff --git a/src/Mod/Complete/Gui/Workbench.cpp b/src/Mod/Complete/Gui/Workbench.cpp
index ebc9b06..a67b47f 100644
--- a/src/Mod/Complete/Gui/Workbench.cpp
+++ b/src/Mod/Complete/Gui/Workbench.cpp
@@ -241,6 +241,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
     geom->setCommand("Sketcher geometries");
     *geom << "Sketcher_CreatePoint"
           << "Sketcher_CreateArc"
+          << "Sketcher_Create3PointArc"
           << "Sketcher_CreateCircle"
           << "Sketcher_CreateLine"
           << "Sketcher_CreatePolyline"
@@ -503,6 +504,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
           << "Separator"
           << "Sketcher_CreatePoint"
           << "Sketcher_CreateArc"
+          << "Sketcher_Create3PointArc"
           << "Sketcher_CreateCircle"
           << "Sketcher_CreateLine"
           << "Sketcher_CreatePolyline"
diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
index 88a5349..6560a39 100644
--- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
+++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
@@ -1214,6 +1214,133 @@ bool CmdSketcherCreateArc::isActive(void)
     return isCreateGeoActive(getActiveGuiDocument());
 }
 
+
+// ======================================================================================
+
+/* XPM */
+static const char *cursor_create3pointarc[]={
+"32 32 3 1",
+"+ c white",
+"# c red",
+". c None",
+"......+...........###...........",
+"......+...........#.#...........",
+"......+...........###...........",
+"......+..............##.........",
+"......+...............##........",
+".......................#........",
+"+++++...+++++...........#.......",
+"........................##......",
+"......+..................#......",
+"......+..................#......",
+"......+...................#.....",
+"......+...................#.....",
+"......+...................#.....",
+"..........................#.....",
+"..........................#.....",
+"..........................#.....",
+"..........................#.....",
+".........................#......",
+".......................###......",
+".......................#.#......",
+".......................###......",
+"...###.................#........",
+"...#.#................#.........",
+"...###...............#..........",
+"......##...........##...........",
+".......###.......##.............",
+"..........#######...............",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................"};
+
+class DrawSketchHandler3PointArc : public DrawSketchHandler
+{
+public:
+    DrawSketchHandler3PointArc() : selectionDone(false) {}
+    virtual ~DrawSketchHandler3PointArc() {}
+
+    virtual void activated(ViewProviderSketch *sketchgui)
+    {
+        setCursor(QPixmap(cursor_create3pointarc),7,7);
+    }
+
+    virtual void mouseMove(Base::Vector2D onSketchPos)
+    {
+        setPositionText(onSketchPos);
+        if (seekAutoConstraint(sugConstr, onSketchPos, Base::Vector2D(0.f,0.f))) {
+            renderSuggestConstraintsCursor(sugConstr);
+            return;
+        }
+        applyCursor();
+    }
+
+    virtual bool pressButton(Base::Vector2D onSketchPos)
+    {
+        EditPoint = onSketchPos;
+        selectionDone = true;
+        return true;
+    }
+
+    virtual bool releaseButton(Base::Vector2D onSketchPos)
+    {
+        if (selectionDone){
+            unsetCursor();
+            resetPositionText();
+
+            Gui::Command::openCommand("Add sketch point");
+            Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))",
+                      sketchgui->getObject()->getNameInDocument(),
+                      EditPoint.fX,EditPoint.fY);
+            Gui::Command::commitCommand();
+            Gui::Command::updateActive();
+
+            // add auto constraints for the line segment start
+            if (sugConstr.size() > 0) {
+                createAutoConstraints(sugConstr, getHighestCurveIndex(), Sketcher::start);
+                sugConstr.clear();
+            }
+
+            sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider
+        }
+        return true;
+    }
+protected:
+    bool selectionDone;
+    Base::Vector2D EditPoint;
+    std::vector<AutoConstraint> sugConstr;
+};
+
+
+DEF_STD_CMD_A(CmdSketcherCreate3PointArc);
+
+CmdSketcherCreate3PointArc::CmdSketcherCreate3PointArc()
+  : Command("Sketcher_Create3PointArc")
+{
+    sAppModule      = "Sketcher";
+    sGroup          = QT_TR_NOOP("Sketcher");
+    sMenuText       = QT_TR_NOOP("Create a 3 point arc");
+    sToolTipText    = QT_TR_NOOP("Create an arc in the sketch");
+    sWhatsThis      = sToolTipText;
+    sStatusTip      = sToolTipText;
+    sPixmap         = "Sketcher_Create3PointArc";
+    eType           = ForEdit;
+}
+
+void CmdSketcherCreate3PointArc::activated(int iMsg)
+{
+    ActivateHandler(getActiveGuiDocument(),new DrawSketchHandler3PointArc() );
+}
+
+bool CmdSketcherCreate3PointArc::isActive(void)
+{
+    return isCreateGeoActive(getActiveGuiDocument());
+}
+
+
+
 // ======================================================================================
 
 /* XPM */
@@ -2135,6 +2262,7 @@ void CreateSketcherCommandsCreateGeo(void)
 
     rcCmdMgr.addCommand(new CmdSketcherCreatePoint());
     rcCmdMgr.addCommand(new CmdSketcherCreateArc());
+    rcCmdMgr.addCommand(new CmdSketcherCreate3PointArc());
     rcCmdMgr.addCommand(new CmdSketcherCreateCircle());
     rcCmdMgr.addCommand(new CmdSketcherCreateLine());
     rcCmdMgr.addCommand(new CmdSketcherCreatePolyline());
diff --git a/src/Mod/Sketcher/Gui/Resources/Makefile.am b/src/Mod/Sketcher/Gui/Resources/Makefile.am
index abb54c9..2bb55a3 100644
--- a/src/Mod/Sketcher/Gui/Resources/Makefile.am
+++ b/src/Mod/Sketcher/Gui/Resources/Makefile.am
@@ -61,6 +61,7 @@ icons/Constraint_PointOnObject.svg \
 		icons/Sketcher_ConstrainLock.svg \
 		icons/Sketcher_ConstrainVertical.svg \
 		icons/Sketcher_CreateArc.svg \
+        icons/Sketcher_Create3PointArc.svg \
 		icons/Sketcher_CreateCircle.svg \
 		icons/Sketcher_CreateLine.svg \
 		icons/Sketcher_CreatePoint.svg \
diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
index 6a2191e..391f5d0 100644
--- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
+++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc
@@ -51,6 +51,7 @@
         <file>icons/Sketcher_ConstrainParallel.svg</file>
         <file>icons/Sketcher_ConstrainVertical.svg</file>
         <file>icons/Sketcher_CreateArc.svg</file>
+        <file>icons/Sketcher_Create3PointArc.svg</file>
         <file>icons/Sketcher_CreateCircle.svg</file>
         <file>icons/Sketcher_CreateLine.svg</file>
         <file>icons/Sketcher_CreatePoint.svg</file>
diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create3PointArc.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create3PointArc.svg
new file mode 100644
index 0000000..d2fc840
--- /dev/null
+++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create3PointArc.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64"
+   height="64"
+   id="svg3003"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="New document 2">
+  <defs
+     id="defs3005" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4"
+     inkscape:cx="22.518427"
+     inkscape:cy="31.132034"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="862"
+     inkscape:window-height="829"
+     inkscape:window-x="40"
+     inkscape:window-y="173"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata3008">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-988.36218)">
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#ff0000;stroke-width:8;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path3789"
+       sodipodi:cx="9.75"
+       sodipodi:cy="36"
+       sodipodi:rx="28.5"
+       sodipodi:ry="29.75"
+       d="M -18.75,35.999999 A 28.5,29.75 0 0 1 38.25,36"
+       transform="matrix(0.88374305,0,0,0.83607912,23.758505,998.07501)"
+       sodipodi:start="3.1415927"
+       sodipodi:end="6.2831853"
+       sodipodi:open="true" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path3795"
+       sodipodi:cx="32.875"
+       sodipodi:cy="13.75"
+       sodipodi:rx="1.375"
+       sodipodi:ry="1.25"
+       d="m 34.25,13.75 a 1.375,1.25 0 1 1 -2.75,0 1.375,1.25 0 1 1 2.75,0 z"
+       transform="translate(-1.25,989.86218)" />
+    <path
+       transform="translate(-25.875,1014.6122)"
+       sodipodi:type="arc"
+       style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path3795-1"
+       sodipodi:cx="32.875"
+       sodipodi:cy="13.75"
+       sodipodi:rx="1.375"
+       sodipodi:ry="1.25"
+       d="m 34.25,13.75 a 1.375,1.25 0 1 1 -2.75,0 1.375,1.25 0 1 1 2.75,0 z" />
+    <path
+       transform="translate(24.375,1014.6122)"
+       sodipodi:type="arc"
+       style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:8;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path3795-7"
+       sodipodi:cx="32.875"
+       sodipodi:cy="13.75"
+       sodipodi:rx="1.375"
+       sodipodi:ry="1.25"
+       d="m 34.25,13.75 a 1.375,1.25 0 1 1 -2.75,0 1.375,1.25 0 1 1 2.75,0 z" />
+  </g>
+</svg>
diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp
index 3d6b36d..828de47 100644
--- a/src/Mod/Sketcher/Gui/Workbench.cpp
+++ b/src/Mod/Sketcher/Gui/Workbench.cpp
@@ -62,6 +62,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
     geom->setCommand("Sketcher geometries");
     *geom << "Sketcher_CreatePoint"
           << "Sketcher_CreateArc"
+          << "Sketcher_Create3PointArc"
           << "Sketcher_CreateCircle"
           << "Sketcher_CreateLine"
           << "Sketcher_CreatePolyline"
@@ -122,6 +123,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
     geom->setCommand("Sketcher geometries");
     *geom << "Sketcher_CreatePoint"
           << "Sketcher_CreateArc"
+          << "Sketcher_Create3PointArc"
           << "Sketcher_CreateCircle"
           << "Sketcher_CreateLine"
           << "Sketcher_CreatePolyline"
-- 
1.7.9


From a854847c237a72f249e2437876a0f182dcdeb07e Mon Sep 17 00:00:00 2001
From: mdinger <mdinger.bugzilla@gmail.com>
Date: Thu, 13 Mar 2014 02:30:01 -0400
Subject: [PATCH 2/4] Draws correctly after first click.

---
 src/Base/Tools2D.h                        |    6 +
 src/Mod/Sketcher/Gui/CommandCreateGeo.cpp |  210 ++++++++++++++++++++++++++---
 2 files changed, 196 insertions(+), 20 deletions(-)

diff --git a/src/Base/Tools2D.h b/src/Base/Tools2D.h
index 1b1b07f..0e2b9b7 100644
--- a/src/Base/Tools2D.h
+++ b/src/Base/Tools2D.h
@@ -61,6 +61,7 @@ public:
   inline bool      operator== (const Vector2D &rclVct) const;
   inline Vector2D  operator+ (const Vector2D &rclVct) const;
   inline Vector2D  operator- (const Vector2D &rclVct) const;
+  inline Vector2D  operator/ (const double x) const;
 
   inline void Set (double fPX, double fPY);
   inline void Scale (double fS);
@@ -221,6 +222,11 @@ inline double Vector2D::operator* (const Vector2D &rclVct) const
   return (fX * rclVct.fX) + (fY * rclVct.fY);
 }
 
+inline Vector2D Vector2D::operator/ (const double x) const
+{
+  return Vector2D(fX / x, fY / x);
+}
+
 inline void Vector2D::Scale (double fS)
 {
   fX *= fS;
diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
index 6560a39..c62fc80 100644
--- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
+++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
@@ -49,6 +49,40 @@ using namespace SketcherGui;
 
 /* helper functions ======================================================*/
 
+// Return counter-clockwise angle from horizontal out of p1 to p2 in radians.
+double GetPointAngle (const Base::Vector2D &p1, const Base::Vector2D &p2)
+{
+  double dX = p2.fX - p1.fX;
+  double dY = p2.fY - p1.fY;
+  return dY >= 0 ? atan2(dY, dX) : atan2(dY, dX) + 2*M_PI;
+}
+
+/*
+Find the centerpoint of a circle drawn through any 3 points:
+
+Given points p1-3, draw 2 lines: S12 and S23 which each connect two points.  From the
+midpoint of each line, draw a perpendicular line (S12p/S23p) across the circle.  These
+lines will cross at the centerpoint.
+
+Mathematically, line S12 will have a slope of m12 which can be determined.  Therefore,
+the slope m12p is -1/m12. Line S12p will have an equation of y = m12p*x + b12p.  b12p can
+be solved for using the midpoint of the line.  This can be done for both lines.  Since
+both S12p and S23p cross at the centerpoint, solving the two equations together will give
+the location of the centerpoint.
+*/
+Base::Vector2D GetCircleCenter (const Base::Vector2D &p1, const Base::Vector2D &p2, const Base::Vector2D &p3)
+{
+  double m12p = (p1.fX - p2.fX) / (p2.fY - p1.fY);
+  double m23p = (p2.fX - p3.fX) / (p3.fY - p2.fY);
+  double x = 1/( 2*(m12p - m23p) ) * ( (pow(p3.fX, 2) - pow(p2.fX, 2)) / (p3.fY - p2.fY) -
+                                       (pow(p2.fX, 2) - pow(p1.fX, 2)) / (p2.fY - p1.fY) +
+                                        p3.fY - p1.fY );
+  double y = m12p * ( x - (p1.fX + p2.fX)/2 ) + (p1.fY + p2.fY)/2;
+
+  return Base::Vector2D(x, y);
+}
+
+
 void ActivateHandler(Gui::Document *doc,DrawSketchHandler *handler)
 {
     if (doc) {
@@ -1259,8 +1293,16 @@ static const char *cursor_create3pointarc[]={
 class DrawSketchHandler3PointArc : public DrawSketchHandler
 {
 public:
-    DrawSketchHandler3PointArc() : selectionDone(false) {}
-    virtual ~DrawSketchHandler3PointArc() {}
+    DrawSketchHandler3PointArc()
+      : Mode(STATUS_SEEK_First),EditCurve(2){}
+    virtual ~DrawSketchHandler3PointArc(){}
+    /// mode table
+    enum SelectMode {
+        STATUS_SEEK_First,      /**< enum value ----. */
+        STATUS_SEEK_Second,     /**< enum value ----. */
+        STATUS_SEEK_Third,      /**< enum value ----. */
+        STATUS_End
+    };
 
     virtual void activated(ViewProviderSketch *sketchgui)
     {
@@ -1269,48 +1311,176 @@ public:
 
     virtual void mouseMove(Base::Vector2D onSketchPos)
     {
-        setPositionText(onSketchPos);
-        if (seekAutoConstraint(sugConstr, onSketchPos, Base::Vector2D(0.f,0.f))) {
-            renderSuggestConstraintsCursor(sugConstr);
-            return;
+        if (Mode==STATUS_SEEK_First) {
+            setPositionText(onSketchPos);
+            if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
+                renderSuggestConstraintsCursor(sugConstr1);
+                return;
+            }
+        }
+        else if (Mode==STATUS_SEEK_Second) {
+            EditCurve[0] = (onSketchPos - FirstPoint)/2 + FirstPoint; // Centerpoint
+            EditCurve[1] = EditCurve[33] = onSketchPos;
+            double radius = (onSketchPos - EditCurve[0]).Length();
+            double lineAngle = GetPointAngle(EditCurve[0], onSketchPos);
+
+            // Build a 32 point circle ignoring already constructed points
+            for (int i=1; i <= 32; i++) {
+                // Start at current angle
+                double angle = (i-1)*2*M_PI/32.0 + lineAngle; // N point closed circle has N segments
+                if (i != 1 && i != 17 ) {
+                    EditCurve[i] = Base::Vector2D(EditCurve[0].fX + radius*cos(angle),
+                                                  EditCurve[0].fY + radius*sin(angle));
+                }
+            }
+
+            // Display radius and start angle
+            // This lineAngle will report counter-clockwise from +X, not relatively
+            SbString text;
+            text.sprintf(" (%.1fR,%.1fdeg)", (float) radius, (float) lineAngle * 180 / M_PI);
+            setPositionText(onSketchPos, text);
+
+            sketchgui->drawEdit(EditCurve);
+            if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f))) {
+                renderSuggestConstraintsCursor(sugConstr2);
+                return;
+            }
+        }
+        else if (Mode==STATUS_SEEK_Third) {
+            EditCurve[30] = GetCircleCenter(FirstPoint, SecondPoint, onSketchPos);
+            double radius = (SecondPoint - EditCurve[30]).Length();
+
+            double angle1 = GetPointAngle(EditCurve[30], FirstPoint);
+            double angle2 = GetPointAngle(EditCurve[30], SecondPoint);
+            double angle3 = GetPointAngle(EditCurve[30], onSketchPos);
+
+            startAngle = min(angle1, angle2); // Angle actually greater than 2*Pi
+            endAngle =   max(angle1, angle2);
+            // angle3 == angle1 or angle2 shouldn't be allowed but not sure...catch/try?
+            // Point 3 is between Point 1 and 2
+            if ( angle3 > startAngle && angle3 < endAngle ) {
+                arcAngle = endAngle - startAngle;
+                // Build a 30 point circle ignoring already constructed points
+                for (int i=1; i <= 28; i++) {
+                    double angle = i*arcAngle/29.0 + startAngle; // N point arc has N-1 segments
+                    EditCurve[i] = Base::Vector2D(EditCurve[30].fX + radius*cos(angle),
+                                                  EditCurve[30].fY + radius*sin(angle));
+                }
+            }
+            // Point 3 is not between Point 1 and 2
+            else {
+                arcAngle = 2*M_PI - (endAngle - startAngle);
+                // Build a 30 point circle ignoring already constructed points
+                for (int i=28; i >= 1; i--) {
+                    double angle = startAngle - i*arcAngle/29.0 ; // N point arc has N-1 segments
+                    EditCurve[i] = Base::Vector2D(EditCurve[30].fX + radius*cos(angle),
+                                                  EditCurve[30].fY + radius*sin(angle));
+                }
+            }
+
+            // This arcAngle will report counter-clockwise from +X, not relatively
+            SbString text;
+            text.sprintf(" (%.1fR,%.1fdeg)", (float) radius, (float) arcAngle * 180 / M_PI);
+            setPositionText(onSketchPos, text);
+
+            sketchgui->drawEdit(EditCurve);
+            if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.0,0.0))) {
+                renderSuggestConstraintsCursor(sugConstr3);
+                return;
+            }
         }
         applyCursor();
+
     }
 
     virtual bool pressButton(Base::Vector2D onSketchPos)
     {
-        EditPoint = onSketchPos;
-        selectionDone = true;
+        if (Mode==STATUS_SEEK_First){
+            // 32 point curve + center + endpoint
+            EditCurve.resize(34);
+            // 17 is circle halfway point (1+32/2)
+            FirstPoint = EditCurve[17] = onSketchPos;
+
+            Mode = STATUS_SEEK_Second;
+        }
+        else if (Mode==STATUS_SEEK_Second){
+            // 30 point arc and center point
+            EditCurve.resize(31);
+            EditCurve[0] = FirstPoint;
+            SecondPoint = EditCurve[29] = onSketchPos;
+
+            Mode = STATUS_SEEK_Third;
+        }
+        else {
+            EditCurve.resize(30);
+            double angle1 = atan2(onSketchPos.fY - CenterPoint.fY,
+                                 onSketchPos.fX - CenterPoint.fX) - startAngle;
+            double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ;
+            arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
+            if (arcAngle > 0)
+                endAngle = startAngle + arcAngle;
+            else {
+                endAngle = startAngle;
+                startAngle += arcAngle;
+            }
+
+            sketchgui->drawEdit(EditCurve);
+            applyCursor();
+            Mode = STATUS_End;
+        }
+
         return true;
     }
 
     virtual bool releaseButton(Base::Vector2D onSketchPos)
     {
-        if (selectionDone){
+        // Need to look at.  rx might need fixing.
+        if (Mode==STATUS_End) {
             unsetCursor();
             resetPositionText();
-
-            Gui::Command::openCommand("Add sketch point");
-            Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))",
+            Gui::Command::openCommand("Add sketch arc");
+            Gui::Command::doCommand(Gui::Command::Doc,
+                "App.ActiveDocument.%s.addGeometry(Part.ArcOfCircle"
+                "(Part.Circle(App.Vector(%f,%f,0),App.Vector(0,0,1),%f),"
+                "%f,%f))",
                       sketchgui->getObject()->getNameInDocument(),
-                      EditPoint.fX,EditPoint.fY);
+                      CenterPoint.fX, CenterPoint.fY, sqrt(rx*rx + ry*ry),
+                      startAngle, endAngle); //arcAngle > 0 ? 0 : 1);
+
             Gui::Command::commitCommand();
             Gui::Command::updateActive();
 
-            // add auto constraints for the line segment start
-            if (sugConstr.size() > 0) {
-                createAutoConstraints(sugConstr, getHighestCurveIndex(), Sketcher::start);
-                sugConstr.clear();
+            // Auto Constraint center point
+            if (sugConstr1.size() > 0) {
+                createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::mid);
+                sugConstr1.clear();
+            }
+
+            // Auto Constraint first picked point
+            if (sugConstr2.size() > 0) {
+                createAutoConstraints(sugConstr2, getHighestCurveIndex(), (arcAngle > 0) ? Sketcher::start : Sketcher::end );
+                sugConstr2.clear();
             }
 
+            // Auto Constraint second picked point
+            if (sugConstr3.size() > 0) {
+                createAutoConstraints(sugConstr3, getHighestCurveIndex(), (arcAngle > 0) ? Sketcher::end : Sketcher::start);
+                sugConstr3.clear();
+            }
+
+            EditCurve.clear();
+            sketchgui->drawEdit(EditCurve);
             sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider
         }
         return true;
     }
 protected:
-    bool selectionDone;
-    Base::Vector2D EditPoint;
-    std::vector<AutoConstraint> sugConstr;
+    SelectMode Mode;
+    std::vector<Base::Vector2D> EditCurve;
+    Base::Vector2D CenterPoint;
+    Base::Vector2D FirstPoint, SecondPoint, ThirdPoint;
+    double rx, ry, startAngle, endAngle, arcAngle;
+    std::vector<AutoConstraint> sugConstr1, sugConstr2, sugConstr3;
 };
 
 
-- 
1.7.9


From c389e85eb143bb16d2efa2e1687fb5c0fde965cb Mon Sep 17 00:00:00 2001
From: mdinger <mdinger.bugzilla@gmail.com>
Date: Thu, 13 Mar 2014 03:06:20 -0400
Subject: [PATCH 3/4] Moving mouse to choose 3rd point appears to work
 correctly

---
 src/Mod/Sketcher/Gui/CommandCreateGeo.cpp |   57 +++++++++++++++++------------
 1 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
index c62fc80..c3fce92 100644
--- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
+++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
@@ -1347,35 +1347,48 @@ public:
             }
         }
         else if (Mode==STATUS_SEEK_Third) {
-            EditCurve[30] = GetCircleCenter(FirstPoint, SecondPoint, onSketchPos);
-            double radius = (SecondPoint - EditCurve[30]).Length();
-
-            double angle1 = GetPointAngle(EditCurve[30], FirstPoint);
-            double angle2 = GetPointAngle(EditCurve[30], SecondPoint);
-            double angle3 = GetPointAngle(EditCurve[30], onSketchPos);
+            /*
+            Centerline inverts when the centerpoint goes from below to above the right point
+            or vice versa.  Easily taken care of by replacing centerline with a point.  It
+            happens because the direction the curve is being drawn reverses.  This happens because
+            it is much easier to draw the line in a consistent direction than otherwise.
+            */
+            CenterPoint = EditCurve[30] = GetCircleCenter(FirstPoint, SecondPoint, onSketchPos);
+            double radius = (SecondPoint - CenterPoint).Length();
+            bool buildForward = true; // Construct curve clockwise
+
+            double angle1 = GetPointAngle(CenterPoint, FirstPoint);
+            double angle2 = GetPointAngle(CenterPoint, SecondPoint);
+            double angle3 = GetPointAngle(CenterPoint, onSketchPos);
+            // Specify what direction curve is drawn
+            if (angle2 > angle1) {
+                EditCurve[0] =  FirstPoint;
+                EditCurve[29] = SecondPoint;
+            }
+            else {
+                EditCurve[0] =  SecondPoint;
+                EditCurve[29] = FirstPoint;
+            }
 
-            startAngle = min(angle1, angle2); // Angle actually greater than 2*Pi
+            startAngle = min(angle1, angle2);
             endAngle =   max(angle1, angle2);
             // angle3 == angle1 or angle2 shouldn't be allowed but not sure...catch/try?
             // Point 3 is between Point 1 and 2
             if ( angle3 > startAngle && angle3 < endAngle ) {
                 arcAngle = endAngle - startAngle;
-                // Build a 30 point circle ignoring already constructed points
-                for (int i=1; i <= 28; i++) {
-                    double angle = i*arcAngle/29.0 + startAngle; // N point arc has N-1 segments
-                    EditCurve[i] = Base::Vector2D(EditCurve[30].fX + radius*cos(angle),
-                                                  EditCurve[30].fY + radius*sin(angle));
-                }
             }
             // Point 3 is not between Point 1 and 2
             else {
                 arcAngle = 2*M_PI - (endAngle - startAngle);
-                // Build a 30 point circle ignoring already constructed points
-                for (int i=28; i >= 1; i--) {
-                    double angle = startAngle - i*arcAngle/29.0 ; // N point arc has N-1 segments
-                    EditCurve[i] = Base::Vector2D(EditCurve[30].fX + radius*cos(angle),
-                                                  EditCurve[30].fY + radius*sin(angle));
-                }
+                buildForward = false;
+            }
+
+            // Build a 30 point circle ignoring already constructed points
+            for (int i=1; i <= 28; i++) {
+                double angle = buildForward ? startAngle + i*arcAngle/29.0 :
+                                              startAngle - i*arcAngle/29.0; // N point arc has N-1 segments
+                EditCurve[i] = Base::Vector2D(EditCurve[30].fX + radius*cos(angle),
+                                              EditCurve[30].fY + radius*sin(angle));
             }
 
             // This arcAngle will report counter-clockwise from +X, not relatively
@@ -1406,8 +1419,7 @@ public:
         else if (Mode==STATUS_SEEK_Second){
             // 30 point arc and center point
             EditCurve.resize(31);
-            EditCurve[0] = FirstPoint;
-            SecondPoint = EditCurve[29] = onSketchPos;
+            SecondPoint = onSketchPos;
 
             Mode = STATUS_SEEK_Third;
         }
@@ -1477,8 +1489,7 @@ public:
 protected:
     SelectMode Mode;
     std::vector<Base::Vector2D> EditCurve;
-    Base::Vector2D CenterPoint;
-    Base::Vector2D FirstPoint, SecondPoint, ThirdPoint;
+    Base::Vector2D CenterPoint, FirstPoint, SecondPoint, ThirdPoint;
     double rx, ry, startAngle, endAngle, arcAngle;
     std::vector<AutoConstraint> sugConstr1, sugConstr2, sugConstr3;
 };
-- 
1.7.9


From 4288012951a8a63c0f0411bc25d7d40e1190eb24 Mon Sep 17 00:00:00 2001
From: mdinger <mdinger.bugzilla@gmail.com>
Date: Fri, 14 Mar 2014 14:31:15 -0400
Subject: [PATCH 4/4] Arc draws correctly.  Autosnap doesn't work at all.

---
 src/Mod/Sketcher/Gui/CommandCreateGeo.cpp |   75 +++++++++++------------------
 1 files changed, 28 insertions(+), 47 deletions(-)

diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
index c3fce92..0521e9b 100644
--- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
+++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp
@@ -1319,18 +1319,18 @@ public:
             }
         }
         else if (Mode==STATUS_SEEK_Second) {
-            EditCurve[0] = (onSketchPos - FirstPoint)/2 + FirstPoint; // Centerpoint
+            CenterPoint  = EditCurve[0] = (onSketchPos - FirstPoint)/2 + FirstPoint;
             EditCurve[1] = EditCurve[33] = onSketchPos;
-            double radius = (onSketchPos - EditCurve[0]).Length();
-            double lineAngle = GetPointAngle(EditCurve[0], onSketchPos);
+            radius = (onSketchPos - CenterPoint).Length();
+            double lineAngle = GetPointAngle(CenterPoint, onSketchPos);
 
             // Build a 32 point circle ignoring already constructed points
             for (int i=1; i <= 32; i++) {
                 // Start at current angle
                 double angle = (i-1)*2*M_PI/32.0 + lineAngle; // N point closed circle has N segments
                 if (i != 1 && i != 17 ) {
-                    EditCurve[i] = Base::Vector2D(EditCurve[0].fX + radius*cos(angle),
-                                                  EditCurve[0].fY + radius*sin(angle));
+                    EditCurve[i] = Base::Vector2D(CenterPoint.fX + radius*cos(angle),
+                                                  CenterPoint.fY + radius*sin(angle));
                 }
             }
 
@@ -1348,50 +1348,42 @@ public:
         }
         else if (Mode==STATUS_SEEK_Third) {
             /*
-            Centerline inverts when the centerpoint goes from below to above the right point
-            or vice versa.  Easily taken care of by replacing centerline with a point.  It
-            happens because the direction the curve is being drawn reverses.  This happens because
-            it is much easier to draw the line in a consistent direction than otherwise.
+            Centerline inverts when the arc flips sides.  Easily taken care of by replacing
+            centerline with a point.  It happens because the direction the curve is being drawn
+            reverses.
             */
             CenterPoint = EditCurve[30] = GetCircleCenter(FirstPoint, SecondPoint, onSketchPos);
-            double radius = (SecondPoint - CenterPoint).Length();
-            bool buildForward = true; // Construct curve clockwise
+            radius = (SecondPoint - CenterPoint).Length();
 
             double angle1 = GetPointAngle(CenterPoint, FirstPoint);
             double angle2 = GetPointAngle(CenterPoint, SecondPoint);
             double angle3 = GetPointAngle(CenterPoint, onSketchPos);
-            // Specify what direction curve is drawn
-            if (angle2 > angle1) {
-                EditCurve[0] =  FirstPoint;
-                EditCurve[29] = SecondPoint;
-            }
-            else {
-                EditCurve[0] =  SecondPoint;
-                EditCurve[29] = FirstPoint;
-            }
-
-            startAngle = min(angle1, angle2);
-            endAngle =   max(angle1, angle2);
-            // angle3 == angle1 or angle2 shouldn't be allowed but not sure...catch/try?
+            
+			// angle3 == angle1 or angle2 shouldn't be allowed but not sure...catch/try?
             // Point 3 is between Point 1 and 2
-            if ( angle3 > startAngle && angle3 < endAngle ) {
+            if ( angle3 > min(angle1, angle2) && angle3 < max(angle1, angle2) ) {
+                EditCurve[0] =  angle2 > angle1 ? FirstPoint  : SecondPoint;
+                EditCurve[29] = angle2 > angle1 ? SecondPoint : FirstPoint;
+				startAngle = min(angle1, angle2);
+				endAngle   = max(angle1, angle2);
                 arcAngle = endAngle - startAngle;
             }
             // Point 3 is not between Point 1 and 2
             else {
-                arcAngle = 2*M_PI - (endAngle - startAngle);
-                buildForward = false;
+                EditCurve[0] =  angle2 > angle1 ? SecondPoint : FirstPoint;
+                EditCurve[29] = angle2 > angle1 ? FirstPoint  : SecondPoint;
+				startAngle = max(angle1, angle2);
+				endAngle   = min(angle1, angle2);
+                arcAngle = 2*M_PI - (startAngle - endAngle);
             }
 
             // Build a 30 point circle ignoring already constructed points
             for (int i=1; i <= 28; i++) {
-                double angle = buildForward ? startAngle + i*arcAngle/29.0 :
-                                              startAngle - i*arcAngle/29.0; // N point arc has N-1 segments
-                EditCurve[i] = Base::Vector2D(EditCurve[30].fX + radius*cos(angle),
-                                              EditCurve[30].fY + radius*sin(angle));
+                double angle = startAngle + i*arcAngle/29.0; // N point arc has N-1 segments
+                EditCurve[i] = Base::Vector2D(CenterPoint.fX + radius*cos(angle),
+                                              CenterPoint.fY + radius*sin(angle));
             }
 
-            // This arcAngle will report counter-clockwise from +X, not relatively
             SbString text;
             text.sprintf(" (%.1fR,%.1fdeg)", (float) radius, (float) arcAngle * 180 / M_PI);
             setPositionText(onSketchPos, text);
@@ -1403,7 +1395,6 @@ public:
             }
         }
         applyCursor();
-
     }
 
     virtual bool pressButton(Base::Vector2D onSketchPos)
@@ -1425,16 +1416,6 @@ public:
         }
         else {
             EditCurve.resize(30);
-            double angle1 = atan2(onSketchPos.fY - CenterPoint.fY,
-                                 onSketchPos.fX - CenterPoint.fX) - startAngle;
-            double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ;
-            arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
-            if (arcAngle > 0)
-                endAngle = startAngle + arcAngle;
-            else {
-                endAngle = startAngle;
-                startAngle += arcAngle;
-            }
 
             sketchgui->drawEdit(EditCurve);
             applyCursor();
@@ -1456,8 +1437,8 @@ public:
                 "(Part.Circle(App.Vector(%f,%f,0),App.Vector(0,0,1),%f),"
                 "%f,%f))",
                       sketchgui->getObject()->getNameInDocument(),
-                      CenterPoint.fX, CenterPoint.fY, sqrt(rx*rx + ry*ry),
-                      startAngle, endAngle); //arcAngle > 0 ? 0 : 1);
+                      CenterPoint.fX, CenterPoint.fY, radius,
+                      startAngle, endAngle);
 
             Gui::Command::commitCommand();
             Gui::Command::updateActive();
@@ -1489,8 +1470,8 @@ public:
 protected:
     SelectMode Mode;
     std::vector<Base::Vector2D> EditCurve;
-    Base::Vector2D CenterPoint, FirstPoint, SecondPoint, ThirdPoint;
-    double rx, ry, startAngle, endAngle, arcAngle;
+    Base::Vector2D CenterPoint, FirstPoint, SecondPoint;
+    double radius, startAngle, endAngle, arcAngle;
     std::vector<AutoConstraint> sugConstr1, sugConstr2, sugConstr3;
 };
 
-- 
1.7.9

