Angle Angle shape constructor
AngleAngleCstr.cs
// Copyright 2012 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

using ESRI.ArcGIS.ArcMapUI;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Editor;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Framework;
using ESRI.ArcGIS.esriSystem;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace AngleAngle
{
  class AngleAngleCstr : IShapeConstructor, IPersist
  {
    IEditor m_editor;
    IEditSketch3 m_edSketch;
    ISnappingEnvironment m_snappingEnv;
    IPointSnapper m_snapper;
    ISnappingFeedback m_snappingFeedback;
    
    // Declare 3 points
    IPoint m_firstPoint;
    IPoint m_secondPoint;
    IPoint m_activePoint;
    // Declare 2 angles
    double m_firstAngle;
    double m_secondAngle;

    enum ToolPhase { Inactive, SecondPoint, Intersection }
    ToolPhase m_etoolPhase;

    #region IShapeConstructor Members

    public void Activate()
    {
    }

    public bool Active
    {
      get { return true; }
    }

    public void AddPoint(IPoint point, bool Clone, bool allowUndo)
    {
    }

    public IPoint Anchor
    {
      get { return Anchor; }
    }

    public double AngleConstraint
    {
      get
      {
        return AngleConstraint;
      }
      set
      {
        AngleConstraint = value;
      }
    }

    public esriSketchConstraint Constraint
    {
      get
      {
        return Constraint;
      }
      set
      {
        Constraint = value;
      }
    }

    public int Cursor
    {
      get { return 0; }
    }

    public void Deactivate()
    {
    }

    public double DistanceConstraint
    {
      get
      {
        return DistanceConstraint;
      }
      set
      {
        DistanceConstraint = value;
      }
    }

    public bool Enabled
    {
      get { return true; }
    }

    public string ID
    {
      get { return ("Angle Angle Constructor"); }
    }

    public void Initialize(IEditor pEditor)
    {
      // Initialize the constructor
      m_editor = pEditor as IEditor;
      m_edSketch = pEditor as IEditSketch3;

      //Get the snap environment
      m_snappingEnv = m_editor.Parent.FindExtensionByName("ESRI Snapping") as ISnappingEnvironment;
      m_snapper = m_snappingEnv.PointSnapper;
      m_snappingFeedback = new SnappingFeedbackClass();
      m_snappingFeedback.Initialize(m_editor.Parent, m_snappingEnv, true);

      m_firstPoint = new PointClass();
      m_secondPoint = new PointClass();
      m_activePoint = new PointClass();

      // Set the phase to inactive so we start at the beginning 
      m_etoolPhase = ToolPhase.Inactive;
    }

    public bool IsStreaming
    {
      get
      {
        return IsStreaming;
      }
      set
      {
        IsStreaming = value;
      }
    }

    public IPoint Location
    {
      get { return Location; }
    }

    public bool OnContextMenu(int X, int Y)
    {
      return true;
    }

    public void OnKeyDown(int keyState, int shift)
    {
      // If the escape key is used, throw away the calculated point 
      if (keyState == (int)Keys.Escape)
        m_etoolPhase = ToolPhase.Inactive;
    }

    public void OnKeyUp(int keyState, int shift)
    {
    }

    public void OnMouseDown(int Button, int shift, int X, int Y)
    {
      if (Button != (int)Keys.LButton) return;
      switch (m_etoolPhase)
      {
        case (ToolPhase.Inactive):
          GetFirstPoint();
          break;
        case (ToolPhase.SecondPoint):
          GetSecondPoint();
          break;
        case (ToolPhase.Intersection):
          GetIntersection();
          break;
      }
    }

    public void OnMouseMove(int Button, int shift, int X, int Y)
    {
      //Snap the mouse location
      if (m_etoolPhase != ToolPhase.Intersection)
      {
        m_activePoint = m_editor.Display.DisplayTransformation.ToMapPoint(X, Y);
        ISnappingResult snapResult = m_snapper.Snap(m_activePoint);
        m_snappingFeedback.Update(snapResult, 0);

        if (snapResult != null)
          m_activePoint = snapResult.Location;
      }
    }

    public void OnMouseUp(int Button, int shift, int X, int Y)
    {
    }

    public void Refresh(int hdc)
    {
      m_snappingFeedback.Refresh(hdc);
    }

    public void SketchModified()
    {
    }
    #endregion

    private void GetFirstPoint()
    {
      INumberDialog numDialog = new NumberDialogClass();
      // Set first point to the active point which may have been snapped
      m_firstPoint = m_activePoint;
      // Get the angle
      if (numDialog.DoModal("Angle 1", 45, 2, m_editor.Display.hWnd))
      {
        m_firstAngle = numDialog.Value * Math.PI / 180;
        m_etoolPhase = ToolPhase.SecondPoint;
      }
    }

    private void GetSecondPoint()
    {
      INumberDialog numDialog = new NumberDialogClass();
      // Set the second point equal to the active point which may have been snapped 
      m_secondPoint = m_activePoint;

      // Get the angle
      if (numDialog.DoModal("Angle 2", -45, 2, m_editor.Display.hWnd))
      {
        m_secondAngle = numDialog.Value * Math.PI / 180;
      }
      else
      {
        m_etoolPhase = ToolPhase.Inactive;
        return;
      }

      // Get the intersection point
      IConstructPoint constructPoint = new PointClass();
      constructPoint.ConstructAngleIntersection(m_firstPoint, m_firstAngle, m_secondPoint, m_secondAngle);

      IPoint point = constructPoint as IPoint;
      if (point.IsEmpty)
      {
        m_etoolPhase = ToolPhase.Inactive;
        MessageBox.Show("No Point Calculated");
        return;
      }

      // Draw the calculated intersection point and erase previous snap feedback
      m_activePoint = point;
      m_etoolPhase = ToolPhase.Intersection;
      m_snappingFeedback.Update(null, 0);
      DrawPoint(m_activePoint);
    }

    private void GetIntersection()
    {
      IEditSketch editSketch = m_editor as IEditSketch;
      editSketch.AddPoint(m_activePoint, true);
      // Set the phase to inactive, back to beginning
      m_etoolPhase = ToolPhase.Inactive;
    }

    private void DrawPoint(IPoint pPoint)
    {
      //Draw a red graphic dot on the display at the given point location
      IRgbColor color = null;
      ISimpleMarkerSymbol marker = null;
      IAppDisplay appDisplay = m_editor.Display as IAppDisplay;
      
      //Set the symbol (red, size 8)
      color = new RgbColor();
      color.Red = 255;
      color.Green = 0;
      color.Blue = 0;
      marker = new SimpleMarkerSymbol();
      marker.Color = color;
      marker.Size = 8;

      //Draw the point
      appDisplay.StartDrawing(0, (short)esriScreenCache.esriNoScreenCache);
      appDisplay.SetSymbol(marker as ISymbol);
      appDisplay.DrawPoint(pPoint);
      appDisplay.FinishDrawing();
    }

    #region IPersist Members

    public void GetClassID(out Guid pClassID)
    {
      //Explicitly set a guid. Used to set command.checked property
      pClassID = new Guid("edb83080-999d-11de-8a39-0800200c9a66");
    }

    #endregion
  }
}