#!/usr/local/bin/perl # perl script for Equal 8 Sided Octagon Rafter Calculations use CGI::Carp qw(fatalsToBrowser); #comment out this line when your done debugging this script $|++; #dont't buffer output #use strict; # file name:: full-octagon.cgi # Created on Sunday, July 15, 2007 by Sim Ayers of SBE Builders # get latest version of this script at http://www.sbebuilders.com ################################################### # You are free to customize this script as you wish. # DISCLAIMER # The information and code provided is provided 'as is' without # warranty of any kind, either express or implied. In no event # shall the Company SBE Builders be liable for any damages whatsoever # including direct, indirect, incidental, consequential, loss of # business profits or special damages, even if the author has been # advised of the possibility of such damages. # DO NOT USE THIS SCRIPT UNLESS YOU CAN FULLY AGREE WITH THIS # DISCLAIMER. # copyright(C) 2007 ################################################### =head In a circle of radius r, the length of the chord that subtends a central angle x is r * sin( x/2). This script uses the theory of an octagon inscribed inside of a circle. So the radius is the run of the octagon hips and the chord is the length of the sides of the octagon. =cut my ($content_type_printed,%data,$back_wall,$projection,$face_wall,$pitch,$show_feet_inches); # print out perl headers to browser print "Content-type: text/plain\n\n" unless $content_type_printed++; &read_input(); #read user input variables if ($data{'face_wall'} eq ""){ # hand edit octagon variables below for default values $face_wall = 67.88; $pitch = 8; $show_feet_inches = 'no'; $jack_spacing = 12; $overhang = 24; } else{ $face_wall = $data{'face_wall'}; $pitch = $data{'pitch'}; $show_feet_inches = $data{'show_feet_inches'}; $jack_spacing = $data{'jack_spacing'}; $overhang = $data{'overhang'}; } #Global symbols # http://perldoc.perl.org/Math/Complex.html use Math::Complex qw(:trig); use POSIX qw(ceil floor); $PIE = 3.14159265358979323846; $RAD_TO_DEGREE = (180/pi); $DEGREE_TO_RAD = ($PIE/180); $RAD_TO_DEGREE45 = (0.785398163397448309616); $dxf_line_count = 100; $DXF_STYLE=0; #dxf Line style $DXF_LAYER=0; #dxf file LAYER number $DXF_COLOR=0; # dxf line color $DXF_TSIZE=4.0; #dxf default dxf text size $half_the_thickness_of_the_hips = 0.75; $nsides=8; # walls at 45 degree angles to face wall $projection = $face_wall * cos(45 * $DEGREE_TO_RAD); $projection_offset = $projection; # get geometry angles for baywindow $run = (($projection * 2) + $face_wall) / 2; $face_wall_half = $face_wall /2; $projection_wall_angle_deg = 45; $projection_offset_wall_angle_deg = 90 - $projection_wall_angle_deg; $interior_wall_angle_deg = 135; $projection_wall_length = $projection_offset / cos($projection_wall_angle_deg * $DEGREE_TO_RAD); $half_projection_wall_length = $projection_wall_length / 2; $bay_hip_rafter_run_bisect_angle_deg = $RAD_TO_DEGREE * atan($run / $face_wall_half); $bay_hip_rafter_top_angle_deg = 90 - $bay_hip_rafter_run_bisect_angle_deg; $pitch_angle = $RAD_TO_DEGREE * atan($pitch / 12); $Major_Pitch = atan($pitch / 12); $common_rafter_rise = $run * ($pitch / 12); $common_rafter_length = $run / cos(atan($pitch / 12)); $common_jackrafter_run = $jack_spacing * tan($bay_hip_rafter_run_bisect_angle_deg * $DEGREE_TO_RAD); $common_jackrafter_length = $common_jackrafter_run / cos(atan($pitch / 12)); $overhang_face_wall_length = $overhang / cos(atan($pitch / 12)); $bay_hip_rafter_run = $face_wall_half / cos($bay_hip_rafter_run_bisect_angle_deg * $DEGREE_TO_RAD); $radius = $bay_hip_rafter_run; $bay_hip_rafter_angle = atan($common_rafter_rise / $bay_hip_rafter_run); $bay_hip_rafter_length = $bay_hip_rafter_run / cos($bay_hip_rafter_angle); $bay_hip_rafter_bevel_angle = 90 - $bay_hip_rafter_run_bisect_angle_deg; $bay_hip_rafter_unit_run = (12 / sin($DEGREE_TO_RAD * $bay_hip_rafter_run_bisect_angle_deg)); $overhang_bay_hip_run = $overhang / cos($bay_hip_rafter_top_angle_deg * $DEGREE_TO_RAD); $overhang_bay_hip_length = $overhang_bay_hip_run / cos($bay_hip_rafter_angle); print "Equal 8 Sided Octagon Rafter Calculations"; print "\nCalculations are rounded to the nearest 1/16 inch"; print "\n\n Face Wall length = " .convertTOfeet($face_wall); print "\n\n Total Width of Octagon = " .convertTOfeet($run*2); print "\n\n Diameter of Octagon = " .convertTOfeet($bay_hip_rafter_run*2); print "\n\n Radius of Octagon = " .convertTOfeet($bay_hip_rafter_run); print "\n\n Projection of Bay Window = " .convertTOfeet($projection); print "\n\n Projection Offset = " .convertTOfeet($projection_offset); print "\n\n Projection Wall Length = " .convertTOfeet($projection_wall_length); print "\n\n Projection Wall Angle = " .roundAngle($projection_wall_angle_deg); print "\n\n Projection Offset Wall Angle = " .roundAngle($projection_offset_wall_angle_deg); print "\n\n Interior Wall Angle = " .roundAngle($interior_wall_angle_deg); print "\n\n Bay Hip Rafter Run Bisect Angle = " .roundAngle($bay_hip_rafter_run_bisect_angle_deg); print "\n\n Common Rafter Run = " .convertTOfeet($run); print "\n\n Common Rafter Pitch = " .roundAngle($pitch); print "\n\n Common Rafter Pitch Angle = " .roundAngle($pitch_angle); print "\n\n Common Rafter Rise = " .convertTOfeet($common_rafter_rise); print "\n\n Common Rafter Length = " .convertTOfeet($common_rafter_length); print "\n\n Common Rafter Overhang Run = " .convertTOfeet($overhang); print "\n\n Common Overhang Rafter Length = " .convertTOfeet($overhang_face_wall_length); print "\n\n Common Jack Rafter Difference in Length = " .convertTOfeet($common_jackrafter_length); print "\n\n Bay Hip Rafter Angle = " .roundAngle($bay_hip_rafter_angle * $RAD_TO_DEGREE); print "\n\n Bay Hip Rafter Bevel Angle = " .roundAngle($bay_hip_rafter_bevel_angle); print "\n\n Bay Hip Rafter Run = " .convertTOfeet($bay_hip_rafter_run); print "\n\n Bay Hip Rafter Length = " .convertTOfeet($bay_hip_rafter_length); print "\n\n Bay Hip Rafter Overhang Run = " .convertTOfeet($overhang_bay_hip_run); print "\n\n Bay Hip Rafter Overhang Rafter Length = " .convertTOfeet($overhang_bay_hip_length); $Major_Side_Plan_Angle = $bay_hip_rafter_run_bisect_angle_deg * $DEGREE_TO_RAD; $Frieze_Block_Angle = atan (sin ($Major_Pitch) / tan($Major_Side_Plan_Angle)); $Frieze_Block_Bevel_Angle = atan (sin ($Frieze_Block_Angle) / tan ($Major_Pitch)); print "\n\n Bay Hip Plan Angle = " .roundAngle($Major_Side_Plan_Angle * $RAD_TO_DEGREE); print "\n\n Frieze Block Angle = " .roundAngle($Frieze_Block_Angle * $RAD_TO_DEGREE); print "\n\n Frieze Block Bevel Angle = " .roundAngle($Frieze_Block_Bevel_Angle * $RAD_TO_DEGREE); $Backing_Angle = acos (cos($pitch_angle * $DEGREE_TO_RAD) / cos ($bay_hip_rafter_angle)); print "\n\n Bay Hip Rafter Backing Angle = " .roundAngle($Backing_Angle * $RAD_TO_DEGREE); $bay_hip_rafter_drop = ($pitch * ($half_the_thickness_of_the_hips / tan($bay_hip_rafter_run_bisect_angle_deg * $DEGREE_TO_RAD))/$bay_hip_rafter_unit_run); print "\n\n Bay Hip Rafter Drop = " .convertTOfeet($bay_hip_rafter_drop); # text file with dxf header information $DXF_HEADER_FILE = "dxf_header.txt"; # text file to save dxf drawing to $DXF_File="full-octagon.dxf"; #load dxf header file $dxf_header = get_dxf_header_file($DXF_HEADER_FILE); open(FILE, ">$DXF_File") || die("$DXF_File: Can't open because ($!)."); # add dxf header information to dxf output file print FILE "$dxf_header\n0\n"; # origin center in dxf document $originX = 100; $originY = 100; $poly_start_angle = (2 * $PIE) / $nsides; $theta = $poly_start_angle; $start_angle = $theta / 2; $x1 = $originX; $y1 = $originY; $radius2 = $overhang_bay_hip_run + $radius; $radius3 = $overhang + $run; $sfx2 = $originX + $radius * cos(($theta ) + $start_angle); $sfy2 = $originY + $radius * sin(($theta ) + $start_angle); $sfx22 = $originX + $radius2 * cos(($theta ) + $start_angle); $sfy22 = $originY + $radius2 * sin(($theta ) + $start_angle); # draw wall line for($i=1; $i<$nsides+2; $i++){ $x2 = $radius * cos(($theta * $i) + $start_angle); $y2 = $radius * sin(($theta * $i) + $start_angle); $x2 += $originX; $y2 += $originY; dxf_line($x2,$y2,$sfx2,$sfy2); $sfx2 = $x2; $sfy2 = $y2; $x22 = $radius2 * cos(($theta * $i) + $start_angle); $y22 = $radius2 * sin(($theta * $i) + $start_angle); $x22 += $originX; $y22 += $originY; dxf_line($x22,$y22,$sfx22,$sfy22); $sfx22 = $x22; $sfy22 = $y22; } # draw hips & king common rafters for($i=1; $i<=$nsides; $i++){ $x2 = $radius2 * cos(($theta * $i) + $start_angle); $y2 = $radius2 * sin(($theta * $i) + $start_angle); $x2 += $originX; $y2 += $originY; dxf_line($x1,$y1,$x2,$y2); $x2 = $radius3 * cos(($theta * $i)); $y2 = $radius3 * sin(($theta * $i)); $x2 += $originX; $y2 += $originY; dxf_line($x1,$y1,$x2,$y2); } # draw jack rafters $max = abs($face_wall_half / $jack_spacing); $common_jackrafter_run = $jack_spacing * tan($bay_hip_rafter_run_bisect_angle_deg * $DEGREE_TO_RAD); $common_jackrafter_run = $jack_spacing * tan($bay_hip_rafter_run_bisect_angle_deg * $DEGREE_TO_RAD); $offset = $jack_spacing / cos ($bay_hip_rafter_run_bisect_angle_deg * $DEGREE_TO_RAD); $offset_run = $jack_spacing * tan ($bay_hip_rafter_run_bisect_angle_deg * $DEGREE_TO_RAD); for($j=1; $j<$max; $j++){ $jack_offset = $run - ($offset_run * $j); $common_jackrafter_length = $jack_offset / cos($Major_Pitch); print "\n\nJack Rafter # $j = " .convertTOfeet($common_jackrafter_length); for($i=1; $i<=$nsides; $i++){ $radius = ($overhang + $run) - ($offset_run * $j); $x1 = $originX + ($offset * ($j ))* sin(($theta * $i)+ $start_angle); $y1 = $originY + ($offset * ($j ))* cos(($theta * $i)+ $start_angle); $x2 = $radius * sin(($theta * $i) + $start_angle*2); $y2 = $radius * cos(($theta * $i) + $start_angle*2); $x2 += $x1; $y2 += $y1; dxf_line($x1,$y1,$x2,$y2); $x1 = $originX + ($offset * ($j ))* sin(($theta * $i)+ $start_angle); $y1 = $originY + ($offset * ($j ))* cos(($theta * $i)+ $start_angle); $x2 = $radius * sin(($theta * $i)); $y2 = $radius * cos(($theta * $i)); $x2 += $x1; $y2 += $y1; dxf_line($x1,$y1,$x2,$y2); } } $str= "ENDSEC\n0\nEOF"; print FILE $str; close FILE; exit; ################################### # library sub routines follow ################################### # [Ctrl]+E for zoom extents sub dxf_line { my ($x1,$y1,$x2,$y2) = @_; $color=0; $dxf_line_count++; $str = sprintf("LINE\n5\n%dD\n8\n%d\n6\nCONTINOUS\n62\n%d\n10\n%lf\n20\n%lf\n30\n0.0\n11\n%lf\n21\n%lf\n31\n0.0\n0\n", $dxf_line_count,$DXF_LAYER,$DFX_COLOR,$x1,$y1,$x2,$y2); #print $str; print FILE $str; } #=============================================================================# sub escape_string { my($esc) = @_; $esc =~ s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg; $esc =~ s/ /+/g; return $esc; } #=============================================================================# sub get_dxf_header_file{ my($file)=shift; my $header; open(FH, "<$file") || die("$file: Can't open because ($!)."); while(){ $header .= $_; } close(FH); return $header; } #=============================================================================# sub hypot{ my ($x,$y) = @_; my $s = sqrt( $x* $x + $y * $y); return $s; } #=============================================================================# sub convertTOfeet{ my ($decimal) = @_; return $decimal unless $show_feet_inches eq 'yes'; #print "\n inches decimal = " .$decimal; my $wholefeet = floor($decimal/12); my $wholeinch = floor($decimal - ($wholefeet*12)); my $decimalfrac = ($decimal*1) - floor($decimal); my ($frac1,$frac2,$frac_str); $frac2 = 16; if ($decimalfrac >= 0.9774) # 15/16 = 0.9375 { $wholeinch++; $decimalfrac = 0.00; if($wholeinch == 12) { $wholefeet++; $wholeinch = 0; } } if ($decimalfrac > 0.0001) { $frac1 = $decimalfrac * $frac2; my $wholefrac = floor($decimalfrac * $frac2); $frac1 = ceil($decimalfrac * $frac2); $frac1 = 15 if($frac1 == 16); ($frac1,$frac2) = check_frac($frac1,$frac2); $frac_str = sprintf(" %d/%d",$frac1,$frac2); } my $str = sprintf("%d'-%d%s''", $wholefeet,$wholeinch,$frac_str); return $str; } #=============================================================================# sub check_frac{ my ($numerator ,$denominator) = @_; return (7,8) if $numerator eq 14; return (3,4) if $numerator eq 12; return (5,8) if $numerator eq 10; return (1,2) if $numerator eq 8; return (3,8) if $numerator eq 6; return (1,4) if $numerator eq 4; return (1,8) if $numerator eq 2; return ("","") if $numerator eq 0; return ("","") if $denominator eq 0; return ($numerator ,$denominator); } #=============================================================================# sub roundAngle{ my ($angle) = @_; my $str = sprintf("%.2f",$angle); return $str; } #===================================================================# sub read_input { my($buffer) = undef; my ($item); if ($ENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); } else { $buffer=$ENV{'QUERY_STRING'}; } $buffer = $ARGV[0] if (not $buffer); my @pairs=split(/&/,$buffer); foreach $item(@pairs) { my ($key,$content)=split (/=/,$item,2); # Split into key and value. $content =~ tr/+/ /; # Convert plus's to spaces $content =~ s/%(..)/pack("c",hex($1))/ge; # Convert %XX from hex numbers to alphanumeric $content =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # prevent hackers from exploiting the input name $key =~ tr/+/ /; # Convert plus's to spaces $key =~ s/%(..)/pack("c",hex($1))/ge; # Convert %XX from hex numbers to alphanumeric $key =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $key =~ s/ /_/g; # get rid of attempts to insert HTML tags $content =~ s///g; # server-side-includes $content =~ s/<([^>]|\n)*>//gs; $content =~ s//>/g; # get rid of attempts to insert illegal characters $content =~ s/\\//g; # remove black slashes $content =~ s/\0//g; # remove nulls $content =~ s/[\\\&\;\`\'\"\|\*\?\~\^\[\]\{\}\$]//gs; $content =~ s/\cM/\n/g; #convert CR to LF $content =~ s/^\s+|\s+$//gs; $content = substr($content,0,4096); $data{$key} = $content; } return 1; }