bin/ltview.pl
changeset 61 4f3a9f297a6a
parent 44 c8df2d579470
child 66 7e56c36eb1ae
equal deleted inserted replaced
60:448b4b706fa5 61:4f3a9f297a6a
     1 #!/usr/bin/perl
     1 #!/usr/bin/perl
     2 #
     2 #
     3 # Make a nice view of a luminaire
     3 # Make an interactive preview of a luminaire
     4 # Argument is the Radiance description of a luminaire, incl. distribution
       
     5 #
     4 #
     6 # This script is based on Radiance's objview.pl plus
     5 # This script is based on Radiance's objview.pl plus
     7 # Rob Guglielmetti's ltview extension to his objview.rb
     6 # Rob Guglielmetti's ltview extension to his objview.rb
     8 #
     7 #
     9 # Axel Jacobs, 25 Dec 2013
     8 # Written by Axel Jacobs <axel@jaloxa.eu>
    10 
     9 
    11 use strict;
    10 use strict;
    12 use warnings;
    11 use warnings;
       
    12 use Math::Trig;
       
    13 use File::Copy;
    13 use File::Temp qw/ tempdir /;
    14 use File::Temp qw/ tempdir /;
    14 
    15 
    15 my $td = tempdir( CLEANUP => 1 );
    16 my $td     = tempdir( CLEANUP => 1 );
    16 my $octree = "$td/lt$$.oct";
    17 my $oct    = "$td/ltview.oct";
    17 my $room = "$td/rm$$.rad";
    18 my $room   = "$td/room.rad";
    18 my $rif = "$td/lt$$.rif";
    19 my $rdim;               # Overall room dimensions
    19 my $lumi = "$td/lt$$.rad";
    20 my $rif    = "$td/ltview.rif";
    20 my $ambf = "$td/af$$.amb";
    21 my $lumi   = "$td/lumi.rad";
    21 my $raddev = "x11";   # default output device. Overwrite with -o
    22 my $ies    = "$td/lumi.ies";
    22 my $up = "Z";
    23 my $raddev = "x11";     # default output device. Overwrite with -o
    23 my $vw = "XYZ";    # default view. See 'man rad' for details
    24 my $is_ies = 0;         # input file is IES photometry, not a Radiance luminaire
    24 my $bubble = 0;    # Box or bubble?  0..box, 1..bubble
       
    25 my $TINY = 0.01;
       
    26 
    25 
    27 my $opts = "";        # Options common to rad and glrad
    26 my $maxscale = 1;       # Maximum luminiare dimension after scaling
    28 my $rendopts = "-ab 1 -ds .15 -av 0 0 0";    # For render= line in rif file
    27 my $opts     = "";      # Options common to rad and glrad
    29 my $usegl = 0;        # Run glrad instead of rad (Boolean).
    28 my $render   = "-ab 1 -ds .15 -av 0 0 0";    # render= line in rif file
    30 my $radopt = 0;       # An option specific to rad was passed (Boolean).
    29 my $radopt   = 0;       # An option specific to rad was passed (Boolean).
    31 my $glradopt = 0;     # An option specific to glrad was passed (Boolean).
       
    32 
    30 
    33 while (@ARGV) {
    31 while (@ARGV) {
    34 	$_ = $ARGV[0];
    32 	$_ = $ARGV[0];
    35 	if (m/-g/) {   # OpenGL output
    33 	if (m/-i/) {
    36 		if ( $^O =~ /MSWin32/ ) {
    34 		$is_ies = 1;
    37 			# No meaningful error messages under Windows. Just ignore...
       
    38 			#die("OpenGL view is not available under Windows.\n");
       
    39 		} else {
       
    40 			$usegl = 1;
       
    41 		}
       
    42 	} elsif (m/-u/) {   # up direction
       
    43 		$up = $ARGV[1];
       
    44 		shift @ARGV;
       
    45 	} elsif ((m/-s/) or (m/-w/)) {   # silent, no warnings
       
    46 		$opts .= " $_";
       
    47 	} elsif (m/-b/) {   # back face visibility
       
    48 		$rendopts .= ' -bv';
       
    49 	} elsif (m/-v/) {   # standard view "[Xx]?[Yy]?[Zz]?[vlcahs]?"
       
    50 		# Prepend view with '+' for custom view away from the luminaire, not at it.
       
    51 		# This is not defined by rad's default views.
       
    52 		$vw = $ARGV[1];
       
    53 		shift @ARGV;
       
    54 	} elsif (m/-N/) {   # No. of parallel processes
       
    55 		if ( $^O =~ /MSWin32/ ) {
       
    56 			# Silently ignore this under Windoze
       
    57 			#die("Multi-processor support is not available under Windows.\n");
       
    58 		} else {
       
    59 			$opts .= ' -N ' . $ARGV[1];
       
    60 		}
       
    61 		$radopt = 1;
       
    62 		shift @ARGV;
       
    63 	} elsif (m/-o/) {   # output device (rvu -devices)
    35 	} elsif (m/-o/) {   # output device (rvu -devices)
    64 		$raddev = $ARGV[1];
    36 		$raddev = $ARGV[1];
    65 		$radopt = 1;
    37 		$radopt = 1;
    66 		shift @ARGV;
    38 		shift @ARGV;
    67 	} elsif ((m/-V/) or (m/-e/)) {   # print view, explicate variables
    39 	} elsif (m/-r/) {
    68 		# Think of those two as '-verbose'.
    40 		$rdim = $ARGV[1];    # Room dimensions
    69 		$opts .= " $_";
    41 		shift @ARGV;
    70 		$radopt = 1;
       
    71 	} elsif (m/-S/) {   # full-screen stereo
       
    72 		$opts .= " $_";
       
    73 		$glradopt = 1;
       
    74 	} elsif (m/-r/) {    # spherical room rather than box
       
    75 		$bubble = 1;
       
    76 	} elsif (m/^-\w/) {
    42 	} elsif (m/^-\w/) {
    77 		die("objview: Bad option: $_\n");
    43 		die("objview: Bad option: $_\n");
    78 	} else {
    44 	} else {
    79 		last;
    45 		last;
    80 	}
    46 	}
    81 	shift @ARGV;
    47 	shift @ARGV;
    82 }
    48 }
    83 
    49 
    84 # We need exactly one input file: a Radiance luminaires description
    50 # We need one Radiance luminaires description, or an IES file
    85 #TODO: this could be expanded to handle Radiance .dat files and IES photometry files...
       
    86 if (! $#ARGV == 0) {
    51 if (! $#ARGV == 0) {
    87 	die("ltview: Need one Radiance luminaire.\n");
    52 	die("ltview: Need one Radiance luminaire or IES file.\n");
    88 }
       
    89 
       
    90 # Make sure we don't confuse glrad and rad options.
       
    91 if ($usegl) {
       
    92 	if ($radopt) {
       
    93 		die("objview: glrad output requested, but rad option passed.\n");
       
    94 	}
       
    95 } else {
       
    96 	if ($glradopt) {
       
    97 		die("objview: rad output requested, but glrad option passed.\n");
       
    98 	}
       
    99 }
    53 }
   100 
    54 
   101 open(FH, ">$room") or
    55 open(FH, ">$room") or
   102 		die("ltview: Can't write to temporary file $room\n");
    56 		die("ltview: Can't write to temporary file $room\n");
   103 print FH "void plastic wall_mat  0  0  5 .2 .2 .2 0 0\n";
    57 print FH "void plastic wall_mat  0  0  5 .2 .2 .2 0 0\n";
   104 
    58 
   105 if ($bubble == 1) {
    59 my $r;
   106 	# Room is a bubble, not a box
    60 if (defined $rdim) {
   107 	my $radius = sprintf "%.6f", 1.1*5 * 3**(1/3);
    61 	# Room dimensions are giving explicitly.  Don't touch the fitting.
   108 	print FH "wall_mat sphere orb  0  0  4 0 0 0 $radius\n";
    62 	$r = $rdim;
       
    63 
       
    64 	copy ($ARGV[0], $lumi);
   109 } else {
    65 } else {
   110 	print FH <<EndOfRoom;
    66 	# Scale fitting so it fits nicely into our default test room.
   111 # Don't rely on genbox here (named genrbox under Debian/Ubuntu)
    67 	$r = 5;    # Default room dimension
   112 wall_mat polygon box.1540  0  0  12  5 -5 -5  5 -5 5  -5 -5 5  -5 -5 -5
    68 
   113 wall_mat polygon box.4620  0  0  12  -5 -5 5  -5 5 5  -5 5 -5  -5 -5 -5
    69 	# Work out how large the luminaire is and scale so that the longest
   114 wall_mat polygon box.2310  0  0  12  -5 5 -5  5 5 -5  5 -5 -5  -5 -5 -5
    70 	# axis-align dimension is $maxscale
   115 wall_mat polygon box.3267  0  0  12  5 5 -5  -5 5 -5  -5 5 5  5 5 5
    71 	my $dimstr = `getbbox -h $ARGV[0]`;
   116 wall_mat polygon box.5137  0  0  12  5 -5 5  5 -5 -5  5 5 -5  5 5 5
    72 	chomp $dimstr;
   117 wall_mat polygon box.6457  0  0  12  -5 5 5  -5 -5 5  5 -5 5  5 5 5
    73 	# Values returned by getbbox are indented and delimited with multiple spaces.
       
    74 	$dimstr =~ s/^\s+//;   # remove leading spaces
       
    75 	my @dims = split(/\s+/, $dimstr);   # convert to array
       
    76 
       
    77 	# Find largest axes-aligned dimension
       
    78 	my @diffs = ($dims[1]-$dims[0], $dims[3]-$dims[2], $dims[5]-$dims[4]);
       
    79 	@diffs = reverse sort { $a <=> $b } @diffs;
       
    80 	my $size = $diffs[0];
       
    81 
       
    82 	# Move objects so centre is at origin
       
    83 	my $xtrans = -1.0 * ($dims[0] + $dims[1]) / 2;
       
    84 	my $ytrans = -1.0 * ($dims[2] + $dims[3]) / 2;
       
    85 	my $ztrans = -1.0 * ($dims[4] + $dims[5]) / 2;
       
    86 	# Scale so that largest object dimension is $maxscale
       
    87 	my $scale = $maxscale / $size;
       
    88 
       
    89 	system "xform -t $xtrans $ytrans $ztrans -s $scale $ARGV[0] > $lumi";
       
    90 }
       
    91 
       
    92 print FH <<EndOfRoom;
       
    93 # Don't generate -y face so we can look into the box (could use clipping)
       
    94 #wall_mat polygon box.1540  0  0  12  $r -$r -$r  $r -$r $r  -$r -$r $r  -$r -$r -$r
       
    95 wall_mat polygon box.4620  0  0  12  -$r -$r $r  -$r $r $r  -$r $r -$r  -$r -$r -$r
       
    96 wall_mat polygon box.2310  0  0  12  -$r $r -$r  $r $r -$r  $r -$r -$r  -$r -$r -$r
       
    97 wall_mat polygon box.3267  0  0  12  $r $r -$r  -$r $r -$r  -$r $r $r  $r $r $r
       
    98 wall_mat polygon box.5137  0  0  12  $r -$r $r  $r -$r -$r  $r $r -$r  $r $r $r
       
    99 wall_mat polygon box.6457  0  0  12  -$r $r $r  -$r -$r $r  $r -$r $r  $r $r $r
   118 EndOfRoom
   100 EndOfRoom
   119 }
       
   120 close(FH);
   101 close(FH);
   121 
       
   122 # Work out how large the luminaire is and scale so that the longest
       
   123 # axis-align dimension is one unit
       
   124 my $dimstr = `getbbox -h $ARGV[0]`;
       
   125 chomp $dimstr;
       
   126 # Values returned by getbbox are indented and delimited with multiple spaces.
       
   127 $dimstr =~ s/^\s+//;   # remove leading spaces
       
   128 my @dims = split(/\s+/, $dimstr);   # convert to array
       
   129 
       
   130 # Find largest axes-aligned dimension
       
   131 my @diffs = ($dims[1]-$dims[0], $dims[3]-$dims[2], $dims[5]-$dims[4]);
       
   132 @diffs = reverse sort { $a <=> $b } @diffs;
       
   133 my $size = $diffs[0];
       
   134 
       
   135 # Move objects so centre is at origin
       
   136 my $xtrans = -1.0 * ($dims[0] + $dims[1]) / 2;
       
   137 my $ytrans = -1.0 * ($dims[2] + $dims[3]) / 2;
       
   138 my $ztrans = -1.0 * ($dims[4] + $dims[5]) / 2;
       
   139 # Scale so that largest object dimension is unity
       
   140 my $scale = 1 / $size;
       
   141 
       
   142 my $cmd = "xform -t $xtrans $ytrans $ztrans -s $scale $ARGV[0] > $lumi";
       
   143 system "$cmd";
       
   144 
   102 
   145 my $scene = "$room $lumi";
   103 my $scene = "$room $lumi";
   146 # Make this work under Windoze
   104 # Make this work under Windoze
   147 if ( $^O =~ /MSWin32/ ) {
   105 if ( $^O =~ /MSWin32/ ) {
   148 	$scene =~ s{\\}{/}g;
   106 	$scene =~ s{\\}{/}g;
   149 	$octree =~ s{\\}{/}g;
   107 	$oct =~ s{\\}{/}g;
   150 	$ambf =~ s{\\}{/}g;
       
   151 	$raddev = "qt";
   108 	$raddev = "qt";
   152 }
   109 }
   153 
   110 
   154 my $custom_vw = $vw;
   111 # Tweak bounding box so we get a nice view covering all of the box, without
   155 $vw =~ s/^\+//;
   112 # having a wasteful black border around it.  Must work for arbitrary box dims.
       
   113 my $zone = 1.1 * $r * ( 1 + 1/tan(22.5*pi/180) );
       
   114 
   156 open(FH, ">$rif") or
   115 open(FH, ">$rif") or
   157 		die("ltview: Can't write to temporary file $rif\n");
   116 		die("ltview: Can't write to temporary file $rif\n");
   158 print FH <<EndOfRif;
   117 print FH <<EndOfRif;
   159 scene= $scene
   118 scene= $scene
   160 EXPOSURE= 2
   119 EXPOSURE= 2
   161 ZONE= Interior -5 5  -5 5  -5 5
   120 ZONE= Interior -$zone $zone  -$zone $zone  -$zone $zone
   162 UP= $up
   121 UP= Z
   163 view= $vw
   122 view= y
   164 OCTREE= $octree
   123 OCTREE= $oct
   165 oconv= -f
   124 oconv= -f
   166 AMBF= $ambf
   125 render= $render
   167 render= $rendopts
       
   168 EndOfRif
   126 EndOfRif
   169 close(FH);
   127 close(FH);
   170 
   128 
   171 # Custom view: look away from the luminaire, not at it.  This is indicated
   129 system "rad -o $raddev $opts $rif";
   172 # by a leading '+' in front of the view (-v argument, default: XYZ)
       
   173 if ($custom_vw =~ m/^\+/) {
       
   174 	# Get rad to spit out the -v* options for the default view requested
       
   175 	my $view = `rad -V -n -s $rif`;
       
   176 	$view =~ s/\n//;
       
   177 	$view =~ s/^VIEW= //;
       
   178 
       
   179 	my $x = 0;
       
   180 	my $y = 0;
       
   181 	my $z = 0;
       
   182 	if ($vw =~ m/X/) {
       
   183 		$x = $dims[0] - $TINY;
       
   184 	} elsif ($vw =~ m/x/) {
       
   185 		$x = $dims[1] + $TINY;
       
   186 	}
       
   187 	if ($vw =~ m/Y/) {
       
   188 		$y = $dims[2] - $TINY;
       
   189 	} elsif ($vw =~ m/y/) {
       
   190 		$y = $dims[3] + $TINY;
       
   191 	}
       
   192 	if ($vw =~ m/Z/) {
       
   193 		$z = $dims[4] - $TINY;
       
   194 	} elsif ($vw =~ m/z/) {
       
   195 		$z = $dims[5] + $TINY;
       
   196 	}
       
   197 	
       
   198 	# Keep rad-generated standard view, but modify -vp
       
   199 	$vw = "nice $view -vp $x $y $z";
       
   200 
       
   201 	open(FH, ">$rif") or
       
   202 			die("ltview: Can't write to temporary file $rif\n");
       
   203 	print FH <<EndOfRif2;
       
   204 scene= $scene
       
   205 EXPOSURE= 2
       
   206 ZONE= Interior -5 5  -5 5  -5 5
       
   207 UP= $up
       
   208 view= $vw
       
   209 OCTREE= $octree
       
   210 oconv= -f
       
   211 AMBF= $ambf
       
   212 render= $rendopts
       
   213 EndOfRif2
       
   214 	close(FH);
       
   215 }
       
   216 
       
   217 if ($usegl) {
       
   218 	system "glrad $opts $rif";
       
   219 } else {
       
   220 	system "rad -o $raddev $opts $rif";
       
   221 }
       
   222 
   130 
   223 #EOF
   131 #EOF