Click here to Skip to main content
15,867,986 members
Articles / Programming Languages / Perl

Point Inside 3D Convex Polygon in Perl

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
6 Feb 2016CPOL 15.6K   60   3   1
An algorithm to determine if a point is inside a 3D convex polygon for a given polygon vertices in Perl

Introduction

This is a Perl version of the original C++ algorithm which can be found here.

Background

Please refer to the original C++ algorithm here.

Using the Code

The algorithm is wrapped into a Perl module library folder GeoProc. The main test program LASProc reads point cloud data from a LAS file, then writes all inside points into a new LAS file. A LAS file is able to be displayed with a freeware FugroViewer.

To consume the GeoProc module library, prepare a GeoPolygonProc object first like this:

PERL
my $ptsArray = [$p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8];
my $polygon  = new GeoPolygon($ptsArray);
my $procObj  = new GeoPolygonProc($polygon);

Here is how to check if a point is inside the polygon:

PERL
if ($x > $procObj->{x0} && $x < $procObj->{x1} &&
    $y > $procObj->{y0} && $x < $procObj->{y1} &&
    $z > $procObj->{z0} && $x < $procObj->{z1} )
    {
        if ($procObj->PointInside3DPolygon($x, $y, $z))

Here are all GeoProc modules:

Please refer to PHP version for the module explanation and comments.

GeoPoint.pm

PERL
#!/usr/bin/perl

package GeoPoint;

 use strict;
 use warning;

sub new
{
    my $class = shift;
    my $self = {
        x => shift,
        y => shift,
        z => shift,
    };   
    bless $self, $class;
    return $self;
}
    
use overload "+" => \&Add, "-" => \&Subtract;

sub Add
{
    my $p0 = shift;
    my $p1 = shift;
    return new GeoPoint($p0->{x} + $p1->{x}, $p0->{y} + $p1->{y}, $p0->{z} + $p1->{z});
}

sub Subtract
{
    my $p0 = shift;
    my $p1 = shift;
    return new GeoPoint($p0->{x} - $p1->{x}, $p0->{y} - $p1->{y}, $p0->{z} - $p1->{z});
}

1;

GeoVector.pm

PERL
#!/usr/bin/perl

package GeoVector;

 use strict;
 use warnings;

sub new
{
    my $class = shift;
    my $self = {
        p0 => shift,
        p1 => shift,        
    };   
    bless $self, $class;
    return $self;
}

sub getX
{
    my $self = shift;    
    return $self->{p1}->{x} - $self->{p0}->{x};
}

sub getY
{
    my $self = shift;        
    return $self->{p1}->{y} - $self->{p0}->{y};
}

sub getZ
{
    my $self = shift;    
    return $self->{p1}->{z} - $self->{p0}->{z};
}
    
use overload "*" => \&Multiple;

sub Multiple
{
    my $u = shift;
    my $v = shift;        
        
    my $x = $u->getY() * $v->getZ() - $u->getZ() * $v->getY();
    my $y = $u->getZ() * $v->getX() - $u->getX() * $v->getZ();
    my $z = $u->getX() * $v->getY() - $u->getY() * $v->getX();                
        
    my $p0 = $v->{p0};
    my $p1 = $p0 + new GeoPoint($x, $y, $z);
    
    return new GeoVector($p0, $p1);    
}

1;

GeoPlane.pm

PERL
#!/usr/bin/perl

package GeoPlane;

 use strict;
 use warnings;

 use GeoVector;

sub new
{
    my $class = shift;
    my $self = {
        a => shift,
        b => shift,
        c => shift,
        d => shift,
    };   
    bless $self, $class;
    return $self;
}   

# Create a GeoPlane from 3 GeoPoint.
# Static method to simulate constructor overloading.
# Usage: GeoPlane->Create($p0, $p1, $p2);
sub Create
{
    my $self = shift; # current object, GeoPlane

    my $p0 = shift; # parameter 1, GeoPoint
    my $p1 = shift; # parameter 2, GeoPoint
    my $p2 = shift; # parameter 3, GeoPoint        
    
    my $v = new GeoVector($p0, $p1);
    my $u = new GeoVector($p0, $p2);
    my $n = $u * $v;
    
    my $a = $n->getX();
    my $b = $n->getY();
    my $c = $n->getZ();                    
    my $d = -($a * $p0->{x} + $b * $p0->{y} + $c * $p0->{z});

    return new GeoPlane($a, $b, $c, $d);
}
    
use overload "neg" => \&Negative;

# Unary operator '-' overloading
sub Negative
{
    my $self = shift; # current object, GeoPlane
    return new GeoPlane(-$self->{a}, -$self->{b}, -$self->{c}, -$self->{d});    
}

# Instance method to simulate (GeoPlane * GeoPoint)
# Usage: $dis = $pl->Multiple(new GeoPoint($p0, $p1, $p2));
sub Multiple
{
    my $pl = shift; # current object, GeoPlane
    my $pt = shift; # parameter 1, GeoPoint
    return $pt->{x} * $pl->{a} + $pt->{y} * $pl->{b} + $pt->{z} * $pl->{c} + $pl->{d};    
}

1;

GeoPolygon.pm

PERL
#!/usr/bin/perl

package GeoPolygon;

 use strict;
 use warnings;

sub new
{
    my ($class, $pts) = @_;
                
    my $this = {};    
    
    my @pts_ref = @$pts;
    
    $this->{n} = scalar @pts_ref;
    
    $this->{v} = [];
    
    $this->{idx} = [];
            
    for(my $i=0; $i<$this->{n}; $i++)
    {        
        $this->{v}[$i] = $pts_ref[$i];        
        $this->{idx}[$i] = $i;        
    }
    
    bless $this, $class;        
    return $this;
}

1;

GeoFace.pm

PERL
#!/usr/bin/perl

package GeoFace;

 use strict;
 use warnings;

sub new
{
    my ($class, $pts, $ptsIdx) = @_;
                
    my $this = {};    
    
    my @pts_ref = @$pts;
    my @ptsIdx_ref = @$ptsIdx;
    
    $this->{n} = scalar @pts_ref;
    
    $this->{v} = [];
    
    $this->{idx} = [];
            
    for(my $i=0; $i<$this->{n}; $i++)
    {                
        push(@{$this->{v}}, $pts_ref[$i]);
        push(@{$this->{idx}}, $ptsIdx_ref[$i]);    
    }
    
    bless $this, $class;        
    return $this;
}

1;

Utility.pm

PERL
#!/usr/bin/perl

package Utility;

 use strict;
 use warnings;
 use experimental 'smartmatch';

 use constant false => 0;
 use constant true  => 1;

# check if 2D array [[]] arr2d contains 1d array [] arr1d.
sub ContainsArray
{
    my ($this, $arr2d, $arr1d) = @_;
                      
    my @arr2d_ref = @$arr2d;
    my @arr1d_ref = @$arr1d;
    
    my $count = scalar @arr2d_ref;        
    
    my @sortedItem = sort { $a <=> $b } @arr1d_ref;
    
    for (my $i = 0; $i < $count; $i++)
    {    
        my $temp = $arr2d_ref[$i];        
        my @currItem = sort { $a <=> $b } @$temp;                
        if(@currItem ~~ \@sortedItem)
        {            
            return true;
        }        
    }
    
    return false;
}

1;

GeoPolygonProc.pm

PERL
#!/usr/bin/perl

package GeoPolygonProc;

 use strict;
 use warnings;
 use Data::Dumper;

 use constant false => 0;
 use constant true  => 1;

my $MaxUnitMeasureError = 0.001;

sub new
{
    my ($class, $polygon) = @_;
                
    my $this = {};    
                        
    bless $this, $class;    

    $this->{polygon} = $polygon;
    $this->SetBoundary();    
    $this->SetMaxError();
    $this->SetFacePlanes();
    
    return $this;
}

sub SetBoundary
{
    my ($this) = @_;
    
    my $n = $this->{polygon}->{n};

    my $v = $this->{polygon}->{v};
    
    $this->{x0} = @$v[0]->{x};
    $this->{y0} = @$v[0]->{y};
    $this->{z0} = @$v[0]->{z};
    $this->{x1} = @$v[0]->{x};
    $this->{y1} = @$v[0]->{y};
    $this->{z1} = @$v[0]->{z};    
    
    for (my $i = 1; $i < $n; $i++)
    {
        if (@$v[$i]->{x} < $this->{x0}) {$this->{x0} = @$v[$i]->{x};}
        if (@$v[$i]->{y} < $this->{y0}) {$this->{y0} = @$v[$i]->{y};}
        if (@$v[$i]->{z} < $this->{z0}) {$this->{z0} = @$v[$i]->{z};}
        if (@$v[$i]->{x} > $this->{x1}) {$this->{x1} = @$v[$i]->{x};}
        if (@$v[$i]->{y} > $this->{y1}) {$this->{y1} = @$v[$i]->{y};}
        if (@$v[$i]->{z} > $this->{z1}) {$this->{z1} = @$v[$i]->{z};}        
    }       
}

sub SetMaxError
{    
    my ($this) = @_;
    $this->{maxDisError} = (abs($this->{x0}) + abs($this->{x1}) +
                            abs($this->{y0}) + abs($this->{y1}) +
                            abs($this->{z0}) + abs($this->{z1})) / 6 * $MaxUnitMeasureError; 
}

sub SetFacePlanes
{
    my ($this) = @_;
    
    # GeoFace array
    $this->{Faces} = [];

    # GeoPlane array
    $this->{FacePlanes} = [];
        
    $this->{NumberOfFaces} = 0;            
            
    # Polygon vertices array
    my $vertices = $this->{polygon}->{v};

    # number of vertices of polygon    
    my $n = $this->{polygon}->{n};    

    # vertices indexes 2d array for all faces,
    # face index is major dimension, face vertice index is minor dimension
    # vertices index is the original index value in the input polygon
    my @faceVerticeIndex = ();
        
    # face planes for all faces
    my $fpOutward = [];
    
    for(my $i=0; $i< $n; $i++)
    {     
        # triangle point #1
        my $p0 = @$vertices[$i];

        for(my $j= $i+1; $j< $n; $j++)
        {
            # triangle point #2
            my $p1 = @$vertices[$j];

            for(my $k = $j + 1; $k<$n; $k++)
            {            
                # triangle point #3
                my $p2 = @$vertices[$k];

                my $trianglePlane = GeoPlane->Create($p0, $p1, $p2);
            
                my $onLeftCount = 0;
                my $onRightCount = 0;

                # Indexes of points that are in same plane with the face triangle plane
                # Integer array
                my $pointInSamePlaneIndex = [];
    
                for(my $l = 0; $l < $n ; $l++)
                {                
                    # any points other than the 3 triangle points
                    if($l != $i && $l != $j && $l != $k)
                    {
                        my $pt = @$vertices[$l];

                        my $dis = $trianglePlane->Multiple($pt);
                                                
                        # next point is in the triangle plane
                        if(abs($dis) < $this->{maxDisError})
                        {                            
                            push(@$pointInSamePlaneIndex, $l);                                    
                        }
                        else
                        {
                            if($dis < 0)
                            {
                                $onLeftCount++;                                
                            }
                            else
                            {
                                $onRightCount++;
                            }
                        }
                    }
                }
        
                # This is a face for a CONVEX 3d polygon.
                # For a CONCAVE 3d polygon, this maybe not a face.
                if($onLeftCount == 0 || $onRightCount == 0)
                {
                    # Integer array
                    my $verticeIndexInOneFace = [];
                   
                    # triangle plane
                    push(@$verticeIndexInOneFace, $i);
                    push(@$verticeIndexInOneFace, $j);
                    push(@$verticeIndexInOneFace, $k);            
                    
                    my $m = scalar @$pointInSamePlaneIndex;

                    # there are other vertices in this triangle plane
                    if($m > 0)
                    {
                        for(my $p = 0; $p < $m; $p++)
                        {
                            push(@$verticeIndexInOneFace, @$pointInSamePlaneIndex[$p]);
                        }                        
                    }
                    
                    # if verticeIndexInOneFace is a new face,
                    # add it in the faceVerticeIndex list,
                    # add the trianglePlane in the face plane list fpOutward
                    if (!Utility->ContainsArray(\@faceVerticeIndex, $verticeIndexInOneFace))
                    {                    
                        push(@faceVerticeIndex, $verticeIndexInOneFace);

                        if ($onRightCount == 0)
                        {
                            push(@$fpOutward, $trianglePlane);
                        }
                        elsif ($onLeftCount == 0)
                        {
                            push(@$fpOutward, -$trianglePlane);
                        }
                    }
                }
                else
                {                    
                    # possible reasons:
                    # 1. the plane is not a face of a convex 3d polygon,
                    #    it is a plane crossing the convex 3d polygon.
                    # 2. the plane is a face of a concave 3d polygon
                }

            } # k loop
        } # j loop        
    } # i loop                        

    $this->{NumberOfFaces} = scalar @faceVerticeIndex;    
    
    for (my $i = 0; $i < $this->{NumberOfFaces}; $i++)
    {                        
        my $facePlane = new GeoPlane(@$fpOutward[$i]->{a}, @$fpOutward[$i]->{b},
                                     @$fpOutward[$i]->{c}, @$fpOutward[$i]->{d});
                                    
        #set FacePlanes
        push(@{$this->{FacePlanes}}, $facePlane);
        
        #GeoPoint array
        my $v = [];

        #Integer array
        my $idx = [];
        
        my $faceIdx = $faceVerticeIndex[$i];
        my $count = scalar @$faceIdx;
                
        for (my $j = 0; $j < $count; $j++)
        {                        
            push(@$idx, @$faceIdx[$j]);
            my $k = @$idx[$j];
            my $pt = new GeoPoint(@$vertices[$k]->{x}, @$vertices[$k]->{y}, @$vertices[$k]->{z});
            push(@$v, $pt);                                            
        }

        #set Faces
        my $face = new GeoFace($v, $idx);
        push(@{$this->{Faces}}, $face);
    }        
}

# public method to update max error
sub UpdateMaxError
{    
    my ($this, $maxError) = @_;
    $this->{maxDisError} = $maxError;       
}

# public method to check if point is inside 3d polygon
sub PointInside3DPolygon
{
    my ($this, $x, $y, $z) = @_;
    
    my $pt = new GeoPoint($x, $y, $z);
         
    for (my $i = 0; $i < $this->{NumberOfFaces}; $i++)
    {        
        my $pl = $this->{FacePlanes}[$i];
    
        my $dis = $pl->Multiple($pt);

        # If the point is in the same half space with normal vector for any face of the cube,
        # then it is outside of the 3D polygon        
        if ($dis > 0)
        {
            return false;
        }
    }

    # If the point is in the opposite half space with normal vector for all 6 faces,
    # then it is inside of the 3D polygon
    return true;            
}
    
1;

Here is the main test program.

LASProc.pl

PERL
#!/usr/bin/perl

 use strict;
 use warnings;
 use Data::Dumper;
 use Fcntl qw(:seek);    

 use lib '../GeoProc';
 use GeoPoint;
 use GeoVector;
 use GeoPlane;
 use GeoPolygon;
 use GeoFace;
 use Utility;
 use GeoPolygonProc;

# Create GeoPolygonProc object
my $p1 = new GeoPoint( - 27.28046,  37.11775,  - 39.03485);
my $p2 = new GeoPoint( - 44.40014,  38.50727,  - 28.78860);
my $p3 = new GeoPoint( - 49.63065,  20.24757,  - 35.05160);
my $p4 = new GeoPoint( - 32.51096,  18.85805,  - 45.29785);
my $p5 = new GeoPoint( - 23.59142,  10.81737,  - 29.30445);
my $p6 = new GeoPoint( - 18.36091,  29.07707,  - 23.04144);
my $p7 = new GeoPoint( - 35.48060,  30.46659,  - 12.79519);
my $p8 = new GeoPoint( - 40.71110,  12.20689,  - 19.05819);
my $ptsArray = [$p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8];
my $polygon = new GeoPolygon($ptsArray);
my $procObj = new GeoPolygonProc($polygon);

# LAS File Process

my $rb;
my $wb;
my $wt;
my $value;

my $rbFileName = "../LASInput/cube.las";
my $wbFileName = "../LASOutput/cube_inside.las";
my $wtFileName = "../LASOutput/cube_inside.txt";

open($rb, "<", $rbFileName)
  || die "can't open $rbFileName: $!";
binmode($rb);

open($wb, ">", $wbFileName)
  || die "can't open $wbFileName: $!";
binmode($wb);

open($wt, ">", $wtFileName)
  || die "can't open $wtFileName: $!";

# read LAS header info

sysseek($rb, 96, 0);

sysread($rb, $value, 4);
my $offset_to_point_data_value = unpack('I', $value);
sysread($rb, $value, 4);
sysread($rb, $value, 1);
sysread($rb, $value, 2);
my $record_len = unpack('v', $value);
sysread($rb, $value, 4);
my $record_num = unpack('L', $value);

sysseek($rb, 131, 0);

sysread($rb, $value, 8);
my $x_scale = unpack('d', $value);
sysread($rb, $value, 8);
my $y_scale = unpack('d', $value);
sysread($rb, $value, 8);
my $z_scale = unpack('d', $value);
sysread($rb, $value, 8);
my $x_offset = unpack('d', $value);
sysread($rb, $value, 8);
my $y_offset = unpack('d', $value);
sysread($rb, $value, 8);
my $z_offset = unpack('d', $value);

# read LAS header
sysseek($rb, 0, 0);
sysread($rb, $value, $offset_to_point_data_value);

# write LAS header
syswrite($wb, $value);

my $insideCount = 0;

my ($i, $record_loc, $xi, $yi, $zi, $x, $y, $z);

for($i=0; $i<$record_num; $i++)
{                            
    $record_loc = $offset_to_point_data_value + $record_len * $i;
    sysseek($rb, $record_loc, 0);   
    sysread($rb, $value, 4);
    $xi = unpack('l', $value);
    sysread($rb, $value, 4);
    $yi = unpack('l', $value);
    sysread($rb, $value, 4);
    $zi = unpack('l', $value);
    $x = $xi * $x_scale + $x_offset;
    $y = $yi * $y_scale + $y_offset;
    $z = $zi * $z_scale + $z_offset;
    
    if ($x > $procObj->{x0} && $x < $procObj->{x1} &&
        $y > $procObj->{y0} && $x < $procObj->{y1} &&
        $z > $procObj->{z0} && $x < $procObj->{z1} )
    {
        if ($procObj->PointInside3DPolygon($x, $y, $z))
        {
            # read LAS Point record
            sysseek($rb, $record_loc, 0);   
            sysread($rb, $value, $record_len);
            
            # write LAS Point record
            syswrite($wb, $value);
                            
            # write text LAS Point record
            $wt->printf("%15.6f %15.6f %15.6f\n", $x, $y, $z);

            $insideCount++;
        }
    }    
}    

# update record_num in LAS header with actual writing point records number    
sysseek($wb, 107, 0);  
syswrite($wb, pack('I', $insideCount));
    
$rb->close();
$wb->close();
$wt->close();

Here is a module test program for all GeoProc module library functions and usages.

Test.pl

PERL
#!/usr/bin/perl

 use strict;
 use warnings;
 use Data::Dumper;

 use lib '../GeoProc';
 use GeoPoint;
 use GeoVector;
 use GeoPlane;
 use GeoPolygon;
 use GeoFace;
 use Utility;
 use GeoPolygonProc;

my $p1 = new GeoPoint( - 27.28046,  37.11775,  - 39.03485);
my $p2 = new GeoPoint( - 44.40014,  38.50727,  - 28.78860);
my $p3 = new GeoPoint( - 49.63065,  20.24757,  - 35.05160);
my $p4 = new GeoPoint( - 32.51096,  18.85805,  - 45.29785);
my $p5 = new GeoPoint( - 23.59142,  10.81737,  - 29.30445);
my $p6 = new GeoPoint( - 18.36091,  29.07707,  - 23.04144);
my $p7 = new GeoPoint( - 35.48060,  30.46659,  - 12.79519);
my $p8 = new GeoPoint( - 40.71110,  12.20689,  - 19.05819);
my $ptsArray = [$p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8];
my $polygon = new GeoPolygon($ptsArray);

print "GeoPoint Test:\n";
my $pt = $p1 + $p2;
print(Dumper($pt));
print $pt->{x} .",". $pt->{y} .",". $pt->{z} ."\n";

print "GeoVector Test:\n";
my $v1 = new GeoVector($p1, $p2);
my $v2 = new GeoVector($p1, $p3);
my $v3 = $v2 * $v1;
printf("%.3f, %.3f, %.3f\n", $v3->getX(), $v3->getY(), $v3->getZ());

print "GeoPlane Test:\n";
my $pl = GeoPlane->Create($p1, $p2, $p3);
printf("%.3f, %.3f, %.3f, %.3f\n", $pl->{a}, $pl->{b}, $pl->{c}, $pl->{d});
$pl = new GeoPlane(1.0, 2.0, 3.0, 4.0);
printf("%.3f, %.3f, %.3f, %.3f\n", $pl->{a}, $pl->{b}, $pl->{c}, $pl->{d});
$pl = -$pl;
printf("%.3f, %.3f, %.3f, %.3f\n", $pl->{a}, $pl->{b}, $pl->{c}, $pl->{d});
my $dis = $pl->Multiple(new GeoPoint(1.0, 2.0, 3.0));
printf("%.3f\n", $dis);

print "GeoPolygon Test:\n";
for(my $i=0; $i<$polygon->{n}; $i++)
{
    print $polygon->{idx}[$i] .": (". $polygon->{v}[$i]->{x} .", ".
          $polygon->{v}[$i]->{y} .", ". $polygon->{v}[$i]->{z} .")\n";
}

print "GeoFace Test:\n";
my $faceVerticesArray = [$p1, $p2, $p3, $p4];
my $faceVerticeIndexArray = [1, 2, 3, 4];
my $face = new GeoFace($faceVerticesArray, $faceVerticeIndexArray);
for(my $i=0; $i<$face->{n}; $i++)
{
    print $face->{idx}[$i] .": (". $face->{v}[$i]->{x} .", ".
          $face->{v}[$i]->{y} .", ". $face->{v}[$i]->{z} .")\n";
}

print "Utility Test:\n";
my $arr1 = [1, 2, 3, 4];    
my $arr2 = [4, 5, 6, 7];    
my $arr2d = [];
push(@$arr2d, $arr1);
push(@$arr2d, $arr2);
my $arr3 = [2, 3, 1, 4];
my $arr4 = [2, 3, 1, 5];
my $b1 = Utility->ContainsArray($arr2d, $arr3);
my $b2 = Utility->ContainsArray($arr2d, $arr4);
print $b1 .", ". $b2 ."\n";
    
print "GeoPolygonProc Test:\n";
my $procObj = new GeoPolygonProc($polygon);
print $procObj->{x0} .", ". $procObj->{x1} .", ". $procObj->{y0} .", ".
      $procObj->{y1} .", ". $procObj->{z0} .", ". $procObj->{z1} ."\n";
printf("%.6f\n", $procObj->{maxDisError});
$procObj->UpdateMaxError(0.0125);
printf("%.6f\n", $procObj->{maxDisError});
print $procObj->{NumberOfFaces}."\n";
print "Face Planes:\n";
for(my $i=0; $i<$procObj->{NumberOfFaces}; $i++)
{
    my $facePlane = $procObj->{FacePlanes}[$i];
    printf("%d%s\n", $i+1, ": ".$facePlane->{a}.", ".$facePlane->{b}.", ".
                                $facePlane->{c}.", ".$facePlane->{d});
}
print "Faces:\n";
for(my $j=0; $j<$procObj->{NumberOfFaces}; $j++)
{
    printf("%s%d:\n", "Face ", $j + 1);
    my $face = $procObj->{Faces}[$j];            
    for(my $i=0; $i<$face->{n}; $i++)
    {
        printf("%d%s\n", $face->{idx}[$i], ": (". $face->{v}[$i]->{x} .", ".
                         $face->{v}[$i]->{y} .", ". $face->{v}[$i]->{z} .")");    
    }
}
my $insidePoint = new GeoPoint(-28.411750, 25.794500, -37.969000);
my $outsidePoint = new GeoPoint(-28.411750, 25.794500, -50.969000);
$b1 = $procObj->PointInside3DPolygon($insidePoint->{x}, $insidePoint->{y}, $insidePoint->{z});
$b2 = $procObj->PointInside3DPolygon($outsidePoint->{x}, $outsidePoint->{y}, $outsidePoint->{z});
print $b1.", ".$b2;

Here is the output of the module test program:

PERL
GeoPoint Test:
$VAR1 = bless( {
                 'x' => '-71.6806',
                 'z' => '-67.82345',
                 'y' => '75.62502'
               }, 'GeoPoint' );
-71.6806,75.62502,-67.82345
GeoVector Test:
-178.391, 160.814, -319.868
GeoPlane Test:
-178.391, 160.814, -319.868, -23321.631
1.000, 2.000, 3.000, 4.000
-1.000, -2.000, -3.000, -4.000
-18.000
GeoPolygon Test:
0: (-27.28046, 37.11775, -39.03485)
1: (-44.40014, 38.50727, -28.7886)
2: (-49.63065, 20.24757, -35.0516)
3: (-32.51096, 18.85805, -45.29785)
4: (-23.59142, 10.81737, -29.30445)
5: (-18.36091, 29.07707, -23.04144)
6: (-35.4806, 30.46659, -12.79519)
7: (-40.7111, 12.20689, -19.05819)
GeoFace Test:
1: (-27.28046, 37.11775, -39.03485)
2: (-44.40014, 38.50727, -28.7886)
3: (-49.63065, 20.24757, -35.0516)
4: (-32.51096, 18.85805, -45.29785)
Utility Test:
1, 0
GeoPolygonProc Test:
-49.63065, -18.36091, 10.81737, 38.50727, -45.29785, -12.79519
0.029235
0.012500
6
Face Planes:
1: -178.390887365, 160.8136689275, -319.8681191512, -23321.6310778083
2: 104.6099805132, 365.1940004963, 125.2599754664, -5811.8668695958
3: 342.39346482, -27.7903996799999, -204.924901278, 2372.9555463542
4: -342.393647417, 27.7906119191, 204.9249816848, -10372.9631493284
5: -104.609966618, -365.193886771, -125.2600697684, -2188.13771525579
6: 178.3908734698, -160.8139027544, 319.8683017482, 15321.6421625963
Faces:
Face 1:
0: (-27.28046, 37.11775, -39.03485)
1: (-44.40014, 38.50727, -28.7886)
2: (-49.63065, 20.24757, -35.0516)
3: (-32.51096, 18.85805, -45.29785)
Face 2:
0: (-27.28046, 37.11775, -39.03485)
1: (-44.40014, 38.50727, -28.7886)
5: (-18.36091, 29.07707, -23.04144)
6: (-35.4806, 30.46659, -12.79519)
Face 3:
0: (-27.28046, 37.11775, -39.03485)
3: (-32.51096, 18.85805, -45.29785)
4: (-23.59142, 10.81737, -29.30445)
5: (-18.36091, 29.07707, -23.04144)
Face 4:
1: (-44.40014, 38.50727, -28.7886)
2: (-49.63065, 20.24757, -35.0516)
6: (-35.4806, 30.46659, -12.79519)
7: (-40.7111, 12.20689, -19.05819)
Face 5:
2: (-49.63065, 20.24757, -35.0516)
3: (-32.51096, 18.85805, -45.29785)
4: (-23.59142, 10.81737, -29.30445)
7: (-40.7111, 12.20689, -19.05819)
Face 6:
4: (-23.59142, 10.81737, -29.30445)
5: (-18.36091, 29.07707, -23.04144)
6: (-35.4806, 30.46659, -12.79519)
7: (-40.7111, 12.20689, -19.05819)
1, 0

Points of Interest

TMTOWTDI means "There's more than one way to do it" according to Wall.

History

  • February 06, 2016: Initial date

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Canada Canada
My name is Jiyang Hou (or John Hou). I was born in HeiLongJiang province in north east of China. I got all my educations in China. My university major is Geophysics, but my main professional role is software developer. My biggest accomplishment so far is quit smoking about 5 years ago after almost 20 years smoking history. I am still interested on programming beside making living with it like many other developers. I immigrated to Canada in 2003 and became a permanent resident till now. I live in Calgary, Alberta, Canada. You can reach me by jyhou69@gmail.com regarding to any questions, comments, advice, etc.

Comments and Discussions

 
QuestionHave you considered to post this as a tip? Pin
Nelek7-Feb-16 23:31
protectorNelek7-Feb-16 23:31 
I think it would fit better that category. For more information about the types please read:
Code Project Article FAQ - Article[^]
Code Project Article FAQ - Tip[^]

If you need information about how to change your submission to a tip, please read:
Code Project Article FAQ - change to tip[^]
M.D.V. Wink | ;)

If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.