File Coverage

blib/lib/Vector/Object3D/Point.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Vector::Object3D::Point;
2              
3             =head1 NAME
4              
5             Vector::Object3D::Point - Three-dimensional point object definitions and operations
6              
7             =head2 SYNOPSIS
8              
9             use Vector::Object3D::Point;
10              
11             use Readonly;
12             Readonly my $pi => 3.14159;
13              
14             # Create an instance of a class:
15             my $point = Vector::Object3D::Point->new(x => 3, y => -2, z => 1);
16             my $point = Vector::Object3D::Point->new(coord => [-2, 2, 1]);
17              
18             # Create a new object as a copy of an existing object:
19             my $copy = $point->copy;
20              
21             # Get current X coordinate value:
22             my $x = $point->get_x;
23             # Get current Y coordinate value:
24             my $y = $point->get_y;
25             # Get current Z coordinate value:
26             my $z = $point->get_z;
27              
28             # Get current coordinate values on two-dimensional plane:
29             my ($x, $y) = $point->get_xy;
30             # Get current coordinate values in three-dimensional space:
31             my ($x, $y, $z) = $point->get_xyz;
32              
33             # Get current coordinates as a matrix object:
34             my $pointMatrix = $point->get_matrix;
35              
36             # Set new X coordinate value:
37             $point->set_x($x);
38             # Set new Y coordinate value:
39             $point->set_y($y);
40             # Set new Z coordinate value:
41             $point->set_z($z);
42              
43             # Set new precision value (which is used while printing out data and comparing
44             # the point object with others):
45             my $precision = 2;
46             $point->set(parameter => 'precision', value => $precision);
47              
48             # Get currently used precision value (undef indicates maximum possible precision
49             # which is designated to the Perl core):
50             my $precision = $point->get(parameter => 'precision');
51              
52             # Print out formatted point data:
53             $point->print(fh => $fh, precision => $precision);
54              
55             # Move point a constant distance in a specified direction:
56             my $point_translated = $point->translate(
57             shift_x => -2,
58             shift_y => 1,
59             shift_z => 3,
60             );
61              
62             # Enlarge, shrink or stretch point by a scale factor:
63             my $point_scaled = $point->scale(
64             scale_x => 2,
65             scale_y => 2,
66             scale_z => 3,
67             );
68              
69             # Rotate point by a given angle around three rotation axis:
70             my $point_rotated = $point->rotate(
71             rotate_xy => 30 * ($pi / 180),
72             rotate_yz => -30 * ($pi / 180),
73             rotate_xz => 45 * ($pi / 180),
74             );
75              
76             # Project point onto a two-dimensional plane using an orthographic projection:
77             my $point2D = $point->cast(type => 'parallel');
78              
79             # Project point onto a two-dimensional plane using a perspective projection:
80             my $point2D = $point->cast(type => 'perspective', distance => 5);
81              
82             # Compare two point objects:
83             my $are_the_same = $point1 == $point2;
84              
85             =head1 DESCRIPTION
86              
87             C<Vector::Object3D::Point> describes point object in a three-dimensional space, providing basic operations to manipulate, transform and cast its coordinates.
88              
89             =head1 METHODS
90              
91             =head2 new
92              
93             Create an instance of a C<Vector::Object3D::Point> class:
94              
95             my $point = Vector::Object3D::Point->new(x => 3, y => -2, z => 1);
96             my $point = Vector::Object3D::Point->new(coord => [-2, 2, 1]);
97              
98             There are two individual means of C<Vector::Object3D::Point> object construction, provided a hash of individual components or a list of coordinates. When present, C<coord> constructor parameter takes precedence over individual coordinates in case both values are provided at the same time.
99              
100             =cut
101              
102             our $VERSION = '0.01';
103              
104 3     3   111682 use strict;
  3         6  
  3         110  
105 3     3   15 use warnings;
  3         4  
  3         81  
106              
107 3     3   1294 use Moose;
  0            
  0            
