[CommandMethod("ModPlus", "mpPl-Rect3Pt", CommandFlags.Redraw)]
public static void mpPl_Rect3Pt()
{
  var doc = AcApp.DocumentManager.MdiActiveDocument;
  var db = doc.Database;
  var ed = doc.Editor;
  try
  {
    // first point
    var ppo = new PromptPointOptions("\nУкажите первую точку: ")
    {
      UseBasePoint = false,
      AllowNone = true
    };
 
    var ppr = ed.GetPoint(ppo);
    if (ppr.Status != PromptStatus.OK) return;
    //var fPt = ModPlus.MpCadHelpers.UcsToWcs(ppr.Value);
    var fPt = ppr.Value;
    // second point
    ppo = new PromptPointOptions("\nУкажите вторую точку: ")
    {
      UseBasePoint = true,
      BasePoint = fPt,
      UseDashedLine = true,
      AllowNone = true
    };
 
    ppr = ed.GetPoint(ppo);
    if (ppr.Status != PromptStatus.OK) return;
    var sPt = ppr.Value;
    using (var tr = db.TransactionManager.StartTransaction())
    {
      // jig
      var jig = new Rect3PtJig();
      var jr = jig.StartJig(fPt, sPt);
 
      if (jr.Status != PromptStatus.OK) return;
      // draw pline
      var pline = jig.Poly();
      var btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite, false);
      btr.AppendEntity(pline);
      tr.AddNewlyCreatedDBObject(pline, true);
      tr.Commit();
    }
  }
  catch (System.Exception exception)
  {
    ed.WriteMessage(exception.ToString());
  }
}
 
class Rect3PtJig : DrawJig
{
  private Point3d _prevPoint;
  private Point3d _currPoint;
  private Point3d _fPoint;
  private Point3d _sPoint;
  private Polyline _polyline;
  private Editor ed;
  public PromptResult StartJig(Point3d fPt, Point3d sPt)
  {
    _fPoint = fPt;//ModPlus.MpCadHelpers.UcsToWcs(fPt);
    _sPoint = sPt;//ModPlus.MpCadHelpers.UcsToWcs(sPt);
    _prevPoint = sPt;
    _polyline = new Polyline();
    ed = AcApp.DocumentManager.MdiActiveDocument.Editor;
    PromptResult rs = ed.Drag(this); 
    if (rs.Status == PromptStatus.OK)
    {
      CalcPline();
    }
    return rs;
 
  }
 
  public Polyline Poly()
  {
    return _polyline;
  }
 
  protected override SamplerStatus Sampler(JigPrompts prompts)
  {
    var jppo = new JigPromptPointOptions("\nУкажите третью точку: ")
    {
      UserInputControls = UserInputControls.Accept3dCoordinates | 
                          UserInputControls.NullResponseAccepted,
 
      BasePoint = _sPoint,
      UseBasePoint = true,
      Cursor = CursorType.RubberBand
    };
 
    var ppr = prompts.AcquirePoint(jppo);
 
    if (ppr.Status != PromptStatus.OK)
      return SamplerStatus.Cancel;
 
    if (ppr.Status == PromptStatus.OK)
    {
      _currPoint = ppr.Value;
 
      if (CursorHasMoved())
      {
        _prevPoint = _currPoint;
        return SamplerStatus.OK;
      }
      return SamplerStatus.NoChange;
    }
       
    return SamplerStatus.NoChange;
  }
 
  void CalcPline()
  {
    // Строим временный отрезок из точки 1 в точку 2
    var tmpLine = new Line(_fPoint, _sPoint);
    // Строим три вспомогательных вектора
    var vecCurrentToFirst = _currPoint - _fPoint;
    var vecCurrentToSecond = _currPoint - _sPoint;
    var vecSecondToFirst = _sPoint - _fPoint;
    /* Определим катет в треугольнике, которй образуется текущей точкой и второй точкой
    через угол между векторами
    */
    var katet = Math.Sin(vecCurrentToSecond.GetAngleTo(vecSecondToFirst)) * vecCurrentToSecond.Length;
    // Найдем угол между вектором из текущей точки к первой точке и вспомогательной линией
    var angleOnToTmpLinePlane = vecCurrentToFirst.GetAngleTo(vecSecondToFirst, tmpLine.Normal);
    // Получим знак (направление) в зависимости от угла (изменим знак переменной "катет")
    if (angleOnToTmpLinePlane < Math.PI)
      katet = -katet;
    // Получим 3 точку по направлению и катету и вектор
    var thPoint = _sPoint + vecSecondToFirst.GetPerpendicularVector().GetNormal() * katet;
    var vecThirdToSecond = thPoint - _sPoint;
    // Получим 4 точку по тому-же принципу. Для откладывания длины использовать абс.значение!
    Point3d fourPoint;
    if (angleOnToTmpLinePlane < Math.PI)
      fourPoint = thPoint - vecThirdToSecond.GetPerpendicularVector().GetNormal() * tmpLine.Length;
    else fourPoint = thPoint + vecThirdToSecond.GetPerpendicularVector().GetNormal() * tmpLine.Length;
    _polyline.Reset(true, 4);
    _polyline.AddVertexAt(0, new Point2d(_fPoint.X, _fPoint.Y), 0.0, 0.0, 0.0);
    _polyline.AddVertexAt(1, new Point2d(_sPoint.X, _sPoint.Y), 0.0, 0.0, 0.0);
    _polyline.AddVertexAt(2, new Point2d(thPoint.X, thPoint.Y), 0.0, 0.0, 0.0);
    _polyline.AddVertexAt(3, new Point2d(fourPoint.X, fourPoint.Y), 0.0, 0.0, 0.0);
    _polyline.SetDatabaseDefaults();
    _polyline.Closed = true;
  }
  protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
  {
    CalcPline();
    draw.Geometry.Draw(_polyline);
    return true;
  }
  private bool CursorHasMoved()
  {
    return _currPoint.DistanceTo(_prevPoint) > Tolerance.Global.EqualPoint;
  }
}