This is rough and badly coded, but works,
It traces the perpendicular line even if there is no line under it, it use the vector, so it calculate the point in the extensions of the original line.
It is not perfect as it rely on some calculation that led to an approssimation so it seems good with two decimal precision.
Only a snippet but useful for someone.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using CamBam.CAD;
using CamBam.Geom;
using CamBam.UI;
using CamBam.Util;
/*
Plugin Template
*/
namespace ThisPlugin
{
public class CamBamInit
{
public static void InitPlugin(CamBamUI ui)
{
string PluginTitle = "Draw a Perp Line";
//Control mycont = new Control();
ToolStripMenuItem TPMI = new ToolStripMenuItem();
TPMI.Text = TextTranslation.Translate(PluginTitle);
TPMI.Click += new EventHandler(plugin_clicked);
TPMI.ShortcutKeys = Keys.Control | Keys.Shift | Keys.L;
TPMI.ShortcutKeyDisplayString = "Ctrl + Shift + L";
ToolStripMenuItem TPMI2 = new ToolStripMenuItem();
TPMI2.Text = TextTranslation.Translate(PluginTitle);
TPMI2.Click += new EventHandler(plugin_clicked);
TPMI2.ShortcutKeys = Keys.Control | Keys.Shift | Keys.L;
TPMI2.ShortcutKeyDisplayString = "Ctrl + Shift + L";
for (int i = 0; i < ui.Menus.mnuEdit.DropDownItems.Count; i++)
{
ToolStripItem toolStripItem2 = ui.Menus.mnuEdit.DropDownItems[i];
if (toolStripItem2 is ToolStripMenuItem && toolStripItem2.Name == "mnuEditTransform")
{
ToolStripMenuItem mytoolStripMenuItem2 = (ToolStripMenuItem)toolStripItem2;
//mytoolStripMenuItem2.DropDownItems.Insert(mytoolStripMenuItem2.DropDownItems.Count, TPMI); // for putting after the last item
mytoolStripMenuItem2.DropDownItems.Insert(1, TPMI); // to put after Move in the Edit -> Transform Submenu
break;
}
}
/*
foreach (ToolStripItem toolStripItem in ui.ViewContextMenus.ViewContextMenu.Items)
{
//CamBam.ThisApplication.AddLogMessage(toolStripItem.Name);
if (toolStripItem is ToolStripMenuItem && toolStripItem.Name == "transformToolStripMenuItem")
{
ToolStripMenuItem mytoolStripMenuItem = (ToolStripMenuItem)toolStripItem;
//mytoolStripMenuItem.DropDownItems.Insert(mytoolStripMenuItem.DropDownItems.Count, TPMI2); // for putting after the last item
mytoolStripMenuItem.DropDownItems.Insert(1, TPMI2); // to put after Move in the Context menu -> Transform Submenu
break;
}
}
*/
}
public static void plugin_clicked(object sender, EventArgs e)
{
MyClass myp1 = new MyClass();
myp1.MyMain();
}
}
public class MyClass
{
public bool DEBUG = true;
public static ICADView view = CamBamUI.MainUI.ActiveView;
public static CADFile myfile = view.CADFile;
public Point3F pl1 = new Point3F ();
public Point3F pl2 = new Point3F ();
public Polyline poly = new Polyline ();
public Polyline ps;
public PointSelectEditMode em = new PointSelectEditMode (CamBamUI.MainUI.ActiveView);
public void MyMain()
{
StartPointSelect ();
}
public void StartPointSelect()
{
em.OnReturnOK += new EventHandler (PointSelect_OnReturnOK);
int Valid = 0;
if (view.SelectedEntities.Length != 1) {
CamBam.ThisApplication.AddLogMessage ("You must select only one object");
} else {
foreach (Entity ent in view.SelectedEntities) {
if (ent.GetType () == typeof(Polyline)) { // The PrimitiveType is translated so check against it may result in 'false'
ps = ent as Polyline;
if (ps.Points.Count > 2) {
CamBam.ThisApplication.AddLogMessage ("too much points"); // it works only for a polyline with two points
} else {
pl1 = ps.Points [0].Point;
pl2 = ps.Points [1].Point;
Valid = 1;
}
} else {
CamBam.ThisApplication.AddLogMessage ("The Object is not a Polyline");
Valid = 0;
}
}
if (Valid == 1) {
em.Prompt = "Select first point...";
em.DefaultValue = null;
CamBamUI.MainUI.ActiveView.SetEditMode (em);
CamBamUI.MainUI.ActiveView.RepaintEditMode ();
CamBam.ThisApplication.AddLogMessage ("P1 " + pl1.ToString () + " P2 " + pl2.ToString ());
}
}
}
void PointSelect_OnReturnOK(object sender, EventArgs e)
{
if (sender is PointSelectEditMode)
{
if (((PointSelectEditMode)sender).ReturnValue is Point3F)
{
Point3F point = (Point3F)((PointSelectEditMode)sender).ReturnValue;
Point3F res1 = PerpPP (pl1, pl2, point);
CamBam.ThisApplication.AddLogMessage (" Calculated Point " + res1.ToString ());
poly.Add (point);
poly.Add (res1);
Layer l2 = CamBamUI.MainUI.ActiveView.CADFile.ActiveLayer;
l2.Entities.Add(poly);
l2.Entities.Add (new Arc(pl1, pl2, 0.5));
view.UpdateViewport ();
}
}
}
Point3F PerpPP(Point3F a , Point3F b, Point3F c)
/*
Find the point d that is perpendicular projection to the point c over a line a -b
*/
{
double x1 = a.X;
double y1 = a.Y;
double z1 = a.Z;
double x2 = b.X;
double y2 = b.Y;
double z2 = b.Z;
double x3 = c.X;
double y3 = c.Y;
double z3 = c.Z;
double alpha = ((x3 - x1)*(x2 - x1) + (y3 - y1)*(y2 - y1) + (z3 - z1)*(z2 - z1)) / ((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) + (z2 - z1)*(z2 - z1));
Point3F result = new Point3F( (x1+alpha*(x2-x1)), (y1+alpha*(y2-y1)), (z1+alpha*(z2-z1)));
return result;
}
}
}