Resources => Scripts and Plugins => Topic started by: lloydsp on November 24, 2012, 14:08:08 pm

Title: constructing a perpendicular to a line
Post by: lloydsp on November 24, 2012, 14:08:08 pm
This is a simple script.  Almost trivial.  But it saves me a lot of time.

Because I draw many "real world" manufactured components into my CB layouts, I frequently need to construct a perpendicular centered on a line segment.  It's do-able with shapes and breaks and joins, or aligns and translates, but this little script makes it easy, and one-step.

Careful!  There are no protections for what sort of object you'll be processing.  The script might break or do odd things if used on other  than simple open polylines.

It draws one identical polyline at the centroid of the each one selected, and at 90 degrees rotation from the original.



' construct perpendiculars to all selected polylines
' perpendiculars constructed to intersect at centroids

sub main
   dim pol1 as Polyline = new Polyline()
   dim l as Layer = doc.ActiveLayer()

   dim x as double = 0      ' polyline coordinate
   dim y as double = 0      ' polyline coordinate
   dim z as double = 0      ' polyline coordinate

   dim cp as Point3F
   dim cp2 as Point3F

   if view.SelectedEntities.Length > 0 then
      for each ent as Entity in view.SelectedEntities
         if pol1.ApplyTransformation() then
              pol1.Transform = Matrix4x4F.Identity
         end if
         '// Repaint the view
      next ent
   end if
end sub
Title: Re: constructing a perpendicular to a line
Post by: onekk on October 20, 2016, 14:30:16 pm
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.

Code: [Select]
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

foreach (ToolStripItem toolStripItem in ui.ViewContextMenus.ViewContextMenu.Items)
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

public static void plugin_clicked(object sender, EventArgs e)

MyClass myp1 = new MyClass();

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 (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;

Title: Re: constructing a perpendicular to a line
Post by: lloydsp on October 20, 2016, 15:44:19 pm
If I might --

I wrote a little script to do that years (and years) ago.  Instead of trying to calculate it all to high-precision, mine just duplicates the line, then rotates it 90-degrees about its center.

Since CB is doing the rotation (rather than my code), I presume the precision is as "good as it gets".

This isn't a criticism, just a hint at another possible way of doing it.

Title: Re: constructing a perpendicular to a line
Post by: onekk on October 20, 2016, 16:03:59 pm
Yes, your method is good.

But if you need a shorter line and the original line is long, you have to trim the line after the copy rotation.

This snippets is a WIP to modify the AutoBox to Obtain some box maybe exagonal or octagonal withe the base "with fingers" so it has to deal with line that are not parallelo to the X or Y axis.

In the proceeding of the work maybe some snippets of code will be useful for someone.

I have just published some "obvious things" on the Snippets Thread.

It is "difficult" to write a Plugin for CamBam, and many things that are obvious "after some time" are very hard "in the beginning".

Loyd yours comments are very welcome, as they are never "not useful", and almost all the time I'm learning something from you.

Nice to see that the Hurricane have "improved" your CNC :-D