#!/usr/bin/perl -w # # imagemap -- interpret NCSA imagemap file (with improvements) # # imagemap,v 1.8 1995/06/16 15:18:20 khera Exp # # V. Khera 7-MAR-1995 # # documentation for the imagemap file follows that of the NCSA imagemap # program. Each point is an x,y tuple. Each line in the map consists of # one of the following formats. Comment lines start with "#". # # circle URL center edgepoint # rect URL upperleft lowerright # point URL point # poly URL point1 point2 point3 point4 ... pointN # default URL # # using "point" and "default" in the same map makes no sense. if "point" # is used, the URL for the closest one is selected. # # URL's in this version of imagemap can be relative to the location of the # imagemap file itself, and relative links in the target file work as expected. # # to use imagemap, in your document put something like this: # # # # where guide/dc/metro.map is relative to the Document Root directory. # also, ScriptAlias /imagemap to this script (or stick it in your cgi-bin # directory and call it directly there). ## CONFIGURATION $webmaster = $ENV{SERVER_ADMIN}; # Apache extension $documentroot = $ENV{DOCUMENT_ROOT}; # Apache extension $servername = $ENV{SERVER_NAME}; ## END CONFIGURATION # global variables $defaultURL = ""; $minDistance = -1; # now, decode the PATH_INFO. (strip the leading "/") # This is the directory we wish to search ($mapfile = $ENV{PATH_INFO}) =~ s@^/@@; $query = $ARGV[0]; # translate back any html-escaped name parts $query =~ s/\+/ /g; $query =~ s/%([\da-f][\da-f])/pack("C",hex($1))/gei; &map($mapfile,$query); exit(0); # $mapfile is the imagemap file realative to DOCUMENT_ROOT # $query contains the coordinates of the point in question as "x,y" sub map { local($mapfile, $query) = @_; local($matched,$method,$url,$points); &error("No map name given") unless $mapfile; &error("Wrong number of arguments; browser may not support ISMAP") unless ($query =~ m/\d+,\d+/); open(FD, "$documentroot/$mapfile") || &error("Could not open $mapfile"); while () { chop; next if (m/^\#/ || m/^\s*$/); # skip comments and blank lines ($method,$url,$points) = split(/ /,$_,3); eval("\$matched = &pointIn_${method}('$url','$query','$points');"); &error("Malformed imagemap file: $method unknown") if ($@ ne ""); last if $matched; } close(FD); if ($defaultURL eq "") { print <<'EOM'; Content-type: text/html Imagemap Output

There was no match found in the imagemap for the point selected.

Please go back and try again.

EOM } else { # if URL does not start with method or a slash, prefix the path # with the directory containing the map file. if ($defaultURL !~ m@^[\w-]+://@ && $defaultURL !~ m@^/@) { $mapfile =~ s@(.*/)?.*@$1@; $defaultURL = "/" . $mapfile . $defaultURL; } # if it is not a full URL, make it one so that relative links # in the target page are properly referenced if ($defaultURL =~ m@^/@) { $defaultURL = "http://$servername" . ($ENV{SERVER_PORT}==80 ? "" : ":$ENV{SERVER_PORT}") . $defaultURL; } print "Location: $defaultURL\n\n"; } } # # set default URL. Only if not already set # sub pointIn_default { local($url,$point,@points) = @_; $defaultURL = $url if ($defaultURL eq ""); 0; } # # set default URL if this point is the closest so far # does not check for validity of parameters # sub pointIn_point { local($url,$point,$target) = @_; local($dist,@pt1,@pt2); @pt1 = $point =~ m/(\d+),(\d+)/; @pt2 = $target =~ m/(\d+),(\d+)/; $dist = ($pt1[0] - $pt2[0])**2 + ($pt1[1] - $pt2[1])**2; if ($minDistance == -1 || $dist < $minDistance) { $minDistance = $dist; $defaultURL = $url; } 0; } # # if point is in given rectangle, set default URL and cause main loop to end # sub pointIn_rect { local($url,$point,$target) = @_; local($ulx,$uly,$llx,$lly) = $target =~ m/(\d+),(\d+)\s+(\d+),(\d+)/; local($x,$y) = $point =~ m/(\d+),(\d+)/; if ($x >= $ulx && $y >= $uly && $x <= $llx && $y <= $lly) { $defaultURL = $url; return 1; # cause main loop to terminate } 0; } # # if point is in circle, set default URL and cause main loop to end # sub pointIn_circle { local($url,$point,$target) = @_; local($cx,$cy,$ex,$ey) = $target =~ m/(\d+),(\d+)\s+(\d+),(\d+)/; local($x,$y) = $point =~ m/(\d+),(\d+)/; local($distanceP,$distanceE); # compare squares of distance from center of edgepoint and given point $distanceP = ($cx - $x)**2 + ($cy - $y)**2; $distanceE = ($cx - $ex)**2 + ($cy - $ey)**2; if ($distanceP <= $distanceE) { $defaultURL = $url; return 1; # cause main loop to terminate } 0; } # # if point is in given polygon, set default URL and cause main loop to end # based mostly on code by Mike Lyons . # sub pointIn_poly { local($url,$point,$target) = @_; local($x,$y) = $point =~ m/(\d+),(\d+)/; local($pn,@px,@py); local($i,$intersections,$dy,$dx,$b,$m,$x1,$y1,$x2,$y2); # We'll treat the test point as the origin, so translate each # point in the polygon appropriately while($target =~ s/\s*(\d+),(\d+)//) { $px[$pn] = $1 - $x; $py[$pn] = $2 - $y; $pn++; } # A polygon with less than 3 points is an error if($pn<3) { return 0; } # Close the polygon $px[$pn] = $px[0]; $py[$pn] = $py[0]; # Now count the number of line segments in the polygon that intersect # the left side of the X axis. If it's an odd number we are inside the # polygon. # Assume no intersection $intersections=0; for($i = 0; $i < $pn; $i++) { $x1 = $px[$i ]; $y1 = $py[$i ]; $x2 = $px[$i+1]; $y2 = $py[$i+1]; # Line is completely to the right of the Y axis next if( ($x1>0) && ($x2>0) ); # Line doesn't intersect the X axis at all next if( (($y1<=>0)==($y2<=>0)) && (($y1!=0)&&($y2!=0)) ); # Special case.. if the Y on the bottom=0, we ignore this intersection # (otherwise a line endpoint counts as 2 hits instead of 1) if ($y2>$y1) { next if $y2==0; } elsif ($y1>$y2) { next if $y1==0; } else { # Horizontal span overlaying the X axis. Consider it an intersection # iff. it extends into the left side of the X axis $intersections++ if ( ($x1 < 0) || ($x2 < 0) ); next; } # We know line must intersect the X axis, so see where $dx = $x2 - $x1; # Special case.. if a vertical line, it intersects unless ( $dx ) { $intersections++; next; } $dy = $y2 - $y1; $m = $dy / $dx; $b = $y2 - $m * $x2; next if ( ( (0 - $b) / $m ) > 0 ); $intersections++; } # If there were an odd number of intersections to the left of the origin # (the clicked-on point) then it is within the polygon if ($intersections % 2) { $defaultURL = $url; return 1; # cause main loop to terminate } 0; } # # output error message # sub error { local($err) = @_; print "Content-type: text/html\n\n"; print "Imagemap Error\n"; print "

\n"; print "The imagemapping failed for some reason. Please contact\n"; print "$webmaster for assistance if needed.\n"; print "Sorry for any inconvenience.

\n"; print "

Error code: $err

\n"; exit(0); }