Mary just started an ambitious pieced quilt that requires 50-some-odd precisely sized 1-1/2 inch circles, with marks to locate a 1 inch circle in the middle. She started using a drafting template to mark the smaller circle on freezer paper (don’t ask, it’s complicated), but we couldn’t find the template I know I have with the larger circles.
[Update: It’s a Bittersweet Briar traditional quilt. See all those little dots-for-berries?]
So I says to my wife, I sez, “Hey, we have the technology. What would really simplify what you’re doing?” After a bit of doodling, we came up with a ring having the proper ID and OD, plus a flat handle of some sort.
Half an hour later, I had a solid model:

An hour after that I handed her a warm piece of plastic:

The bottom ring is exactly 1-1/2 inch OD, 1 inch ID, and thin enough to draw around. The handle keeps her fingers out of the way and even has grips and a hole for a string.
The print quality near the hole isn’t as good as I’d like, because the slicer turned that entire volume into a solid slab of plastic. I can fix that in the second version, but right now she has something to work with, evaluate, and figure out what would improve it.
3D printing isn’t for everybody, but it’s a vital part of my shop!
The OpenSCAD source code has parameters for everything, so we can crank out more templates without fuss:
// Quilting - Circle Template // Ed Nisley KE4ZNU - July 2013 Layout = "Show"; // Show Build Circle Handle //------- //- Extrusion parameters must match reality! // Print with 2 shells ThreadThick = 0.25; ThreadWidth = 0.40; HoleFinagle = 0.2; HoleFudge = 1.00; function HoleAdjust(Diameter) = HoleFudge*Diameter + HoleFinagle; Protrusion = 0.1; // make holes end cleanly function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); function IntegerMultipleMin(Size,Unit) = Unit * floor(Size / Unit); inch = 25.4; //------- // Dimensions CircleID = (1) * inch; SeamAllowance = (1/4) * inch; CircleOD = CircleID + 2*SeamAllowance; CircleThick = 6*ThreadThick; CircleSides = 12*4; HandleHeight = (2) * inch; HandleThick = IntegerMultiple(5.0,ThreadWidth); HandleSides = 12*4; StringDia = 4.0; StringSides = 8; StringHeight = 0.75*HandleHeight; DentDepth = HandleThick/4; DentDia = 15.0; DentSphereRadius = (pow(DentDepth,2) + pow(DentDia,2)/4)/(2*DentDepth); //------- module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2); FixDia = Dia / cos(180/Sides); cylinder(r=HoleAdjust(FixDia)/2,h=Height,$fn=Sides); } module ShowPegGrid(Space = 10.0,Size = 1.0) { RangeX = floor(100 / Space); RangeY = floor(125 / Space); for (x=[-RangeX:RangeX]) for (y=[-RangeY:RangeY]) translate([x*Space,y*Space,Size/2]) %cube(Size,center=true); } //------- // Circle ring plate module CircleRing() { rotate(180/CircleSides) difference() { cylinder(r=CircleOD/2,h=CircleThick,$fn=CircleSides); translate([0,0,-Protrusion]) cylinder(r=CircleID/2,h=(CircleThick + 2*Protrusion),$fn=CircleSides); } } //------- // Handle module Handle() { difference() { rotate([0,90,0]) scale([HandleHeight/(CircleOD/2),0.9,1]) rotate(180/HandleSides) cylinder(r=CircleOD/2,h=HandleThick,center=true,$fn=HandleSides); translate([0,0,-HandleHeight]) cube([2*CircleOD,2*CircleOD,2*HandleHeight],center=true); translate([-HandleThick,0,StringHeight]) rotate([0,90,0]) rotate(180/StringSides) PolyCyl(StringDia,2*HandleThick,StringSides); # for (i=[-1,1]) { translate([i*(DentSphereRadius + HandleThick/2 - DentDepth),0,StringHeight]) sphere(r=DentSphereRadius); } } } module Template() { CircleRing(); Handle(); } //------- // Build it! ShowPegGrid(); if (Layout == "Circle") CircleRing(); if (Layout == "Handle") Handle(); if (Layout == "Show") Template();