108             with 'Vector::Object3D::Parameters';
109             with 'Vector::Object3D::Point::Cast';
110             with 'Vector::Object3D::Point::Transform';
111              
112             use Vector::Object3D::Matrix;
113              
114             use overload
115             '==' => \&_comparison,
116             '!=' => \&_negative_comparison;
117              
118             has 'x' => (
119             is => 'rw',
120             isa => 'Num',
121             reader => 'get_x',
122             required => 1,
123             writer => 'set_x',
124             );
125              
126             has 'y' => (
127             default => undef,
128             is => 'rw',
129             isa => 'Maybe[Num]',
130             reader => 'get_y',
131             required => 0,
132             writer => 'set_y',
133             );
134              
135             has 'z' => (
136             default => undef,
137             is => 'rw',
138             isa => 'Maybe[Num]',
139             reader => 'get_z',
140             required => 0,
141             writer => 'set_z',
142             );
143              
144             sub build_default_parameter_values {
145             my %parameter_values = (
146             precision => undef,
147             );
148              
149             return \%parameter_values;
150             }
151              
152             around BUILDARGS => sub {
153             my ($orig, $class, %args) = @_;
154              
155             my $coord = $args{coord};
156              
157             if (defined $coord and ref $coord eq 'ARRAY') {
158             my @fields = @{$coord} == 2 ? qw(x y) : qw(x y z);
159             @args{@fields} = @{$coord};
160             }
161              
162             return $class->$orig(%args);
163             };
164              
165             =head2 copy
166              
167             Create a new C<Vector::Object3D::Point> object as a copy of an existing object:
168              
169             my $copy = $point->copy;
170              
171             =cut
172              
173             sub copy {
174             my ($self) = @_;
175              
176             my @coord = $self->get_xyz;
177              
178             my $class = $self->meta->name;
179             my $copy = $class->new(coord => \@coord);
180              
181             my %parameter_values = $self->get_parameter_values;
182              
183             while (my ($param, $value) = each %parameter_values) {
184             $copy->set(parameter => $param, value => $value);
185             }
186              
187             return $copy;
188             }
189              
190             =head2 get_x
191              
192             Get current X coordinate value:
193              
194             my $x = $point->get_x;
195              
196             =head2 get_y
197              
198             Get current Y coordinate value:
199              
200             my $y = $point->get_y;
201              
202             =head2 get_z
203              
204             Get current Z coordinate value:
205              
206             my $z = $point->get_z;
207              
208             =head2 get_xy
209              
210             Get current coordinate values on two-dimensional plane:
211              
212             my ($x, $y) = $point->get_xy;
213              
214             Note these values are not casted, they are the actual coordinate values that were used to initialize an object. See description of the C<cast> method for details about point projection onto a two-dimensional plane.
215              
216             =cut
217              
218             sub get_xy {
219             my ($self) = @_;
220              
221             my $x = $self->get_x;
222             my $y = $self->get_y;
223              
224             return ($x, $y);
225             }
226              
227             =head2 get_xyz
228              
229             Get current coordinate values in three-dimensional space:
230              
231             my ($x, $y, $z) = $point->get_xyz;
232              
233             =cut
234              
235             sub get_xyz {
236             my ($self) = @_;
237              
238             my $x = $self->get_x;
239             my $y = $self->get_y;
240             my $z = $self->get_z;
241              
242             return ($x, $y, $z);
243             }
244              
245             =head2 get_matrix
246              
247             Get current coordinates as a matrix object:
248              
249             my $pointMatrix = $point->get_matrix;
250              
251             =cut
252              
253             sub get_matrix {
254             my ($self) = @_;
255              
256             my @xyz = defined $self->get_z ? $self->get_xyz : $self->get_xy;
257              
258             my $pointMatrix = Vector::Object3D::Matrix->new(rows => [[ @xyz ]]);
259              
260             return $pointMatrix;
261             }
262              
263             =head2 set_x
264              
265             Set new X coordinate value:
266              
267             $point->set_x($x);
268              
269             =head2 set_y
270              
271             Set new Y coordinate value:
272              
273             $point->set_y($y);
274              
275             =head2 set_z
276              
277             Set new Z coordinate value:
278              
279             $point->set_z($z);
280              
281             =head2 set
282              
283             Set new precision value (which is used while comparing point objects with each other):
284              
285             my $precision = 2;
286             $point->set(parameter => 'precision', value => $precision);
287              
288             =head2 get
289              
290             Get currently used precision value (undef indicates maximum possible precision which is designated to the Perl core):
291              
292             my $precision = $point->get(parameter => 'precision');
293              
294             =head2 print
295              
296             Print out text-formatted point data (which might be, for instance, useful for debugging purposes):
297              
298             $point->print(fh => $fh, precision => $precision);
299              
300             C<fh> defaults to the standard output. C<precision> is intended for internal use by string format specifier that outputs individual point coordinates as decimal floating points, and defaults to 2.
301              
302             =cut
303              
304             sub print {
305             my ($self, %args) = @_;
306              
307             my $pointMatrix = $self->get_matrix;
308             $pointMatrix->print(%args);
309              
310             return;
311             }
312              
313             =head2 rotate
314              
315             Rotate point by a given angle around three rotation axis:
316              
317             my $point_rotated = $point->rotate(
318             rotate_xy => 30 * ($pi / 180),
319             rotate_yz => -30 * ($pi / 180),
320             rotate_xz => 45 * ($pi / 180),
321             );
322              
323             =head2 scale
324              
325             Enlarge, shrink or stretch point by a scale factor:
326              
327             my $point_scaled = $point->scale(
328             scale_x => 2,
329             scale_y => 2,
330             scale_z => 3,
331             );
332              
333             Non-uniform scaling (anisotropic scaling), obtained when at least one of the scaling factors is different from the others, is allowed.
334              
335             =head2 translate
336              
337             Move point a constant distance in a specified direction:
338              
339             my $point_translated = $point->translate(
340             shift_x => -2,
341             shift_y => 1,
342             shift_z => 3,
343             );
344              
345             =head2 cast
346              
347             Project point onto a two-dimensional plane using an orthographic projection:
348              
349             my $point2D = $point->cast(type => 'parallel');
350              
351             Project point onto a two-dimensional plane using a perspective projection:
352              
353             my $point2D = $point->cast(type => 'perspective', distance => 5);
354              
355             =head2 compare (==)
356              
357             Compare two point objects:
358              
359             my $are_the_same = $point1 == $point2;
360              
361             Overloaded comparison operator evaluates to true whenever two point objects are identical (all their coordinates are exactly the same).
362              
363             =cut
364              
365             sub _comparison {
366             my ($self, $arg) = @_;
367              
368             # Get compare precision for both points:
369             my $precision1 = $self->get(parameter => 'precision');
370             $precision1 = defined $precision1 ? '.' . $precision1 : '';
371             my $precision2 = $arg->get(parameter => 'precision');
372             $precision2 = defined $precision2 ? '.' . $precision2 : '';
373              
374             my @coordinates1 = $self->get_xyz;
375             my @coordinates2 = $arg->get_xyz;
376              
377             for (my $i = 0; $i < @coordinates1; $i++) {
378             my $coordinate_value = $coordinates1[$i] || 0;
379             my $val1 = sprintf qq{%${precision1}f}, $coordinate_value;
380             $val1 =~ s/^(.*\..*?)0*$/$1/;
381             $val1 =~ s/\.$//;
382              
383             $coordinate_value = $coordinates2[$i] || 0;
384             my $val2 = sprintf qq{%${precision2}f}, $coordinate_value;
385             $val2 =~ s/^(.*\..*?)0*$/$1/;
386             $val2 =~ s/\.$//;
387              
388             return 0 if $val1 ne $val2;
389             }
390              
391             return 1;
392             }
393              
394             =head2 negative compare (!=)
395              
396             Compare two point objects:
397              
398             my $are_not_the_same = $point1 != $point2;
399              
400             Overloaded negative comparison operator evaluates to true whenever two point objects differ (any of their coordinates do not match).
401              
402             =cut
403              
404             sub _negative_comparison {
405             my ($self, $arg) = @_;
406              
407             return not $self->_comparison($arg);
408             }
409              
410             =head1 BUGS
411              
412             There are no known bugs at the moment. Please report any bugs or feature requests.
413              
414             =head1 EXPORT
415              
416             C<Vector::Object3D::Point> exports nothing neither by default nor explicitly.
417              
418             =head1 SEE ALSO
419              
420             L<Vector::Object3D>, L<Vector::Object3D::Line>, L<Vector::Object3D::Parameters>, L<Vector::Object3D::Point::Cast>, L<Vector::Object3D::Point::Transform>, L<Vector::Object3D::Polygon>.
421              
422             =head1 AUTHOR
423              
424             Pawel Krol, E<lt>pawelkrol@cpan.orgE<gt>.
425              
426             =head1 VERSION
427              
428             Version 0.01 (2012-12-24)
429              
430             =head1 COPYRIGHT AND LICENSE
431              
432             Copyright (C) 2012 by Pawel Krol.
433              
434             This library is free open source software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.
435              
436             PLEASE NOTE THAT IT COMES WITHOUT A WARRANTY OF ANY KIND!
437              
438             =cut
439              
440             no Moose;
441             __PACKAGE__->meta->make_immutable;
442              
443             1;