POV-Ray : Newsgroups : povray.binaries.images : Four-Centered Arch : Re: Four-Centered Arch Server Time
20 May 2024 07:50:55 EDT (-0400)
  Re: Four-Centered Arch  
From: Samuel B 
Date: 23 Jul 2023 21:30:00
Message: <web.64bdd37db7f509a4f8c47d526e741498@news.povray.org>
"Samuel B." <stb### [at] hotmailcom> wrote:
> [...] Macro coming up shortly.

Here it is. The outer and inner arches are defined separately by width, height
and corner radius (smallest circle). Everything else applies to the entire
object.

#macro FourCenteredArch
 (
  AW1, // arch width 1 (from center)
  AH1, // arch height 1 (from ground)
  CR1, // radius 1 (outer corner, >=0 & <=AW1)

  AW2, // arch width 2 (from center)
  AH2, // arch height 2 (from ground)
  CR2, // radius 2 (inner corner, >=0 & <=AW2)

  AD, // arch depth (to -z)
  BV, // edge bevel radius
 )

 // a small value
 #local Eps = .0001;

 // intersection of a vertical line and circle, produces a y value (circle
radius, line x-position)
 #macro CircleLineIntercept(CirR, LinX)
  #local V = pow(CirR, 2) - pow(LinX, 2);
  #if(V>=0)
   (sqrt(V))
  #else
   (0)
  #end
 #end

 // calculate and return various values for shape and bevel macros
 #macro GetValues(AW, AH, CR, IO) // IO = is outside inside shape
  #declare CR = max(CR, BV*IO+Eps); // prevent circle radius from being negative
  #if(CR>=AW) #declare CR = AW-Eps; #end // prevent degenerate plane normal
  #declare CV  = <AW-CR, AH, 0>; // small circle position
  #declare CRT = 2 * CV.x; // get a temporarory circle radius based on distance
between initial circle centers
  #declare CY = (CircleLineIntercept(CRT, CV.x)); // get intercept of line and
1st circle
  #declare CV2 = CV - 2 * <CV.x, CY, 0>; // large  circle's position (will be
used directly for geometry)
  #declare CRL = 2 * CRT + CR; // large (second) circle's radius
  #declare CY2 = (CircleLineIntercept(CRL, CV2.x)); // value needed for shifting
geometry down (get y intercept of line and 2nd circle)
  #declare CO = (CV2.y+CY2-AH); // offset amount to shift geometry downward, to
fit inside box and top margin
  #declare CV = <CV.x, CV.y-CO, 0>; // offset CV
  #declare CV2 = <CV2.x, CV2.y-CO, 0>; // offset CV2
  #declare Dir = vnormalize(CV - CV2); // angle between 1st and 2nd circle
centers, used for various things
  #declare DirP = <Dir.y, -Dir.x, 0>; // perpendicular to Dir
  #declare ISP = <CV2.x-(CV2.y-CV.y)*Dir.x/Dir.y, CV.y, 0>; // find an
intersection to be used to prevent future CSG issues
  #declare PlaneDirP = plane{<CV2.y-CV.y, -CV2.x+CV.x, 0>, 0 translate CV}
 #end

 // basic shape
 #macro MakeShape(AW, AH, CR, AD, IC, IO)
  GetValues(AW, AH, CR, IO)
  #local IC = Eps * IC; // is a cutting object, so make an offset
  union{
   // solid portion under curve
   box{<-IC, -IC, 0-IC>, <AW, CV.y+Eps, AD+IC>}

   #macro Curve()
    union{
     difference{
      cylinder{
       z*(-IC), z*(AD+IC), CR
       translate CV
      }
      plane{y, CV.y-Eps}
      object{PlaneDirP inverse}
     }
     difference{
      cylinder{
       z*(-IC), z*(AD+IC), CRL
       translate CV2
      }
      plane{x, -IC}
      object{PlaneDirP translate -y*IC}
     }
    }
   #end

   object{Curve()}

   translate -z*AD
  }
 #end

 // bevels for curved portion
 #macro MakeBevel(AW, AH, CR, IO)
  GetValues(AW, AH, CR, IO)
  union{
   difference{
    torus{
     CR, BV
     rotate x*90
     translate CV+z*(BV-AD)
    }
    plane{y, CV.y}
    object{PlaneDirP inverse}
   }
   difference{
    torus{
     CRL, BV
     rotate x*90
     translate CV2+z*(BV-AD)
    }
    plane{x, 0}
    object{PlaneDirP}
   }
  }
 #end

 // final object
 union{
  #local ArchHalf =
   union{
    // shape offset +z by bevel value
    difference{
     MakeShape(AW1, AH1, CR1, AD-BV, false, true)
     MakeShape(AW2, AH2, CR2, AD-BV, true, false)
    }
    // shape inset by bevel value
    #if(BV>0)
     difference{
      MakeShape(AW1-BV, AH1-BV, CR1-BV, AD, false, true)
      MakeShape(AW2+BV, AH2+BV, CR2+BV, AD, true, false)
     }
     // bevels
     union{
      object{MakeBevel(AW1-BV, AH1-BV, CR1-BV, true)}
      cylinder{<AW1-BV, 0, -AD+BV>, <AW1-BV, CV.y, -AD+BV>, BV}
      object{MakeBevel(AW2+BV, AH2+BV, CR2+BV, false)}
      cylinder{<AW2+BV, 0, -AD+BV>, <AW2+BV, CV.y, -AD+BV>, BV}
     }
    #end
   }
  object{ArchHalf}
  object{ArchHalf scale <-1, 1, 1>}
 }

#end

Here's how to call the macro:

object{
 FourCenteredArch(
  1.0, // arch width 1 (from center)
  2.0, // arch height 1 (from ground)
  0.5, // radius 1 (outer corner, >=0 & <=arch width 1)

  0.6, // arch width 2 (from center)
  1.4, // arch height 2 (from ground)
  0.2, // radius 2 (inner corner, >=0 & <=arch width 2)

  0.3, // arch depth (to -z)
  0.03 // edge bevel radius (>arch depth)
 )
}


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.