Skip to content

Instantly share code, notes, and snippets.

@nodtem66
Last active August 16, 2023 09:56
Show Gist options
  • Save nodtem66/d1cab427c98b5309c8a76642c6ba7c2a to your computer and use it in GitHub Desktop.
Save nodtem66/d1cab427c98b5309c8a76642c6ba7c2a to your computer and use it in GitHub Desktop.
ImageJ Toolset for measuring (1) circumradius, (2) angle between two lines, and (3) distance between line and point.
// Measurement tools
// author [email protected]
// http://wsr.imagej.net/developer/macro/macros.html#toolsets
var obtusedAngles = false;
macro "Unused Tool - " {}
macro "X axis Registration Tool - C037T2d13-T9d13X" {
cmd = getArgument();
}
macro "Y axis Registration Tool - C037T2d13|T9d13Y" {
cmd = getArgument();
}
macro "circumcircle [f1]" {
requires("1.30k");
if (selectionType() == -1) {
exit("[circumcircle]: Please select three points!");
}
getSelectionCoordinates(x, y);
if (x.length != 3){
exit("Calculation requires only three points");
}
//-- Get pixel data
getPixelSize(unit, pw, ph, pd);
//-- First calculate the perimeter of the triangle
d1=sqrt((x[0]-x[1])*(x[0]-x[1])*pw*pw+(y[0]-y[1])*(y[0]-y[1])*ph*ph);
d2=sqrt((x[1]-x[2])*(x[1]-x[2])*pw*pw+(y[1]-y[2])*(y[1]-y[2])*ph*ph);
d3=sqrt((x[2]-x[0])*(x[2]-x[0])*pw*pw+(y[2]-y[0])*(y[2]-y[0])*ph*ph);
//-- Half the perimeter
s=0.5*(d1+d2+d3);
//-- Area of circumcircle
a=sqrt(s*(s-d1)*(s-d2)*(s*d3));
//-- Circumradius
r=(d1*d2*d3)/sqrt((d1+d2+d3)*(d2+d3-d1)*(d3+d1-d2)*(d1+d2-d3));
//-- Menger curvature is the inverse of the radius of the circle
mc=1/r;
//-- Centroid coordinates (from https://en.wikipedia.org/wiki/Circumscribed_circle#Cartesian_coordinates_2)
D=2*abs(x[0]*(y[1]-y[2]) + x[1]*(y[2]-y[0]) + x[2]*(y[0]-y[1]));
cenX=abs((x[0]*x[0]+y[0]*y[0]) * (y[1]-y[2]) + (x[1]*x[1]+y[1]*y[1]) * (y[2]-y[0]) + (x[2]*x[2]+y[2]*y[2]) * (y[0]-y[1]))/D;
cenY=abs((x[0]*x[0]+y[0]*y[0]) * (x[2]-x[1]) + (x[1]*x[1]+y[1]*y[1]) * (x[0]-x[2]) + (x[2]*x[2]+y[2]*y[2]) * (x[1]-x[0]))/D;
//-- report
//print("a: "+x[0]+","+y[0]);
//print("b: "+x[1]+","+y[1]);
//print("c: "+x[2]+","+y[2]);
//print("Area of circumcircle: "+a);
//print("Radius: "+r);
//print("Menger Curvature: "+mc);
//print("Circumcentre: "+cenX+","+cenY);
row = Table.size;
Table.set("Area", row, a);
Table.set("Radius", row, r);
Table.set("Menger Curvature", row, mc);
Table.set("Centre X", row, cenX);
Table.set("Centre Y", row, cenY);
Table.update;
//-- Create an overlay
//-- Triangle
makePolygon(x[0],y[0],x[1],y[1],x[2],y[2]);
Overlay.addSelection("cyan");
//-- Circumcentre
makeLine(cenX-5,cenY,cenX+5,cenY);
Overlay.addSelection("magenta");
makeLine(cenX,cenY-5,cenX,cenY+5);
Overlay.addSelection("magenta");
//-- Circumcircle
run("Specify...", "width="+(r*2/pw)+" height="+(r*2/ph)+" x="+cenX+" y="+cenY+" oval centered");
Overlay.addSelection("red");
run("Select None");
}
macro "Two-line Angle [f2]" {
requires("1.30k");
if (selectionType() == -1) {
exit("[Two-lines Angle]: Please select four points!");
}
getSelectionCoordinates(x, y);
if (x.length != 4) {
exit("[Two-lines Angle]: Please select four points!");
}
m1 = (y[1]-y[0])/(x[1]-x[0]+1e-16);
m2 = (y[3]-y[2])/(x[3]-x[2]+1e-16);
theta_deg = 0;
if (abs(m1*m2 + 1) < 1e-9) {
theta_deg = 90.0;
} else {
tan_theta = abs((m1 - m2)/(1+m1*m2));
theta_deg = atan2(tan_theta, 1.0) * 180.0 / PI;
}
if (obtusedAngles) {
theta_deg = 180 - theta_deg;
}
makeLine(x[0],y[0],x[1],y[1]);
Overlay.addSelection("red");
makeLine(x[2],y[2],x[3],y[3]);
Overlay.addSelection("red");
mid1 = newArray((x[0]+x[1])/2, (y[0]+y[1])/2);
mid2 = newArray((x[2]+x[3])/2, (y[2]+y[3])/2);
makeSelection("polyline", newArray(mid1[0], mid2[0]), newArray(mid1[1], mid2[1]));
setForegroundColor(0, 255, 255);
run("Dotted Line", "line=1 dash=6,6");
run("Select None");
Table.set("Line angle", Table.size, theta_deg);
Table.update;
}
macro "Two-line distance [f4]" {
requires("1.30k");
if (selectionType() == -1) {
exit("[Two-lines distance]: Please select three points!");
}
getSelectionCoordinates(x, y);
if (x.length != 3) {
exit("[Two-lines distance]: Please select three points!");
}
a = y[0] - y[1];
b = x[1] - x[0];
c = (x[0]-x[1])*y[0] + (y[1]-y[0])*x[0];
ab2 = a*a + b*b;
xc = (b*(b*x[2] - a*y[2]) - a*c) / ab2;
yc = (a*(-b*x[2] + a*y[2])-b*c) / ab2;
//-- Get pixel data
getPixelSize(unit, pw, ph, pd);
d = abs( (x[1]-x[0])*(y[0]-y[2]) - (x[0]-x[2])*(y[1]-y[0]) ) / sqrt(ab2) * pw;
makeLine(x[0],y[0],x[1],y[1]);
Overlay.addSelection("red");
makeSelection("polyline", newArray(xc, x[2]), newArray(yc, y[2]));
setForegroundColor(0, 255, 255);
run("Dotted Line", "line=1 dash=6,6");
run("Select None");
Table.set("Line Distance", Table.size, d);
Table.update;
}
macro "Two-line angle option [f3]" {
Dialog.create("Set Two-line angle measurement");
Dialog.addCheckbox("Obtuse angle", obtusedAngles);
Dialog.show();
obtusedAngles = Dialog.getCheckbox();
}
@nodtem66
Copy link
Author

Installation

  • Copy this file to macros/toolsets
  • Open ImageJ > More tool menu (>> Icon on the right)
  • Select "Basic measurement"

Usage

Circumradius

  • Use "Multipoint"
  • Select three points for calculating circumradius
  • Press [F1]

Angle between two lines

  • Use "Multipoint"
  • Select four points
  • Press [F2]
  • Optional: Press [F3] to change between acute and obtuse angle measurement

Distance between a line and a point

  • Use "Multipoint"
  • Select three points (the first two points will be a line)
  • Press [F4]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment