#!/usr/bin/perl
use feature
qw{say current_sub
};
sub permutation {
sub {
my ($le, $pv, @ri) = @_;
defined $pv ? map {[$pv, @$_]} __SUB__
->([], @$le, @ri) : ([]) , @ri ? __SUB__->([@$le, $pv], @ri) : ()
}->([], @_);
}
@vttab = permutation(0..3);
push @{$vttab[$_]}, @{$vttab[$_]}[0,1] for 0..$#vttab; # ring overlap
sub norm2d {
my ($x, $y) = @_;
}
use Math
::Trig qw{asin asin_real rad2deg
}; sub sigangvv { # Signed angle between two vectors
my ($x1, $y1, $x2, $y2) = @_;
sub normalize2d {
my ($x, $y) = @_;
$norm = norm2d($x, $y);
($x / $norm, $y / $norm);
}
sub vprod2d {
my ($x1, $y1, $x2, $y2) = @_;
($x1 * $y2) - ($y1 * $x2);
}
$vprod = vprod2d(normalize2d($x1, $y1), normalize2d($x2, $y2));
$sigang = rad2deg(asin_real($vprod)); # -90..0..+90
}
use constant EPS => 0.0001;
for (<DATA>) {
for $vtlst (@vttab) {
my @angles = ();
for $ie (0..3) {
my ($v1, $v2, $v3) = @{$vtlst}[$ie, $ie+1, $ie+2];
my $x1 = $xys[$v2][0] - $xys[$v1][0];
my $y1 = $xys[$v2][1] - $xys[$v1][1];
my $x2 = $xys[$v3][0] - $xys[$v2][0];
my $y2 = $xys[$v3][1] - $xys[$v2][1];
if (norm2d($x1, $y1) < EPS) {
#warn "skip too short vector(1): $v2 - $v1 => ($x1, $y1)\n";
next;
}
if (norm2d($x2, $y2) < EPS) {
#warn "skip too short vector(2): $v3 - $v2 => ($x2, $y2)\n";
next;
}
my $sigang = sigangvv($x1, $y1, $x2, $y2);
if (abs($sigang) < EPS
) { #warn "skip too thin angle: ($x1, $y1)..($x2, $y2)\n";
next;
}
}
use List::Util 'sum';
my $angsum = sum @angles;
if (abs(abs($angsum) - 360.0) < EPS
) { say "$_ : true";
}
}
say "$_ : false";
L1:;
}
__DATA__
[0, 0], [1, 0], [1, 1], [0, 1]
[0, 0], [1, 1], [1, 0], [0, 1]
[0, 0], [2, 0], [1, 1], [0, 2]
[0, 0], [1, 1], [2, 2], [3, 3]
[0, 0], [0, 0], [0, 0], [0, 0]
IyEvdXNyL2Jpbi9wZXJsCnVzZSBmZWF0dXJlIHF3e3NheSBjdXJyZW50X3N1Yn07CgpzdWIgcGVybXV0YXRpb24gewogIHN1YiB7CiAgICBteSAoJGxlLCAkcHYsIEByaSkgPSBAXzsKICAgIGRlZmluZWQgJHB2ID8gbWFwIHtbJHB2LCBAJF9dfSBfX1NVQl9fLT4oW10sIEAkbGUsIEByaSkgOiAoW10pCiAgICAgICwgQHJpID8gX19TVUJfXy0+KFtAJGxlLCAkcHZdLCBAcmkpIDogKCkKICAgIH0tPihbXSwgQF8pOwp9CkB2dHRhYiA9IHBlcm11dGF0aW9uKDAuLjMpOwpwdXNoIEB7JHZ0dGFiWyRfXX0sIEB7JHZ0dGFiWyRfXX1bMCwxXSBmb3IgMC4uJCN2dHRhYjsgIyByaW5nIG92ZXJsYXAKCnN1YiBub3JtMmQgewogIG15ICgkeCwgJHkpID0gQF87CiAgc3FydCgkeCoqMiArICR5KioyKTsKfQoKdXNlIE1hdGg6OlRyaWcgcXd7YXNpbiBhc2luX3JlYWwgcmFkMmRlZ307CnN1YiBzaWdhbmd2diB7ICMgU2lnbmVkIGFuZ2xlIGJldHdlZW4gdHdvIHZlY3RvcnMKICAgIG15ICgkeDEsICR5MSwgJHgyLCAkeTIpID0gQF87CiAgICBzdWIgbm9ybWFsaXplMmQgewogICAgICBteSAoJHgsICR5KSA9IEBfOwogICAgICAkbm9ybSA9IG5vcm0yZCgkeCwgJHkpOwogICAgICAoJHggLyAkbm9ybSwgJHkgLyAkbm9ybSk7CiAgICB9CiAgICBzdWIgdnByb2QyZCB7CiAgICAgIG15ICgkeDEsICR5MSwgJHgyLCAkeTIpID0gQF87CiAgICAgICgkeDEgKiAkeTIpIC0gKCR5MSAqICR4Mik7CiAgICB9CiAgICAkdnByb2QgPSB2cHJvZDJkKG5vcm1hbGl6ZTJkKCR4MSwgJHkxKSwgbm9ybWFsaXplMmQoJHgyLCAkeTIpKTsKICAgICRzaWdhbmcgPSByYWQyZGVnKGFzaW5fcmVhbCgkdnByb2QpKTsgIyAtOTAuLjAuLis5MAp9Cgp1c2UgY29uc3RhbnQgRVBTID0+IDAuMDAwMTsKCmZvciAoPERBVEE+KSB7CiAgY2hvbXA7CiAgbXkgQHh5cyA9IGV2YWwgIigkXykiOwoKICBmb3IgJHZ0bHN0IChAdnR0YWIpIHsKICAgIG15IEBhbmdsZXMgPSAoKTsKICAgIGZvciAkaWUgKDAuLjMpIHsKICAgICAgbXkgKCR2MSwgJHYyLCAkdjMpID0gQHskdnRsc3R9WyRpZSwgJGllKzEsICRpZSsyXTsKICAgICAgbXkgJHgxID0gJHh5c1skdjJdWzBdIC0gJHh5c1skdjFdWzBdOwogICAgICBteSAkeTEgPSAkeHlzWyR2Ml1bMV0gLSAkeHlzWyR2MV1bMV07CiAgICAgIG15ICR4MiA9ICR4eXNbJHYzXVswXSAtICR4eXNbJHYyXVswXTsKICAgICAgbXkgJHkyID0gJHh5c1skdjNdWzFdIC0gJHh5c1skdjJdWzFdOwogICAgICBpZiAobm9ybTJkKCR4MSwgJHkxKSA8IEVQUykgewoJI3dhcm4gInNraXAgdG9vIHNob3J0IHZlY3RvcigxKTogJHYyIC0gJHYxID0+ICgkeDEsICR5MSlcbiI7CgluZXh0OwogICAgICB9CiAgICAgIGlmIChub3JtMmQoJHgyLCAkeTIpIDwgRVBTKSB7Cgkjd2FybiAic2tpcCB0b28gc2hvcnQgdmVjdG9yKDIpOiAkdjMgLSAkdjIgPT4gKCR4MiwgJHkyKVxuIjsKCW5leHQ7CiAgICAgIH0KICAgICAgbXkgJHNpZ2FuZyA9IHNpZ2FuZ3Z2KCR4MSwgJHkxLCAkeDIsICR5Mik7CiAgICAgIGlmIChhYnMoJHNpZ2FuZykgPCBFUFMpIHsKCSN3YXJuICJza2lwIHRvbyB0aGluIGFuZ2xlOiAoJHgxLCAkeTEpLi4oJHgyLCAkeTIpXG4iOwoJbmV4dDsKICAgICAgfQogICAgICBwdXNoIEBhbmdsZXMsICRzaWdhbmc7CiAgICB9CiAgICB1c2UgTGlzdDo6VXRpbCAnc3VtJzsKICAgIG15ICRhbmdzdW0gPSBzdW0gQGFuZ2xlczsKICAgIGlmIChhYnMoYWJzKCRhbmdzdW0pIC0gMzYwLjApIDwgRVBTKSB7CiAgICAgIHNheSAiJF8gOiB0cnVlIjsKICAgICAgZ290byBMMTsKICAgIH0KICB9CiAgc2F5ICIkXyA6IGZhbHNlIjsKIEwxOjsKfQpfX0RBVEFfXwpbMCwgMF0sIFsxLCAwXSwgWzEsIDFdLCBbMCwgMV0KWzAsIDBdLCBbMSwgMV0sIFsxLCAwXSwgWzAsIDFdClswLCAwXSwgWzIsIDBdLCBbMSwgMV0sIFswLCAyXQpbMCwgMF0sIFsxLCAxXSwgWzIsIDJdLCBbMywgM10KWzAsIDBdLCBbMCwgMF0sIFswLCAwXSwgWzAsIDBd