#! /usr/bin/perl # # gen_obj.pl # convert GIS building format file into OBJ format file # (This program check GIS data) # (the format is defined by hatayama@cs.dis.tutech.co.jp) # Version 1.02 2000/01/25 # Version 1.1 2001/05/20 # Version 1.2 2001/10/22 # # Author and Contact: kuwatay@nttdata.co.jp # # Copyright (C) 2000,2001 by Yoshitaka Kuwata # Copyright (C) 2000,2001 by NTT DATA CORPORATION # All Right Reserved # $objfile = "nagata_building.obj"; # default filename $verbose = 0; # set 1 if for verbose messages $vverbose = 0; # very verbose $comment = 1; # output comment $gengroup = 1; # generate group code, 1 for grouping $genmaterial = 0; # generate material code 1 for generate $genfloor = 0; # generate floor polygon $building_file = "building"; # default input file (building) $road_file = "road"; # default input file (road) $node_file = "node"; # default input file (node) $del_last_vertex = 0; # delete the last vertex $genobj = 1; # generate obj file (default) # parse command line arguments for ($i = 0 ; $i <= $#ARGV ; $i++) { if ( $ARGV[$i] =~ /^-f(.[a-zA-Z0-9_\/\.]*)/) { # outpot file $objfile = $1; } elsif ( $ARGV[$i] =~ /^-b(.[a-zA-Z0-9_\/\.]*)/) { # building file $building_file = $1; } elsif ( $ARGV[$i] =~ /^-r(.[a-zA-Z0-9_\/\.]*)/) { # road file $road_file = $1; } elsif ( $ARGV[$i] =~ /^-n(.[a-zA-Z0-9_\/\.]*)/) { # node file $node_file = $1; } elsif ( $ARGV[$i] =~ /^-v/) { # verbose $verbose = 1; } elsif ( $ARGV[$i] =~ /^-g/) { # make building & road in groups $gengroup = 1; } elsif ( $ARGV[$i] =~ /^-m/) { # use material $genmaterial = 1; } elsif ( $ARGV[$i] =~ /^-n/) { # generate floor $genfloor = 1; } elsif ( $ARGV[$i] =~ /^-d/) { # generate floor $del_last_vertex = 1; } elsif ( $ARGV[$i] =~ /^-c/) { # check only $genobj = 0; $verbose = 1; $vverbose = 1; } elsif ( $ARGV[$i] =~ /^-/) { printf("Unrecognized \"%s\"\n", $ARGV[$i]); usage(); exit(1); } else { $building_file = $ARGV[$i]; # building } } # open outpot file if ($genobj) { open (OBJFILE, "> $objfile") || die ("Cannot open output file \"$objfile\""); generate_header(); } ##################################################################### # open building file open(BUILDING_FILE, "< $building_file") || die ("Cannot open building file"); # read header part of the file $number = read_unsigned(BUILDING_FILE); $offsetx = read_long(BUILDING_FILE); $offsety = read_long(BUILDING_FILE); $n = read_unsigned(BUILDING_FILE); if ($verbose) { printf("Coordinate system number:%d\n", $number); printf("Coordinate system offset(%d, %d)\n", $offsetx, $offsety); printf("number of points:%d\n", $n); } for ($i = 0 ; $i < $n ; $i++) { read_building_record(); } close(BUILDING_FILE); ##################################################################### # open node file open(NODE_FILE, "< $node_file") || die ("Cannot open node file $node_file"); # read header part of the node file $number = read_unsigned(NODE_FILE); $offsetx = read_long(NODE_FILE); $offsety = read_long(NODE_FILE); $n = read_unsigned(NODE_FILE); for ($i = 0 ; $i < $n ; $i++) { read_node_record(); } close(NODE_FILE); if ($genobj) { if ($genmaterial) { # printf OBJFILE ("usemtl flwhite\n"); printf OBJFILE ("usemtl archwhite1\n"); } printf OBJFILE ("# from road file\n"); } ##################################################################### # open road file open(ROAD_FILE, "< $road_file") || die ("Cannot open road file $road_file"); # read header part of the road file $number = read_unsigned(ROAD_FILE); $offsetx = read_long(ROAD_FILE); $offsety = read_long(ROAD_FILE); $n = read_unsigned(ROAD_FILE); for ($i = 0 ; $i < $n ; $i++) { read_road_record(); } close(ROAD_FILE); if ($genobj) { close (OBJFILE); } # end of main program ##################################################################### sub generate_header() { printf OBJFILE ("# DON'T EDIT THIS FILE\n"); printf OBJFILE ("# THIS FILE WAS CREATED BY $0\n"); printf OBJFILE ("# Copyright (C) 2001 by Y. Kuwata\n# All rights reserved\n\n"); if ($genmaterial) { printf OBJFILE ("usemtl archwhite\n"); } } sub read_building_record() { # read stuff $size = read_unsigned(BUILDING_FILE); $id = read_unsigned(BUILDING_FILE); $center_x = read_unsigned(BUILDING_FILE); $center_y = read_unsigned(BUILDING_FILE); $nfloor = read_unsigned(BUILDING_FILE); $attr = read_unsigned(BUILDING_FILE); $is_burning = read_unsigned(BUILDING_FILE); $p_burned = read_unsigned(BUILDING_FILE); $p_broken = read_unsigned(BUILDING_FILE); $nn = read_unsigned(BUILDING_FILE); # error checking if ($nfloor < 1) { printf STDERR ("Error on nfloor in ID: $id\n"); } # for ($j = 0 ; $j < $nn ; $j++) { $node = read_unsigned(BUILDING_FILE); # just pass by } $fig_id = read_unsigned(BUILDING_FILE); $area1f = read_unsigned(BUILDING_FILE); $areaall = read_unsigned(BUILDING_FILE); $structure = read_unsigned(BUILDING_FILE); $nn = read_unsigned(BUILDING_FILE); if ($nn < 3) { printf STDERR ("Warning: #coordinate is less than 3, ID: $id\n"); } if ($genobj) { printf OBJFILE ("# building ID=$id\n"); $height = calc_height( $nfloor); $vformat = "v %6.4f %6.4f %6.4f\n"; # grouping if ($gengroup) { printf OBJFILE ("g b-%05d\n", $id); } } # read coordinates for ($j=0 , $p=0; $j < $nn ; $j++, $p++) { $x[$p] = read_unsigned(BUILDING_FILE) / 1000; $y[$p] = read_unsigned(BUILDING_FILE) / 1000; # for error checking (added 01/25) if ($j > 0 && $x[$p] == $x[$p-1] && $y[$p] == $y[$p-1]) { # find data error!! printf STDERR ("Warning: Duplicated point found in building ID:$id\n"); $p--; # skip it } if ($x[$p] == 0) { printf STDERR ("Warning: One of builing coordinate (x) is zero, ID: $id\n"); } if ($y[$p] == 0) { printf STDERR ("Warning: One of builing coordinate (y) is zero, ID: $id\n"); } } if (($x[0] == $x[$nn-1] && $y[0] == $y[$nn-1]) || $del_last_vertex) { #if ($vverbose) { #printf ("Delete end point\n"); # } $p--; } else { printf STDERR ("Warning: Building ID : $id; poligon is not closed\n"); } # check size $aa = area($nn-1, @x, @y); if ( int($area1f / 100) != int($aa)) { printf STDERR ("Warning; Building ID : $id; area size is not correct\n"); printf STDERR (" %d (in data), %d (calculated) \n", $area1f / 100, $aa ); } # generate shape if ($genobj) { $nn = $p; # make walls for ($j = 0 ; $j < $nn ; $j++) { printf OBJFILE ($vformat, $x[$j],$y[$j],0); } for ($j = 0 ; $j < $nn ; $j++) { printf OBJFILE ($vformat, $x[$j],$y[$j],$height); } for ($j = 0 ; $j < $nn ; $j++) { $nnn = $nn * 2; #printf OBJFILE ("# wall %d\n", $j+1); printf OBJFILE ("f -%d -%d -%d -%d\n", $nnn - $j, ($j == $nn-1) ? $nnn : $nnn - $j - 1, ($j == $nn-1) ? $nn : $nn - $j -1, $nn - $j); } # make ceeling # printf OBJFILE ("# ceeling\n"); printf OBJFILE ("f"); for ($j = $nn ; $j > 0 ; $j--) { printf OBJFILE (" -%d", $j); } printf OBJFILE ("\n"); # make bottom if ($genfloor) { printf OBJFILE ("f"); for ($j = $nn +1; $j <= $nn*2 ; $j++) { printf OBJFILE (" -%d", $j); } printf OBJFILE ("\n"); } # just make some comment if ($comment) { printf OBJFILE ("# %d vertices, %d polygons, (%d floors building)\n\n", $nn * 2, ($genfloor) ? $nn + 2: $nn+ 1, $nfloor); } } # if($genobj) } sub calc_height($) { local $f = shift; if ($f == 0) { # error checking return 0.01; # avoid 0 floor } return $f * 3; # should be more complecated ;-< } sub read_node_record() { # read stuff $size = read_unsigned(NODE_FILE); $id = read_unsigned(NODE_FILE); $pos_x = read_unsigned(NODE_FILE) / 1000; $pos_y = read_unsigned(NODE_FILE) / 1000; $node_x{$id} = $pos_x; $node_y{$id} = $pos_y; $nconnect = read_unsigned(NODE_FILE); for ($j = 0 ; $j < $nconnect ; $j++) { read_unsigned(NODE_FILE); } $has_trafficsignal = read_unsigned(NODE_FILE); for ($j = 0 ; $j < $nconnect ; $j++) { read_unsigned(NODE_FILE); } for ($j = 0 ; $j < $nconnect ; $j++) { read_unsigned(NODE_FILE); read_unsigned(NODE_FILE); } for ($j = 0 ; $j < $nconnect ; $j++) { read_unsigned(NODE_FILE); read_unsigned(NODE_FILE); read_unsigned(NODE_FILE); } } sub read_road_record() { # read stuff $size = read_unsigned(ROAD_FILE); $id = read_unsigned(ROAD_FILE); $start_node = read_unsigned(ROAD_FILE); $end_node = read_unsigned(ROAD_FILE); $length = read_unsigned(ROAD_FILE) / 1000; $kind = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $width = read_unsigned(ROAD_FILE) / 1000; $dummy = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $dummy = read_unsigned(ROAD_FILE); $vformat = "v %6.4f %6.4f %6.4f\n"; $dx = $width * ($node_y{$end_node} - $node_y{$start_node}) / 2 / $length; $dy = $width * ($node_x{$end_node} - $node_x{$start_node}) / 2 / $length; if ($genobj) { printf OBJFILE ("# road ID=$id\n"); # grouping if ($gengroup) { printf OBJFILE ("g r-%05d\n", $id); } # make square printf OBJFILE ($vformat, $node_x{$start_node} - $dx, $node_y{$start_node} + $dy, 0); printf OBJFILE ($vformat, $node_x{$start_node} + $dx, $node_y{$start_node} - $dy, 0); printf OBJFILE ($vformat, $node_x{$end_node} + $dx, $node_y{$end_node} - $dy, 0); printf OBJFILE ($vformat, $node_x{$end_node} - $dx, $node_y{$end_node} + $dy, 0); printf OBJFILE ("f -4 -3 -2 -1\n"); if ($genfloor) { printf OBJFILE ("f -1 -2 -3 -4\n"); # for the other side of road printf OBJFILE ("# 4 vertices, 2 polygon \n\n"); # just make some comment } else { printf OBJFILE ("# 4 vertices, 1 polygon \n\n"); } } } sub read_unsigned($) { my ($f) = shift; read($f, $data, 4); return unpack("L",$data); # CAUTION !! MACHINE DEPENDENT!! } sub read_long($) { my ($f) = shift; read($f, $data, 4); return unpack("l",$data); # CAUTION !! MACHINE DEPENDENT!! } # calculate area size from geometry # 2001/10/22 sub area($\$\$) { my ($n, $x, $y) = @_; my ($i, $s); $s = 0; if ($n % 2 == 0) { # printf("Even\n"); for ($i = 2 ; $i <= $n / 2 ; $i++) { my ($i2) = $i*2; $s += ($x[$i2-2] - $x[0]) * ($y[$i2-1] - $y[$i2-3]) + ($x[$i2-1] - $x[1]) * ($y[$i2] -$y[$i2-2]); } } else { # printf("Odd\n"); for ($i = 2 ; $i <= $n ; $i++) { $s += ($x[$i-1] - $x[0]) * ($y[$i] - $y[$i-2]); } } $s /= 2; # printf("s = %d\n", $s); return $s; } sub usage() { printf("Usage: $0 [-v] [-fobj-filename] building-filename\n"); printf(" -v: verbose mode\n"); printf(" -g: generate group code\n"); printf(" -m: generate material code\n"); printf(" -n: generate floor\n"); printf(" -f: output obj file\n"); printf(" -b: input building file\n"); printf(" -r: input road file\n"); printf(" -n: input node file"); printf(" -c: don't generate obj file (Check only)"); } # 出力形式指定オプションに関するメモ # -g を付けるとグループを生成し名前をつけます。 # ビルディング: b-99999 # 道: r-99999 # # -m を付けるとマテリアルコードをファイルの最初に生成します。 # (テスト用) # 現在はすべてのオブジェクトを同じマテリアルに設定しています。 # # EOF