From dc683ed701b016a1c79800db2ed41aed9cf8cac6 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sun, 2 Mar 2025 20:18:17 +0100 Subject: [PATCH 01/15] added dimensions --- tests/dimension.scad | 81 ++++++++++++++++++++++ utils/dimension.scad | 157 +++++++++++++++++++++++++++++++++++++++++++ utils/maths.scad | 29 ++++++++ 3 files changed, 267 insertions(+) create mode 100644 tests/dimension.scad create mode 100644 utils/dimension.scad diff --git a/tests/dimension.scad b/tests/dimension.scad new file mode 100644 index 0000000..0c51ca4 --- /dev/null +++ b/tests/dimension.scad @@ -0,0 +1,81 @@ +// +// NopSCADlib Copyright Chris Palmer 2018 +// nop.head@gmail.com +// hydraraptor.blogspot.com +// +// This file is part of NopSCADlib. +// +// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with NopSCADlib. +// If not, see . +// +include <../utils/core/core.scad> +use <../utils/dimension.scad> + + +module dimensions_3d_xy() { + dimension([0,0,0], [10,10,0], "", 0.2); + dimension([0,0,0], [10,-10,0], "", 0.2); + dimension([0,0,0], [-10,10,0], "", 0.2); + dimension([0,0,0], [-10,-10,0], "", 0.2); + + + dimension([0,0,0], [0,10,0], "", 0.2); + dimension([0,0,0], [0,-10,0], "", 0.2); + dimension([0,0,0], [10,0,0], "", 0.2); + dimension([0,0,0], [-10,0,0], "", 0.2); +} + +module dimensions_3d_xyz() { + dimension([0,0,0], [10,10,10], "", 0.2); + dimension([0,0,0], [10,-10,10], "", 0.2); + dimension([0,0,0], [-10,10,10], "", 0.2); + dimension([0,0,0], [-10,-10,10], "", 0.2); + + dimension([0,0,0], [10,10,-10], "", 0.2); + dimension([0,0,0], [10,-10,-10], "", 0.2); + dimension([0,0,0], [-10,10,-10], "", 0.2); + dimension([0,0,0], [-10,-10,-10], "", 0.2); + + dimension([0,0,0], [-3,0,10], "", 0.2); + dimension([0,0,0], [0,0,-10], "", 0.2); + + dimension([0,0,0], [0,2,10], "", 0.2); + dimension([0,0,0], [0,2,-10], "", 0.2); + +} + +module dimension_1d_x() { + dimension_x([12,0,0], [18,0,0]); + dimension_x([12,5,0], [18,10,0]); + dimension_x([12,5,0], [18,10,5]); +} + +module dimension_1d_y() { + dimension_y([12,0,0], [12,-5,0]); + dimension_y([12,-8,0], [18,-10,0]); + dimension_y([12,-5,0], [18,-10,5]); +} + +module dimension_1d_z() { + dimension_z([20,0,0], [20,0,5]); + dimension_z([20,0,0], [20,0,10]); + dimension_z([20,0,0], [20,10,10]); +} + +if($preview) + dimensions_3d_xy(); + dimensions_3d_xyz(); + dimension_1d_x(); + dimension_1d_y(); + dimension_1d_z(); + + + \ No newline at end of file diff --git a/utils/dimension.scad b/utils/dimension.scad new file mode 100644 index 0000000..81ff73e --- /dev/null +++ b/utils/dimension.scad @@ -0,0 +1,157 @@ +// +// NopSCADlib Copyright Chris Palmer 2018 +// nop.head@gmail.com +// hydraraptor.blogspot.com +// +// This file is part of NopSCADlib. +// +// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with NopSCADlib. +// If not, see . +// + +// +//! Annotation used in this documentation +// + +include <../utils/core/core.scad> +include <../utils/maths.scad> + + + +//if text is empty, will display the number value +//text_plane is either "XY" or "XZ" +module dimension(startpoint, endpoint, text = "", thickness = 0.1) { + // Compute vector between points + direction = endpoint - startpoint; + length = norm(direction); + midpoint = (startpoint + endpoint) / 2; + + // Ensure nonzero values for calculations + dir_xy = norm([direction.x, direction.y]); + + // Compute rotation angles safely + //azimuth = (dir_xy == 0) ? 0 : atan2(direction.y, direction.x); + azimuth = atan2(direction.y, direction.x); + /*elevation = (direction.x == 0 && direction.y == 0) + ? ((direction.z > 0) ? -90 : 90) + : -atan2(direction.z, dir_xy);*/ + elevation = -atan2(direction.z, dir_xy); + + // Draw measurement line as a thin cylinder + translate(midpoint) + rotate([0, elevation, azimuth]) + rotate([0, 90, 0]) + cylinder(d = thickness, h = length - thickness * 2, center = true); + + // Draw endpoint markers + translate(startpoint) + rotate([0, elevation - 90, azimuth]) + translate([0, 0, -thickness * 4]) + cylinder(h = thickness * 4, r1 = thickness * 2, r2 = 0); + + translate(endpoint) + rotate([0, elevation + 90, azimuth]) + translate([0, 0, -thickness * 4]) + cylinder(h = thickness * 4, r1 = thickness * 2, r2 = 0); + + // Draw the text/distance + dir = (length > 0) ? (direction / length) * thickness * 4 : [1, 0, 0]; + up_dir = rotate_vector_3d([0,1,0], [0,0,1] ,azimuth); + + translate(midpoint + up_dir*0.66) + rotate([0, elevation, azimuth]) + linear_extrude(thickness) + text(text == "" ? str(length) : text, size = thickness * 5, valign = "center", halign = "center"); +} + +//offset will detirmine how much space is between the measured point and the dimension +//for x, this offset will be in the y direction +module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0.1) { + y = max(startpoint.y, endpoint.y) + offset; + z = max(startpoint.z, endpoint.z) ; + dimension([startpoint.x, y, z], [endpoint.x, y, z], text, thickness); + + v1= [startpoint.x, y, z]-startpoint; + h1 = norm(v1); + axis1 = cross([0,0,1], v1); + angle1 = atan2(norm(axis1), v1.z); + translate(startpoint) + rotate(angle1, axis1) + cylinder( h= h1+thickness*2, d=thickness); + + + v2= [endpoint.x, y, z]-endpoint; + h2 = norm(v2); + axis2 = cross([0,0,1], v2); + angle2 = atan2(norm(axis2), v2.z); + + translate(endpoint) + rotate(angle2, axis2) + cylinder( h= h2+thickness*2, d=thickness); +} + +//offset will detirmine how much space is between the measured point and the dimension +//for y, this offset will be in the x direction +module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0.1) { + x = max(startpoint.x, endpoint.x) + offset; + z = max(startpoint.z, endpoint.z) ; + dimension([x, startpoint.y, z], [x, endpoint.y, z], text, thickness); + + v1= [x, startpoint.y, z]-startpoint; + h1 = norm(v1); + axis1 = cross([0,0,1], v1); + angle1 = atan2(norm(axis1), v1.z); + + translate(startpoint) + rotate(angle1, axis1) + cylinder( h= h1+thickness*2, d=thickness); + + + v2= [x, endpoint.y, z]-endpoint; + h2 = norm(v2); + axis2 = cross([0,0,1], v2); + angle2 = atan2(norm(axis2), v2.z); + + translate(endpoint) + rotate(angle2, axis2) + cylinder( h= h2+thickness*2, d=thickness); +} + +//offset will detirmine how much space is between the measured point and the dimension +//for z, this offset will be in the x direction +module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0.1) { + x = max(startpoint.x, endpoint.x) + offset; + y = max(startpoint.y, endpoint.y) ; + dimension([x, y, startpoint.z], [x, y, endpoint.z], text, thickness); + + v1= [x, y, startpoint.z]-startpoint; + h1 = norm(v1); + axis1 = cross([0,0,1], v1); + angle1 = atan2(norm(axis1), v1.z); + + translate(startpoint) + rotate(angle1, axis1) + cylinder( h= h1+thickness*2, d=thickness); + + + v2= [x, y, endpoint.z]-endpoint; + h2 = norm(v2); + axis2 = cross([0,0,1], v2); + angle2 = atan2(norm(axis2), v2.z); + + translate(endpoint) + rotate(angle2, axis2) + cylinder( h= h2+thickness*2, d=thickness); +} + + + + diff --git a/utils/maths.scad b/utils/maths.scad index 3d03f47..4fea047 100644 --- a/utils/maths.scad +++ b/utils/maths.scad @@ -191,3 +191,32 @@ function cubic_real_roots(a, b, c, d) = //! Returns real roots of cubic equation function path_length(path, i = 0, length = 0) = //! Calculated the length along a path i >= len(path) - 1 ? length : path_length(path, i + 1, length + norm(path[i + 1] - path[i])); + + function rotate_vector_2d(v, angle) = [ + v[0] * cos(angle) - v[1] * sin(angle), + v[0] * sin(angle) + v[1] * cos(angle) +]; + +function rotate_vector_2d(v, angle) = [ + v[0] * cos(angle) - v[1] * sin(angle), + v[0] * sin(angle) + v[1] * cos(angle) +]; + +function rotation_matrix(axis, angle) = let( + u = axis / norm(axis), // Normalize axis + ux = u[0], uy = u[1], uz = u[2], + cosA = cos(angle), sinA = sin(angle), + one_minus_cosA = 1 - cosA +) [ + [cosA + ux*ux*one_minus_cosA, ux*uy*one_minus_cosA - uz*sinA, ux*uz*one_minus_cosA + uy*sinA], + [uy*ux*one_minus_cosA + uz*sinA, cosA + uy*uy*one_minus_cosA, uy*uz*one_minus_cosA - ux*sinA], + [uz*ux*one_minus_cosA - uy*sinA, uz*uy*one_minus_cosA + ux*sinA, cosA + uz*uz*one_minus_cosA] +]; + +function rotate_vector_3d(v, axis, angle) = let( + mat = rotation_matrix(axis, angle) +) [ + mat[0][0]*v[0] + mat[0][1]*v[1] + mat[0][2]*v[2], + mat[1][0]*v[0] + mat[1][1]*v[1] + mat[1][2]*v[2], + mat[2][0]*v[0] + mat[2][1]*v[1] + mat[2][2]*v[2] +]; \ No newline at end of file From 6467de5facdc2a5b6ccdbdbe32f703ba3faa70f4 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sun, 2 Mar 2025 23:01:20 +0100 Subject: [PATCH 02/15] Update maths.scad --- utils/maths.scad | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/utils/maths.scad b/utils/maths.scad index 4fea047..87153e3 100644 --- a/utils/maths.scad +++ b/utils/maths.scad @@ -192,11 +192,6 @@ function path_length(path, i = 0, length = 0) = //! Calculated the length along i >= len(path) - 1 ? length : path_length(path, i + 1, length + norm(path[i + 1] - path[i])); - function rotate_vector_2d(v, angle) = [ - v[0] * cos(angle) - v[1] * sin(angle), - v[0] * sin(angle) + v[1] * cos(angle) -]; - function rotate_vector_2d(v, angle) = [ v[0] * cos(angle) - v[1] * sin(angle), v[0] * sin(angle) + v[1] * cos(angle) @@ -219,4 +214,4 @@ function rotate_vector_3d(v, axis, angle) = let( mat[0][0]*v[0] + mat[0][1]*v[1] + mat[0][2]*v[2], mat[1][0]*v[0] + mat[1][1]*v[1] + mat[1][2]*v[2], mat[2][0]*v[0] + mat[2][1]*v[1] + mat[2][2]*v[2] -]; \ No newline at end of file +]; From b166ec47dd7e34e6798c1287d0ce8612a84e9be1 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sun, 2 Mar 2025 23:07:17 +0100 Subject: [PATCH 03/15] Remove old commented code from dimension.scad --- utils/dimension.scad | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/utils/dimension.scad b/utils/dimension.scad index 81ff73e..76eb3e1 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -27,7 +27,6 @@ include <../utils/maths.scad> //if text is empty, will display the number value -//text_plane is either "XY" or "XZ" module dimension(startpoint, endpoint, text = "", thickness = 0.1) { // Compute vector between points direction = endpoint - startpoint; @@ -37,12 +36,8 @@ module dimension(startpoint, endpoint, text = "", thickness = 0.1) { // Ensure nonzero values for calculations dir_xy = norm([direction.x, direction.y]); - // Compute rotation angles safely - //azimuth = (dir_xy == 0) ? 0 : atan2(direction.y, direction.x); + // Compute rotation angles azimuth = atan2(direction.y, direction.x); - /*elevation = (direction.x == 0 && direction.y == 0) - ? ((direction.z > 0) ? -90 : 90) - : -atan2(direction.z, dir_xy);*/ elevation = -atan2(direction.z, dir_xy); // Draw measurement line as a thin cylinder From 012388571185c674293ba17de39e0db59a775ff4 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Fri, 7 Mar 2025 22:07:53 +0100 Subject: [PATCH 04/15] Improved text alligment --- utils/dimension.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/dimension.scad b/utils/dimension.scad index 76eb3e1..8094519 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -64,7 +64,7 @@ module dimension(startpoint, endpoint, text = "", thickness = 0.1) { translate(midpoint + up_dir*0.66) rotate([0, elevation, azimuth]) linear_extrude(thickness) - text(text == "" ? str(length) : text, size = thickness * 5, valign = "center", halign = "center"); + text(text == "" ? str(length) : text, size = thickness * 5, valign = "bottom", halign = "center"); } //offset will detirmine how much space is between the measured point and the dimension From 3a62198183b6a1dce74479ae44e00b4d5e690431 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Thu, 13 Mar 2025 22:37:53 +0100 Subject: [PATCH 05/15] replaced the new math functions with rotate and transform --- utils/dimension.scad | 4 ++-- utils/maths.scad | 26 +------------------------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/utils/dimension.scad b/utils/dimension.scad index 8094519..b528bff 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -59,9 +59,9 @@ module dimension(startpoint, endpoint, text = "", thickness = 0.1) { // Draw the text/distance dir = (length > 0) ? (direction / length) * thickness * 4 : [1, 0, 0]; - up_dir = rotate_vector_3d([0,1,0], [0,0,1] ,azimuth); + up_dir = transform([0,1,0], rotate(azimuth)); - translate(midpoint + up_dir*0.66) + translate(midpoint + up_dir*thickness) rotate([0, elevation, azimuth]) linear_extrude(thickness) text(text == "" ? str(length) : text, size = thickness * 5, valign = "bottom", halign = "center"); diff --git a/utils/maths.scad b/utils/maths.scad index 87153e3..0f8b68c 100644 --- a/utils/maths.scad +++ b/utils/maths.scad @@ -190,28 +190,4 @@ function cubic_real_roots(a, b, c, d) = //! Returns real roots of cubic equation function path_length(path, i = 0, length = 0) = //! Calculated the length along a path i >= len(path) - 1 ? length - : path_length(path, i + 1, length + norm(path[i + 1] - path[i])); - -function rotate_vector_2d(v, angle) = [ - v[0] * cos(angle) - v[1] * sin(angle), - v[0] * sin(angle) + v[1] * cos(angle) -]; - -function rotation_matrix(axis, angle) = let( - u = axis / norm(axis), // Normalize axis - ux = u[0], uy = u[1], uz = u[2], - cosA = cos(angle), sinA = sin(angle), - one_minus_cosA = 1 - cosA -) [ - [cosA + ux*ux*one_minus_cosA, ux*uy*one_minus_cosA - uz*sinA, ux*uz*one_minus_cosA + uy*sinA], - [uy*ux*one_minus_cosA + uz*sinA, cosA + uy*uy*one_minus_cosA, uy*uz*one_minus_cosA - ux*sinA], - [uz*ux*one_minus_cosA - uy*sinA, uz*uy*one_minus_cosA + ux*sinA, cosA + uz*uz*one_minus_cosA] -]; - -function rotate_vector_3d(v, axis, angle) = let( - mat = rotation_matrix(axis, angle) -) [ - mat[0][0]*v[0] + mat[0][1]*v[1] + mat[0][2]*v[2], - mat[1][0]*v[0] + mat[1][1]*v[1] + mat[1][2]*v[2], - mat[2][0]*v[0] + mat[2][1]*v[1] + mat[2][2]*v[2] -]; + : path_length(path, i + 1, length + norm(path[i + 1] - path[i])); \ No newline at end of file From f731f0fe98a3a3d975c34cd85ac4f618c2f1bf6b Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Thu, 13 Mar 2025 22:53:21 +0100 Subject: [PATCH 06/15] added a function to rotate around the dim axis --- tests/dimension.scad | 2 +- utils/dimension.scad | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/dimension.scad b/tests/dimension.scad index 0c51ca4..1ff4f1f 100644 --- a/tests/dimension.scad +++ b/tests/dimension.scad @@ -30,7 +30,7 @@ module dimensions_3d_xy() { dimension([0,0,0], [0,10,0], "", 0.2); dimension([0,0,0], [0,-10,0], "", 0.2); dimension([0,0,0], [10,0,0], "", 0.2); - dimension([0,0,0], [-10,0,0], "", 0.2); + dimension([0,0,0], [-10,0,0], "", 0.2, rot_around_dim=270); } module dimensions_3d_xyz() { diff --git a/utils/dimension.scad b/utils/dimension.scad index b528bff..afd5ec8 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -27,7 +27,7 @@ include <../utils/maths.scad> //if text is empty, will display the number value -module dimension(startpoint, endpoint, text = "", thickness = 0.1) { +module dimension(startpoint, endpoint, text = "", thickness = 0.1, rot_around_dim = 0) { // Compute vector between points direction = endpoint - startpoint; length = norm(direction); @@ -60,8 +60,10 @@ module dimension(startpoint, endpoint, text = "", thickness = 0.1) { // Draw the text/distance dir = (length > 0) ? (direction / length) * thickness * 4 : [1, 0, 0]; up_dir = transform([0,1,0], rotate(azimuth)); + depth_dir = transform([0,0,1], rotate(azimuth)); - translate(midpoint + up_dir*thickness) + rotate(direction*rot_around_dim/2) + translate(midpoint + up_dir*thickness - depth_dir*thickness/2) rotate([0, elevation, azimuth]) linear_extrude(thickness) text(text == "" ? str(length) : text, size = thickness * 5, valign = "bottom", halign = "center"); From 106666ec493f6b088ee398b276e8734d0790a451 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sat, 15 Mar 2025 21:28:33 +0100 Subject: [PATCH 07/15] simplified the math to use rotates instead, added examples, and allowed the user to choose witch plane the x,y and z dimensions are in --- tests/dimension.scad | 19 +++++++------ utils/dimension.scad | 68 +++++++++++++++++++++++++++----------------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/tests/dimension.scad b/tests/dimension.scad index 1ff4f1f..53ca9a5 100644 --- a/tests/dimension.scad +++ b/tests/dimension.scad @@ -29,8 +29,8 @@ module dimensions_3d_xy() { dimension([0,0,0], [0,10,0], "", 0.2); dimension([0,0,0], [0,-10,0], "", 0.2); - dimension([0,0,0], [10,0,0], "", 0.2); - dimension([0,0,0], [-10,0,0], "", 0.2, rot_around_dim=270); + dimension([0,0,0], [10,0,0], "", 0.2,rot_around_dim=0); + dimension([0,0,0], [-10,0,0], "", 0.2, rot_around_dim=90); } module dimensions_3d_xyz() { @@ -42,7 +42,7 @@ module dimensions_3d_xyz() { dimension([0,0,0], [10,10,-10], "", 0.2); dimension([0,0,0], [10,-10,-10], "", 0.2); dimension([0,0,0], [-10,10,-10], "", 0.2); - dimension([0,0,0], [-10,-10,-10], "", 0.2); + dimension([0,0,0], [-10,-10,-10], "", 0.2, rot_around_dim=45); dimension([0,0,0], [-3,0,10], "", 0.2); dimension([0,0,0], [0,0,-10], "", 0.2); @@ -55,24 +55,25 @@ module dimensions_3d_xyz() { module dimension_1d_x() { dimension_x([12,0,0], [18,0,0]); dimension_x([12,5,0], [18,10,0]); + dimension_x([12,0,-5], [18,0,0], plane= "xz"); dimension_x([12,5,0], [18,10,5]); } module dimension_1d_y() { dimension_y([12,0,0], [12,-5,0]); dimension_y([12,-8,0], [18,-10,0]); - dimension_y([12,-5,0], [18,-10,5]); + dimension_y([12,-5,0], [18,-10,5], plane= "yz"); } module dimension_1d_z() { - dimension_z([20,0,0], [20,0,5]); - dimension_z([20,0,0], [20,0,10]); - dimension_z([20,0,0], [20,10,10]); + dimension_z([20,0,5], [20,0,0]); + dimension_z([20,0,10], [20,0,0]); + dimension_z([20,0,0], [20,10,10],plane= "yz"); } if($preview) - dimensions_3d_xy(); - dimensions_3d_xyz(); + //dimensions_3d_xy(); + //dimensions_3d_xyz(); dimension_1d_x(); dimension_1d_y(); dimension_1d_z(); diff --git a/utils/dimension.scad b/utils/dimension.scad index afd5ec8..decc7d9 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -27,7 +27,7 @@ include <../utils/maths.scad> //if text is empty, will display the number value -module dimension(startpoint, endpoint, text = "", thickness = 0.1, rot_around_dim = 0) { +module dimension(startpoint, endpoint, text = "", thickness = 0.1, rot_around_dim=0) { // Compute vector between points direction = endpoint - startpoint; length = norm(direction); @@ -39,42 +39,56 @@ module dimension(startpoint, endpoint, text = "", thickness = 0.1, rot_around_di // Compute rotation angles azimuth = atan2(direction.y, direction.x); elevation = -atan2(direction.z, dir_xy); + + //end triangle size + etr_width = thickness *5; + etr_height = thickness *3; // Draw measurement line as a thin cylinder translate(midpoint) rotate([0, elevation, azimuth]) rotate([0, 90, 0]) - cylinder(d = thickness, h = length - thickness * 2, center = true); + resize([thickness, thickness, length - etr_width+0.01 ]) + cube(center = true); + + //do some vector calculations + dir = (length > 0) ? (direction / length) * thickness * 4 : [1, 0, 0]; + //up_dir = transform([0,1,0], rotate(azimuth)); + //depth_dir = transform([0,0,1], rotate(azimuth)); // Draw endpoint markers translate(startpoint) - rotate([0, elevation - 90, azimuth]) - translate([0, 0, -thickness * 4]) - cylinder(h = thickness * 4, r1 = thickness * 2, r2 = 0); + rotate([0, elevation, azimuth]) + rotate([rot_around_dim,0,0]) + translate([0,0,-thickness/2]) + linear_extrude(thickness) + polygon([[etr_width, etr_height/2],[0,0],[etr_width, -etr_height/2]],[[0,1,2]]); translate(endpoint) - rotate([0, elevation + 90, azimuth]) - translate([0, 0, -thickness * 4]) - cylinder(h = thickness * 4, r1 = thickness * 2, r2 = 0); + rotate([0, elevation, azimuth]) + rotate([rot_around_dim,0,0]) + translate([0,0,-thickness/2]) + linear_extrude(thickness) + polygon([[-etr_width, etr_height/2],[0,0],[-etr_width, -etr_height/2]],[[0,1,2]]); + // Draw the text/distance - dir = (length > 0) ? (direction / length) * thickness * 4 : [1, 0, 0]; - up_dir = transform([0,1,0], rotate(azimuth)); - depth_dir = transform([0,0,1], rotate(azimuth)); - - rotate(direction*rot_around_dim/2) - translate(midpoint + up_dir*thickness - depth_dir*thickness/2) + translate(midpoint) rotate([0, elevation, azimuth]) + rotate([rot_around_dim,0,0]) + translate([0,thickness,-thickness/2]) linear_extrude(thickness) text(text == "" ? str(length) : text, size = thickness * 5, valign = "bottom", halign = "center"); } //offset will detirmine how much space is between the measured point and the dimension //for x, this offset will be in the y direction -module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0.1) { - y = max(startpoint.y, endpoint.y) + offset; - z = max(startpoint.z, endpoint.z) ; - dimension([startpoint.x, y, z], [endpoint.x, y, z], text, thickness); +//plane options : xy, xz +module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0.1, plane = "xy") { + y = max(startpoint.y, endpoint.y) + (plane=="xy"?offset:0); + z = max(startpoint.z, endpoint.z) + (plane=="xz"?offset:0); + + dimension([startpoint.x, y, z], [endpoint.x, y, z], text, thickness, rot_around_dim=(plane=="xz"?90:0)); v1= [startpoint.x, y, z]-startpoint; h1 = norm(v1); @@ -97,10 +111,11 @@ module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0.1) //offset will detirmine how much space is between the measured point and the dimension //for y, this offset will be in the x direction -module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0.1) { - x = max(startpoint.x, endpoint.x) + offset; - z = max(startpoint.z, endpoint.z) ; - dimension([x, startpoint.y, z], [x, endpoint.y, z], text, thickness); +//plane options : xy, yz +module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0.1, plane = "xy") { + x = max(startpoint.x, endpoint.x) + (plane=="xy"?offset:0); + z = max(startpoint.z, endpoint.z) + (plane=="yz"?offset:0); + dimension([x, startpoint.y, z], [x, endpoint.y, z], text, thickness, rot_around_dim=(plane=="yz"?90:0)); v1= [x, startpoint.y, z]-startpoint; h1 = norm(v1); @@ -124,10 +139,11 @@ module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0.1) //offset will detirmine how much space is between the measured point and the dimension //for z, this offset will be in the x direction -module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0.1) { - x = max(startpoint.x, endpoint.x) + offset; - y = max(startpoint.y, endpoint.y) ; - dimension([x, y, startpoint.z], [x, y, endpoint.z], text, thickness); +//plane options : xz, yz +module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0.1, plane = "xz") { + x = max(startpoint.x, endpoint.x) + (plane=="xz"?offset:0); + y = max(startpoint.y, endpoint.y) + (plane=="yz"?offset:0); + dimension([x, y, startpoint.z], [x, y, endpoint.z], text, thickness, rot_around_dim=(plane=="xz"?90:0)); v1= [x, y, startpoint.z]-startpoint; h1 = norm(v1); From 8992cce7a62d2fec956aae64236ba19dc340603f Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sat, 15 Mar 2025 22:19:12 +0100 Subject: [PATCH 08/15] added argument for text size, and improve auto size --- tests/dimension.scad | 40 ++++++++++++++++++++-------------------- utils/dimension.scad | 39 +++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/tests/dimension.scad b/tests/dimension.scad index 53ca9a5..f85d3e4 100644 --- a/tests/dimension.scad +++ b/tests/dimension.scad @@ -23,32 +23,32 @@ use <../utils/dimension.scad> module dimensions_3d_xy() { dimension([0,0,0], [10,10,0], "", 0.2); dimension([0,0,0], [10,-10,0], "", 0.2); - dimension([0,0,0], [-10,10,0], "", 0.2); - dimension([0,0,0], [-10,-10,0], "", 0.2); + dimension([0,0,0], [-10,10,0], ""); + dimension([0,0,0], [-10,-10,0], ""); - dimension([0,0,0], [0,10,0], "", 0.2); - dimension([0,0,0], [0,-10,0], "", 0.2); - dimension([0,0,0], [10,0,0], "", 0.2,rot_around_dim=0); - dimension([0,0,0], [-10,0,0], "", 0.2, rot_around_dim=90); + dimension([0,0,0], [0,10,0], ""); + dimension([0,0,0], [0,-10,0], ""); + dimension([0,0,0], [10,0,0], "",rot_around_dim=0); + dimension([0,0,0], [-10,0,0], "", rot_around_dim=90); } module dimensions_3d_xyz() { - dimension([0,0,0], [10,10,10], "", 0.2); - dimension([0,0,0], [10,-10,10], "", 0.2); - dimension([0,0,0], [-10,10,10], "", 0.2); - dimension([0,0,0], [-10,-10,10], "", 0.2); + dimension([0,0,0], [10,10,10], ""); + dimension([0,0,0], [10,-10,10], ""); + dimension([0,0,0], [-10,10,10], ""); + dimension([0,0,0], [-10,-10,10], ""); - dimension([0,0,0], [10,10,-10], "", 0.2); - dimension([0,0,0], [10,-10,-10], "", 0.2); - dimension([0,0,0], [-10,10,-10], "", 0.2); - dimension([0,0,0], [-10,-10,-10], "", 0.2, rot_around_dim=45); + dimension([0,0,0], [10,10,-10], ""); + dimension([0,0,0], [10,-10,-10], ""); + dimension([0,0,0], [-10,10,-10], ""); + dimension([0,0,0], [-10,-10,-10], "", rot_around_dim=45); - dimension([0,0,0], [-3,0,10], "", 0.2); - dimension([0,0,0], [0,0,-10], "", 0.2); + dimension([0,0,0], [-3,0,10], ""); + dimension([0,0,0], [0,0,-10], ""); - dimension([0,0,0], [0,2,10], "", 0.2); - dimension([0,0,0], [0,2,-10], "", 0.2); + dimension([0,0,0], [0,2,10], ""); + dimension([0,0,0], [0,2,-10], ""); } @@ -72,8 +72,8 @@ module dimension_1d_z() { } if($preview) - //dimensions_3d_xy(); - //dimensions_3d_xyz(); + dimensions_3d_xy(); + dimensions_3d_xyz(); dimension_1d_x(); dimension_1d_y(); dimension_1d_z(); diff --git a/utils/dimension.scad b/utils/dimension.scad index decc7d9..ea19ecb 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -17,21 +17,20 @@ // If not, see . // -// -//! Annotation used in this documentation -// - include <../utils/core/core.scad> include <../utils/maths.scad> //if text is empty, will display the number value -module dimension(startpoint, endpoint, text = "", thickness = 0.1, rot_around_dim=0) { +//thickness will determine the thickness of the lines, and size of the arrows, if 0, will use 0.5% of the length of the dim +//text_size will determine the size of the text, if 0, will use percentage of the length of the dim +module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rot_around_dim=0) { // Compute vector between points direction = endpoint - startpoint; length = norm(direction); midpoint = (startpoint + endpoint) / 2; + thickness = (thickness == 0? length/200:thickness); // Ensure nonzero values for calculations dir_xy = norm([direction.x, direction.y]); @@ -41,8 +40,8 @@ module dimension(startpoint, endpoint, text = "", thickness = 0.1, rot_around_di elevation = -atan2(direction.z, dir_xy); //end triangle size - etr_width = thickness *5; - etr_height = thickness *3; + etr_width = thickness *10; + etr_height = thickness *4; // Draw measurement line as a thin cylinder translate(midpoint) @@ -78,17 +77,21 @@ module dimension(startpoint, endpoint, text = "", thickness = 0.1, rot_around_di rotate([rot_around_dim,0,0]) translate([0,thickness,-thickness/2]) linear_extrude(thickness) - text(text == "" ? str(length) : text, size = thickness * 5, valign = "bottom", halign = "center"); + text(text == "" ? str(length) : text, size = (text_size == 0? length/15:text_size), valign = "bottom", halign = "center"); } //offset will detirmine how much space is between the measured point and the dimension //for x, this offset will be in the y direction //plane options : xy, xz -module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0.1, plane = "xy") { +module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xy") { + length = norm(endpoint - startpoint); + thickness = (thickness == 0? length/200:thickness); + + y = max(startpoint.y, endpoint.y) + (plane=="xy"?offset:0); z = max(startpoint.z, endpoint.z) + (plane=="xz"?offset:0); - dimension([startpoint.x, y, z], [endpoint.x, y, z], text, thickness, rot_around_dim=(plane=="xz"?90:0)); + dimension([startpoint.x, y, z], [endpoint.x, y, z], text, thickness, text_size, rot_around_dim=(plane=="xz"?90:0)); v1= [startpoint.x, y, z]-startpoint; h1 = norm(v1); @@ -112,10 +115,14 @@ module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0.1, //offset will detirmine how much space is between the measured point and the dimension //for y, this offset will be in the x direction //plane options : xy, yz -module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0.1, plane = "xy") { +module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xy") { + length = norm(endpoint - startpoint); + thickness = (thickness == 0? length/200:thickness); + + x = max(startpoint.x, endpoint.x) + (plane=="xy"?offset:0); z = max(startpoint.z, endpoint.z) + (plane=="yz"?offset:0); - dimension([x, startpoint.y, z], [x, endpoint.y, z], text, thickness, rot_around_dim=(plane=="yz"?90:0)); + dimension([x, startpoint.y, z], [x, endpoint.y, z], text, thickness, text_size, rot_around_dim=(plane=="yz"?90:0)); v1= [x, startpoint.y, z]-startpoint; h1 = norm(v1); @@ -140,10 +147,14 @@ module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0.1, //offset will detirmine how much space is between the measured point and the dimension //for z, this offset will be in the x direction //plane options : xz, yz -module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0.1, plane = "xz") { +module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xz") { + length = norm(endpoint - startpoint); + thickness = (thickness == 0? length/200:thickness); + + x = max(startpoint.x, endpoint.x) + (plane=="xz"?offset:0); y = max(startpoint.y, endpoint.y) + (plane=="yz"?offset:0); - dimension([x, y, startpoint.z], [x, y, endpoint.z], text, thickness, rot_around_dim=(plane=="xz"?90:0)); + dimension([x, y, startpoint.z], [x, y, endpoint.z], text, thickness, text_size, rot_around_dim=(plane=="xz"?90:0)); v1= [x, y, startpoint.z]-startpoint; h1 = norm(v1); From 4f68935b5b56b7405eb6c1e0fae5845e8f800489 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sun, 16 Mar 2025 18:23:15 +0100 Subject: [PATCH 09/15] some cleanup --- utils/dimension.scad | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/utils/dimension.scad b/utils/dimension.scad index ea19ecb..4aa2ad7 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -25,7 +25,7 @@ include <../utils/maths.scad> //if text is empty, will display the number value //thickness will determine the thickness of the lines, and size of the arrows, if 0, will use 0.5% of the length of the dim //text_size will determine the size of the text, if 0, will use percentage of the length of the dim -module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rot_around_dim=0) { +module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rot_around_dim=0, text_centered=true) { // Compute vector between points direction = endpoint - startpoint; length = norm(direction); @@ -52,8 +52,6 @@ module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , //do some vector calculations dir = (length > 0) ? (direction / length) * thickness * 4 : [1, 0, 0]; - //up_dir = transform([0,1,0], rotate(azimuth)); - //depth_dir = transform([0,0,1], rotate(azimuth)); // Draw endpoint markers translate(startpoint) @@ -77,7 +75,7 @@ module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rotate([rot_around_dim,0,0]) translate([0,thickness,-thickness/2]) linear_extrude(thickness) - text(text == "" ? str(length) : text, size = (text_size == 0? length/15:text_size), valign = "bottom", halign = "center"); + text(text == "" ? str(length) : text, size = (text_size == 0? length/15:text_size), valign = (text_centered?"center":"bottom"), halign = "center"); } //offset will detirmine how much space is between the measured point and the dimension From e87e19aa182acee64e3d47c282c81b7ef495bf81 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sun, 16 Mar 2025 18:43:26 +0100 Subject: [PATCH 10/15] removed center from experiment --- utils/dimension.scad | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/dimension.scad b/utils/dimension.scad index 4aa2ad7..d53bf7e 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -25,7 +25,7 @@ include <../utils/maths.scad> //if text is empty, will display the number value //thickness will determine the thickness of the lines, and size of the arrows, if 0, will use 0.5% of the length of the dim //text_size will determine the size of the text, if 0, will use percentage of the length of the dim -module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rot_around_dim=0, text_centered=true) { +module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rot_around_dim=0) { // Compute vector between points direction = endpoint - startpoint; length = norm(direction); @@ -75,7 +75,7 @@ module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rotate([rot_around_dim,0,0]) translate([0,thickness,-thickness/2]) linear_extrude(thickness) - text(text == "" ? str(length) : text, size = (text_size == 0? length/15:text_size), valign = (text_centered?"center":"bottom"), halign = "center"); + text(text == "" ? str(length) : text, size = (text_size == 0? length/15:text_size), valign = "bottom", halign = "center"); } //offset will detirmine how much space is between the measured point and the dimension From 9862b3c3a347fac5bb355b1d62a02bdc0970221b Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sun, 16 Mar 2025 18:50:51 +0100 Subject: [PATCH 11/15] typos --- utils/dimension.scad | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/dimension.scad b/utils/dimension.scad index d53bf7e..91a13b1 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -78,7 +78,7 @@ module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , text(text == "" ? str(length) : text, size = (text_size == 0? length/15:text_size), valign = "bottom", halign = "center"); } -//offset will detirmine how much space is between the measured point and the dimension +//offset will determine how much space is between the measured point and the dimension //for x, this offset will be in the y direction //plane options : xy, xz module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xy") { @@ -110,7 +110,7 @@ module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0, t cylinder( h= h2+thickness*2, d=thickness); } -//offset will detirmine how much space is between the measured point and the dimension +//offset will determine how much space is between the measured point and the dimension //for y, this offset will be in the x direction //plane options : xy, yz module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xy") { @@ -142,7 +142,7 @@ module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, t cylinder( h= h2+thickness*2, d=thickness); } -//offset will detirmine how much space is between the measured point and the dimension +//offset will determine how much space is between the measured point and the dimension //for z, this offset will be in the x direction //plane options : xz, yz module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xz") { From c17cc1321bcd06af439519435734f6e0eb8f5d43 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Wed, 19 Mar 2025 21:42:34 +0100 Subject: [PATCH 12/15] Changed the module comments style --- utils/dimension.scad | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/utils/dimension.scad b/utils/dimension.scad index 91a13b1..0a86c77 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -22,10 +22,8 @@ include <../utils/maths.scad> -//if text is empty, will display the number value -//thickness will determine the thickness of the lines, and size of the arrows, if 0, will use 0.5% of the length of the dim -//text_size will determine the size of the text, if 0, will use percentage of the length of the dim -module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rot_around_dim=0) { + +module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , rot_around_dim=0) { //! Will create a 3D dimension between two points. If text is empty, will display the measured distance. Thickness will determine the thickness of the lines, and size of the arrows, if 0, will use 0.5% of the length of the dim. Text_size will determine the size of the text, if 0, will use percentage of the length of the dim // Compute vector between points direction = endpoint - startpoint; length = norm(direction); @@ -78,10 +76,8 @@ module dimension(startpoint, endpoint, text = "", thickness = 0, text_size = 0 , text(text == "" ? str(length) : text, size = (text_size == 0? length/15:text_size), valign = "bottom", halign = "center"); } -//offset will determine how much space is between the measured point and the dimension -//for x, this offset will be in the y direction -//plane options : xy, xz -module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xy") { + +module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xy") { //! Will create a dimension in the x direction. Offset will determine how much space is between the measured point and the dimension. Plane options : xy, xz length = norm(endpoint - startpoint); thickness = (thickness == 0? length/200:thickness); @@ -110,10 +106,8 @@ module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0, t cylinder( h= h2+thickness*2, d=thickness); } -//offset will determine how much space is between the measured point and the dimension -//for y, this offset will be in the x direction -//plane options : xy, yz -module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xy") { + +module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xy") { //! Will create a dimension in the y direction. Offset will determine how much space is between the measured point and the dimension. Plane options : xy, yz length = norm(endpoint - startpoint); thickness = (thickness == 0? length/200:thickness); @@ -142,10 +136,7 @@ module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, t cylinder( h= h2+thickness*2, d=thickness); } -//offset will determine how much space is between the measured point and the dimension -//for z, this offset will be in the x direction -//plane options : xz, yz -module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xz") { +module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0, text_size = 0 , plane = "xz") { //! Will create a dimension in the z direction. Offset will determine how much space is between the measured point and the dimension. Plane options : xz, yz length = norm(endpoint - startpoint); thickness = (thickness == 0? length/200:thickness); From 921843cc09e7ae2953090c30e7d5b9c644e3b966 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sat, 22 Mar 2025 14:54:42 +0100 Subject: [PATCH 13/15] made negative offset work as expected (go to the opposite side, and use min instead of max on ccordinates) --- utils/dimension.scad | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/utils/dimension.scad b/utils/dimension.scad index 0a86c77..c0b0ef8 100644 --- a/utils/dimension.scad +++ b/utils/dimension.scad @@ -81,9 +81,8 @@ module dimension_x(startpoint, endpoint, offset = 1, text = "", thickness = 0, t length = norm(endpoint - startpoint); thickness = (thickness == 0? length/200:thickness); - - y = max(startpoint.y, endpoint.y) + (plane=="xy"?offset:0); - z = max(startpoint.z, endpoint.z) + (plane=="xz"?offset:0); + y = offset > 0 ? max(startpoint.y, endpoint.y) + (plane=="xy"?offset:0) : min(startpoint.y, endpoint.y) + (plane=="xy"?offset:0); + z = offset > 0 ? max(startpoint.z, endpoint.z) + (plane=="xz"?offset:0) : min(startpoint.z, endpoint.z) + (plane=="xz"?offset:0); dimension([startpoint.x, y, z], [endpoint.x, y, z], text, thickness, text_size, rot_around_dim=(plane=="xz"?90:0)); @@ -112,8 +111,8 @@ module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, t thickness = (thickness == 0? length/200:thickness); - x = max(startpoint.x, endpoint.x) + (plane=="xy"?offset:0); - z = max(startpoint.z, endpoint.z) + (plane=="yz"?offset:0); + x = offset > 0 ? max(startpoint.x, endpoint.x) + (plane=="xy"?offset:0) : min(startpoint.x, endpoint.x) + (plane=="xy"?offset:0); + z = offset > 0 ? max(startpoint.z, endpoint.z) + (plane=="yz"?offset:0) : min(startpoint.z, endpoint.z) + (plane=="yz"?offset:0); dimension([x, startpoint.y, z], [x, endpoint.y, z], text, thickness, text_size, rot_around_dim=(plane=="yz"?90:0)); v1= [x, startpoint.y, z]-startpoint; @@ -123,6 +122,7 @@ module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, t translate(startpoint) rotate(angle1, axis1) + rotate([offset>0?0:180,0,0]) cylinder( h= h1+thickness*2, d=thickness); @@ -133,6 +133,7 @@ module dimension_y(startpoint, endpoint, offset = 1, text = "", thickness = 0, t translate(endpoint) rotate(angle2, axis2) + rotate([offset>0?0:180,0,0]) cylinder( h= h2+thickness*2, d=thickness); } @@ -141,8 +142,8 @@ module dimension_z(startpoint, endpoint, offset = 1, text = "", thickness = 0, t thickness = (thickness == 0? length/200:thickness); - x = max(startpoint.x, endpoint.x) + (plane=="xz"?offset:0); - y = max(startpoint.y, endpoint.y) + (plane=="yz"?offset:0); + x = offset > 0 ? max(startpoint.x, endpoint.x) + (plane=="xz"?offset:0) : min(startpoint.x, endpoint.x) + (plane=="xz"?offset:0); + y = offset > 0 ? max(startpoint.y, endpoint.y) + (plane=="yz"?offset:0) : min(startpoint.y, endpoint.y) + (plane=="yz"?offset:0); dimension([x, y, startpoint.z], [x, y, endpoint.z], text, thickness, text_size, rot_around_dim=(plane=="xz"?90:0)); v1= [x, y, startpoint.z]-startpoint; From 49bd6e0a04885cf5cad7655aee038e16dc0a7e15 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sat, 22 Mar 2025 15:00:20 +0100 Subject: [PATCH 14/15] added negative offsets to test --- tests/dimension.scad | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/dimension.scad b/tests/dimension.scad index f85d3e4..a5fa4be 100644 --- a/tests/dimension.scad +++ b/tests/dimension.scad @@ -54,7 +54,7 @@ module dimensions_3d_xyz() { module dimension_1d_x() { dimension_x([12,0,0], [18,0,0]); - dimension_x([12,5,0], [18,10,0]); + dimension_x([12,5,0], [18,10,0], offset = -1); dimension_x([12,0,-5], [18,0,0], plane= "xz"); dimension_x([12,5,0], [18,10,5]); } @@ -62,7 +62,7 @@ module dimension_1d_x() { module dimension_1d_y() { dimension_y([12,0,0], [12,-5,0]); dimension_y([12,-8,0], [18,-10,0]); - dimension_y([12,-5,0], [18,-10,5], plane= "yz"); + dimension_y([12,-5,0], [18,-10,5], offset = -1, plane= "yz"); } module dimension_1d_z() { From c50f95a203ead9070407fbae7d1247a00938b255 Mon Sep 17 00:00:00 2001 From: Alex Verschoot Date: Sat, 22 Mar 2025 21:43:54 +0100 Subject: [PATCH 15/15] added some documentation to the nut --- docs/sliding_t_nut.png | Bin 0 -> 28725 bytes vitamins/nut.scad | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 docs/sliding_t_nut.png diff --git a/docs/sliding_t_nut.png b/docs/sliding_t_nut.png new file mode 100644 index 0000000000000000000000000000000000000000..79013962e09bd982dcbc7ee9f23a4388e4094ce9 GIT binary patch literal 28725 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 use