| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# Copyright 2010, 2011, 2012, 2013 Kevin Ryde |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# This file is part of Image-Base-X11-Protocol. |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# Image-Base-X11-Protocol is free software; you can redistribute it and/or |
|
6
|
|
|
|
|
|
|
# modify it under the terms of the GNU General Public License as published |
|
7
|
|
|
|
|
|
|
# by the Free Software Foundation; either version 3, or (at your option) any |
|
8
|
|
|
|
|
|
|
# later version. |
|
9
|
|
|
|
|
|
|
# |
|
10
|
|
|
|
|
|
|
# Image-Base-X11-Protocol is distributed in the hope that it will be useful, |
|
11
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
13
|
|
|
|
|
|
|
# Public License for more details. |
|
14
|
|
|
|
|
|
|
# |
|
15
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License along |
|
16
|
|
|
|
|
|
|
# with Image-Base-X11-Protocol. If not, see . |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# /usr/share/doc/x11proto-core-dev/x11protocol.txt.gz |
|
20
|
|
|
|
|
|
|
# |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
package Image::Base::X11::Protocol::Drawable; |
|
23
|
3
|
|
|
3
|
|
2842
|
use 5.004; |
|
|
3
|
|
|
|
|
10
|
|
|
|
3
|
|
|
|
|
157
|
|
|
24
|
3
|
|
|
3
|
|
17
|
use strict; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
99
|
|
|
25
|
3
|
|
|
3
|
|
31
|
use Carp; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
253
|
|
|
26
|
3
|
|
|
3
|
|
2886
|
use POSIX 'floor'; |
|
|
3
|
|
|
|
|
24181
|
|
|
|
3
|
|
|
|
|
19
|
|
|
27
|
3
|
|
|
3
|
|
7759
|
use X11::Protocol 0.56; # version 0.56 for robust_req() fix |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
use X11::Protocol::Other 3; # v.3 for hexstr_to_rgb() |
|
29
|
|
|
|
|
|
|
use vars '@ISA', '$VERSION'; |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
use Image::Base; |
|
32
|
|
|
|
|
|
|
@ISA = ('Image::Base'); |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
$VERSION = 14; |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# uncomment this to run the ### lines |
|
37
|
|
|
|
|
|
|
# use Smart::Comments '###'; |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub new { |
|
40
|
|
|
|
|
|
|
my $class = shift; |
|
41
|
|
|
|
|
|
|
if (ref $class) { |
|
42
|
|
|
|
|
|
|
croak "Cannot clone base drawable"; |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
return bless { |
|
45
|
|
|
|
|
|
|
# these not documented as yet |
|
46
|
|
|
|
|
|
|
-colour_to_pixel => { }, |
|
47
|
|
|
|
|
|
|
-gc_colour => '', |
|
48
|
|
|
|
|
|
|
-gc_pixel => -1, |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
@_ }, $class; |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# This not working yet. Good to CopyArea when screen,depth,colormap permit, |
|
54
|
|
|
|
|
|
|
# is it worth the trouble though? |
|
55
|
|
|
|
|
|
|
# |
|
56
|
|
|
|
|
|
|
# =item C<$new_image = $image-Enew_from_image ($class, key=Evalue,...)> |
|
57
|
|
|
|
|
|
|
# |
|
58
|
|
|
|
|
|
|
# Create and return a new image of type C<$class>. |
|
59
|
|
|
|
|
|
|
# |
|
60
|
|
|
|
|
|
|
# Target class C is recognised and done by |
|
61
|
|
|
|
|
|
|
# CopyArea of the C<$image> drawable into the new pixmap. Other classes are |
|
62
|
|
|
|
|
|
|
# left to the plain C C. |
|
63
|
|
|
|
|
|
|
# |
|
64
|
|
|
|
|
|
|
# sub new_from_image { |
|
65
|
|
|
|
|
|
|
# my $self = shift; |
|
66
|
|
|
|
|
|
|
# my $new_class = shift; |
|
67
|
|
|
|
|
|
|
# |
|
68
|
|
|
|
|
|
|
# if (! ref $new_class |
|
69
|
|
|
|
|
|
|
# && $new_class->isa('Image::Base::X11::Protocol::Pixmap')) { |
|
70
|
|
|
|
|
|
|
# my %param = @_; |
|
71
|
|
|
|
|
|
|
# my $X = $self->{'-X'}; |
|
72
|
|
|
|
|
|
|
# if ($param{'-X'} == $X) { |
|
73
|
|
|
|
|
|
|
# my ($depth, $width, $height, $colormap) |
|
74
|
|
|
|
|
|
|
# = $self->get('-screen','-depth','-width','-height'); |
|
75
|
|
|
|
|
|
|
# my ($new_screen, $new_depth) |
|
76
|
|
|
|
|
|
|
# = $new_class->_new_params_screen_and_depth(\%params); |
|
77
|
|
|
|
|
|
|
# if ($new_screen == $screen |
|
78
|
|
|
|
|
|
|
# && $new_depth == $depth |
|
79
|
|
|
|
|
|
|
# && $new_colormap == $colormap) { |
|
80
|
|
|
|
|
|
|
# |
|
81
|
|
|
|
|
|
|
# my $new_image = $new_class->new (%param); |
|
82
|
|
|
|
|
|
|
# |
|
83
|
|
|
|
|
|
|
# ### copy to new Pixmap |
|
84
|
|
|
|
|
|
|
# my ($width, $height) = $self->get('-width','-height'); |
|
85
|
|
|
|
|
|
|
# my ($new_width, $new_height) = $new_image->get('-width','-height'); |
|
86
|
|
|
|
|
|
|
# $X->CopyArea ($self->{'-drawable'}, # src |
|
87
|
|
|
|
|
|
|
# $new_image->{'-drawable'}, # dst |
|
88
|
|
|
|
|
|
|
# _gc_created($self), |
|
89
|
|
|
|
|
|
|
# 0,0, # src x,y |
|
90
|
|
|
|
|
|
|
# min ($width,$new_width), min ($height,$new_height) |
|
91
|
|
|
|
|
|
|
# 0,0); # dst x,y |
|
92
|
|
|
|
|
|
|
# return $new_image; |
|
93
|
|
|
|
|
|
|
# } |
|
94
|
|
|
|
|
|
|
# } |
|
95
|
|
|
|
|
|
|
# } |
|
96
|
|
|
|
|
|
|
# return $self->SUPER::new_from_image ($new_class, @_); |
|
97
|
|
|
|
|
|
|
# } |
|
98
|
|
|
|
|
|
|
# sub _gc_created { |
|
99
|
|
|
|
|
|
|
# my ($self) = @_; |
|
100
|
|
|
|
|
|
|
# return ($self->{'-gc_created'} ||= do { |
|
101
|
|
|
|
|
|
|
# my $gc = $self->{'-X'}->new_rsrc; |
|
102
|
|
|
|
|
|
|
# ### CreateGC: $gc |
|
103
|
|
|
|
|
|
|
# $self->{'-X'}->CreateGC ($gc, $self->{'-drawable'}); |
|
104
|
|
|
|
|
|
|
# $gc |
|
105
|
|
|
|
|
|
|
# }); |
|
106
|
|
|
|
|
|
|
# } |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub DESTROY { |
|
109
|
|
|
|
|
|
|
my ($self) = @_; |
|
110
|
|
|
|
|
|
|
### X11-Protocol-Drawable DESTROY |
|
111
|
|
|
|
|
|
|
_free_gc_created ($self); |
|
112
|
|
|
|
|
|
|
shift->SUPER::DESTROY (@_); |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
sub _free_gc_created { |
|
115
|
|
|
|
|
|
|
my ($self) = @_; |
|
116
|
|
|
|
|
|
|
if (my $gc = delete $self->{'-gc_created'}) { |
|
117
|
|
|
|
|
|
|
### FreeGC: $gc |
|
118
|
|
|
|
|
|
|
$self->{'-X'}->FreeGC ($gc); |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub get { |
|
123
|
|
|
|
|
|
|
my ($self) = @_; |
|
124
|
|
|
|
|
|
|
local $self->{'_during_get'} = {}; |
|
125
|
|
|
|
|
|
|
return shift->SUPER::get(@_); |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
my %get_geometry = (-depth => sub{$_[1]->{'root_depth'}}, |
|
128
|
|
|
|
|
|
|
-root => sub{$_[1]->{'root'}}, |
|
129
|
|
|
|
|
|
|
-x => sub{0}, |
|
130
|
|
|
|
|
|
|
-y => sub{0}, |
|
131
|
|
|
|
|
|
|
-width => sub{$_[1]->{'width_in_pixels'}}, |
|
132
|
|
|
|
|
|
|
-height => sub{$_[1]->{'height_in_pixels'}}, |
|
133
|
|
|
|
|
|
|
-border_width => sub{0}, |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# and with extra crunching |
|
136
|
|
|
|
|
|
|
-screen => sub{$_[0]}); |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub _get { |
|
139
|
|
|
|
|
|
|
my ($self, $key) = @_; |
|
140
|
|
|
|
|
|
|
### X11-Protocol-Drawable _get(): $key |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
if (! exists $self->{$key} |
|
143
|
|
|
|
|
|
|
&& defined (my $rsubr = $get_geometry{$key})) { |
|
144
|
|
|
|
|
|
|
my $X = $self->{'-X'}; |
|
145
|
|
|
|
|
|
|
my $drawable = $self->{'-drawable'}; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
if (defined (my $screen = X11::Protocol::Other::root_to_screen ($X, $drawable))) { |
|
148
|
|
|
|
|
|
|
# $drawable is a root window, grab info out of $X |
|
149
|
|
|
|
|
|
|
&$rsubr ($screen, $X->{'screens'}->[$screen]); |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
my %geom = $X->GetGeometry ($self->{'-drawable'}); |
|
153
|
|
|
|
|
|
|
foreach my $gkey (keys %get_geometry) { |
|
154
|
|
|
|
|
|
|
if (! defined $self->{$gkey}) { |
|
155
|
|
|
|
|
|
|
$self->{$gkey} = $geom{substr($gkey,1)}; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
if (! defined $self->{'-screen'}) { |
|
159
|
|
|
|
|
|
|
$self->{'-screen'} = X11::Protocol::Other::root_to_screen ($X, $geom{'root'}); |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
return $self->SUPER::_get($key); |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub set { |
|
166
|
|
|
|
|
|
|
my ($self, %params) = @_; |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
if (exists $params{'-pixmap'}) { |
|
169
|
|
|
|
|
|
|
$params{'-drawable'} = delete $params{'-pixmap'}; |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
if (exists $params{'-window'}) { |
|
172
|
|
|
|
|
|
|
$params{'-drawable'} = delete $params{'-window'}; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
if (exists $params{'-drawable'}) { |
|
176
|
|
|
|
|
|
|
_free_gc_created ($self); |
|
177
|
|
|
|
|
|
|
# purge these cached values, %params can supply new ones if desired |
|
178
|
|
|
|
|
|
|
delete @{$self}{keys %get_geometry}; # hash slice |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
if (exists $params{'-colormap'}) { |
|
181
|
|
|
|
|
|
|
%{$self->{'-colour_to_pixel'}} = (); # clear |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
if (exists $params{'-gc'}) { |
|
184
|
|
|
|
|
|
|
# no longer know what colour is in the gc, or not unless included in |
|
185
|
|
|
|
|
|
|
# %params |
|
186
|
|
|
|
|
|
|
$self->{'-gc_colour'} = ''; |
|
187
|
|
|
|
|
|
|
$self->{'-gc_pixel'} = -1; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
%$self = (%$self, %params); |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
194
|
|
|
|
|
|
|
# drawing |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub xy { |
|
197
|
|
|
|
|
|
|
my ($self, $x, $y, $colour) = @_; |
|
198
|
|
|
|
|
|
|
### xy |
|
199
|
|
|
|
|
|
|
### $x |
|
200
|
|
|
|
|
|
|
### $y |
|
201
|
|
|
|
|
|
|
### $colour |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
if ($x < 0 || $y < 0 || $x > 0x7FFF || $y > 0x7FFF) { |
|
204
|
|
|
|
|
|
|
### outside max drawable, don't overflow INT16 ... |
|
205
|
|
|
|
|
|
|
return undef; # fetch or store |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
my $X = $self->{'-X'}; |
|
209
|
|
|
|
|
|
|
my $drawable = $self->{'-drawable'}; |
|
210
|
|
|
|
|
|
|
if (@_ == 4) { |
|
211
|
|
|
|
|
|
|
# store colour |
|
212
|
|
|
|
|
|
|
$X->PolyPoint ($drawable, _gc_colour($self,$colour), 'Origin', $x,$y); |
|
213
|
|
|
|
|
|
|
return; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# fetch colour |
|
217
|
|
|
|
|
|
|
my @reply = $X->robust_req ('GetImage', $drawable, |
|
218
|
|
|
|
|
|
|
$x, $y, 1, 1, 0xFFFFFFFF, 'ZPixmap'); |
|
219
|
|
|
|
|
|
|
if (! ref $reply[0]) { |
|
220
|
|
|
|
|
|
|
if ($reply[0] eq 'Match') { |
|
221
|
|
|
|
|
|
|
### Match error reading offscreen |
|
222
|
|
|
|
|
|
|
return ''; |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
croak "Error reading pixel: ",join(' ',@reply); |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
my ($depth, $visual, $bytes) = @{$reply[0]}; |
|
227
|
|
|
|
|
|
|
if (! defined $self->{'-depth'}) { |
|
228
|
|
|
|
|
|
|
$self->{'-depth'} = $depth; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
### $depth |
|
231
|
|
|
|
|
|
|
### $visual |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# X11::Protocol 0.56 shows named 'LeastSiginificant' in the pod, but the |
|
234
|
|
|
|
|
|
|
# code gives raw number '0'. Let num() crunch either. |
|
235
|
|
|
|
|
|
|
if ($X->num('Significance',$X->{'image_byte_order'}) == 0) { |
|
236
|
|
|
|
|
|
|
#### reverse for LSB image format |
|
237
|
|
|
|
|
|
|
$bytes = reverse $bytes; |
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
### $bytes |
|
240
|
|
|
|
|
|
|
my $pixel = unpack ('N', $bytes); |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# not sure what the protocol says about extra bits or bytes in the reply |
|
243
|
|
|
|
|
|
|
# data, have seen a freebsd server giving garbage, so mask the extras |
|
244
|
|
|
|
|
|
|
$pixel &= (1 << $depth) - 1; |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
### pixel: sprintf '%X', $pixel |
|
247
|
|
|
|
|
|
|
### pixel_to_colour: $self->pixel_to_colour($pixel) |
|
248
|
|
|
|
|
|
|
if (defined ($colour = $self->pixel_to_colour($pixel))) { |
|
249
|
|
|
|
|
|
|
return $colour; |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
if (my $colormap = $self->{'-colormap'}) { |
|
252
|
|
|
|
|
|
|
#### query: $X->QueryColors ($self->get('-colormap'), $pixel) |
|
253
|
|
|
|
|
|
|
my ($rgb) = $X->QueryColors ($self->get('-colormap'), $pixel); |
|
254
|
|
|
|
|
|
|
#### $rgb |
|
255
|
|
|
|
|
|
|
return sprintf('#%04X%04X%04X', @$rgb); |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
return $pixel; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
sub Image_Base_Other_xy_points { |
|
260
|
|
|
|
|
|
|
my $self = shift; |
|
261
|
|
|
|
|
|
|
my $colour = shift; |
|
262
|
|
|
|
|
|
|
my $gc = _gc_colour($self,$colour); |
|
263
|
|
|
|
|
|
|
my $X = $self->{'-X'}; |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
# PolyPoint is 3xCARD32 for drawable,gc,mode then room for maxlen-3 words |
|
266
|
|
|
|
|
|
|
# of X,Y values. X and Y are INT16 each, hence room for (maxlen-3)*2 |
|
267
|
|
|
|
|
|
|
# individual points. Is there any merit sending smaller chunks though? |
|
268
|
|
|
|
|
|
|
# 250kbytes is a typical server limit. |
|
269
|
|
|
|
|
|
|
# |
|
270
|
|
|
|
|
|
|
my $maxpoints = 2*($X->{'maximum_request_length'} - 3); |
|
271
|
|
|
|
|
|
|
### $maxpoints |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
my @points; |
|
274
|
|
|
|
|
|
|
while (@_) { |
|
275
|
|
|
|
|
|
|
if (@points >= $maxpoints) { |
|
276
|
|
|
|
|
|
|
$X->PolyPoint ($self->{'-drawable'}, $gc, 'Origin', @points); |
|
277
|
|
|
|
|
|
|
$#points = -1; # empty |
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
my $x = shift; |
|
280
|
|
|
|
|
|
|
my $y = shift; |
|
281
|
|
|
|
|
|
|
if ($x >= 0 && $y >= 0 && $x <= 0x7FFF && $y <= 0x7FFF) { |
|
282
|
|
|
|
|
|
|
# within max drawable ... |
|
283
|
|
|
|
|
|
|
push @points, $x,$y; |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
if (@points) { |
|
287
|
|
|
|
|
|
|
$X->PolyPoint ($self->{'-drawable'}, $gc, 'Origin', @points); |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
sub line { |
|
292
|
|
|
|
|
|
|
my ($self, $x1, $y1, $x2, $y2, $colour) = @_ ; |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
($x1,$y1, $x2,$y2) = _line_clip ($x1,$y1, $x2,$y2) |
|
295
|
|
|
|
|
|
|
or return; # nothing left after clipping |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
$self->{'-X'}->PolySegment ($self->{'-drawable'}, _gc_colour($self,$colour), |
|
298
|
|
|
|
|
|
|
$x1,$y1, $x2,$y2); |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
sub rectangle { |
|
302
|
|
|
|
|
|
|
my ($self, $x1, $y1, $x2, $y2, $colour, $fill) = @_; |
|
303
|
|
|
|
|
|
|
### X11-Protocol-Drawable rectangle |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
unless ($x2 >= 0 && $y2 >= 0 && $x1 <= 0x7FFF && $y1 <= 0x7FFF) { |
|
306
|
|
|
|
|
|
|
### entirely outside max possible drawable ... |
|
307
|
|
|
|
|
|
|
return; |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# Don't underflow INT16 -0x8000 x,y in request. But retain negativeness so |
|
311
|
|
|
|
|
|
|
# as not to bring top and left sides of an unfilled rect into view. |
|
312
|
|
|
|
|
|
|
if ($x1 < -1) { $x1 = -1; } |
|
313
|
|
|
|
|
|
|
if ($y1 < -1) { $y1 = -1; } |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# Don't overflow CARD16 width,height in request. Together with x1,y1 >= |
|
316
|
|
|
|
|
|
|
# -1 this makes w,h <= 0x8002. It doesn't bring the unfilled right and |
|
317
|
|
|
|
|
|
|
# bottom sides into view even if the drawable is 0 to 0x7FFF. |
|
318
|
|
|
|
|
|
|
if ($x2 > 0x8000) { $x2 = 0x8000; } |
|
319
|
|
|
|
|
|
|
if ($y2 > 0x8000) { $y2 = 0x8000; } |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
if ($x1 == $x2 || $y1 == $y2) { |
|
322
|
|
|
|
|
|
|
# single pixel wide or high, must treat as filled since PolyRectangle() |
|
323
|
|
|
|
|
|
|
# draws nothing if passed width==0 or height==0 |
|
324
|
|
|
|
|
|
|
$fill = 1; |
|
325
|
|
|
|
|
|
|
} else { |
|
326
|
|
|
|
|
|
|
$fill = !!$fill; # 0 or 1 for arithmetic |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
### coords: [ $x1, $y1, $x2-$x1, $y2-$y1 ] |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
$self->{'-X'}->request ($fill ? 'PolyFillRectangle' : 'PolyRectangle', |
|
331
|
|
|
|
|
|
|
$self->{'-drawable'}, |
|
332
|
|
|
|
|
|
|
_gc_colour($self,$colour), |
|
333
|
|
|
|
|
|
|
[ $x1, $y1, $x2-$x1+$fill, $y2-$y1+$fill ]); |
|
334
|
|
|
|
|
|
|
} |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub Image_Base_Other_rectangles { |
|
337
|
|
|
|
|
|
|
### X11-Protocol-Drawable rectangles() |
|
338
|
|
|
|
|
|
|
### count: scalar(@_) |
|
339
|
|
|
|
|
|
|
my $self = shift; |
|
340
|
|
|
|
|
|
|
my $colour = shift; |
|
341
|
|
|
|
|
|
|
my $fill = !! shift; # 0 or 1 |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
my $method = ($fill ? 'PolyFillRectangle' : 'PolyRectangle'); |
|
344
|
|
|
|
|
|
|
### $method |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
### coords count: scalar(@_) |
|
347
|
|
|
|
|
|
|
### coords: @_ |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
my @rects; |
|
350
|
|
|
|
|
|
|
my @filled; |
|
351
|
|
|
|
|
|
|
while (my ($x1,$y1, $x2,$y2) = splice @_,0,4) { |
|
352
|
|
|
|
|
|
|
### quad: ($x1,$y1, $x2,$y2) |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
unless ($x2 >= 0 && $y2 >= 0 && $x1 <= 0x7FFF && $y1 <= 0x7FFF) { |
|
355
|
|
|
|
|
|
|
### entirely outside max possible drawable ... |
|
356
|
|
|
|
|
|
|
next; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
# don't underflow INT16 -0x8000 x,y in request |
|
359
|
|
|
|
|
|
|
# but retain negativeness so as not to bring unfilled sides into view |
|
360
|
|
|
|
|
|
|
if ($x1 < -1) { $x1 = -1; } |
|
361
|
|
|
|
|
|
|
if ($y1 < -1) { $y1 = -1; } |
|
362
|
|
|
|
|
|
|
# don't overflow CARD16 width,height in request |
|
363
|
|
|
|
|
|
|
if ($x2 > 0x8000) { $x2 = 0x8000; } |
|
364
|
|
|
|
|
|
|
if ($y2 > 0x8000) { $y2 = 0x8000; } |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
if (! $fill && ($x1 == $x2 || $y1 == $y2)) { |
|
367
|
|
|
|
|
|
|
# single pixel wide or high |
|
368
|
|
|
|
|
|
|
push @filled, [ $x1, $y1, $x2-$x1+1, $y2-$y1+1 ]; |
|
369
|
|
|
|
|
|
|
} else { |
|
370
|
|
|
|
|
|
|
push @rects, [ $x1, $y1, $x2-$x1+$fill, $y2-$y1+$fill ]; |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
} |
|
373
|
|
|
|
|
|
|
### @rects |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
my $X = $self->{'-X'}; |
|
376
|
|
|
|
|
|
|
my $gc = _gc_colour($self,$colour); |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# PolyRectangle is 3xCARD32 header,drawable,gc then room for maxlen-3 |
|
379
|
|
|
|
|
|
|
# words of X,Y,WIDTH,HEIGHT values. X,Y are INT16 and WIDTH,HEIGHT are |
|
380
|
|
|
|
|
|
|
# CARD16 each, hence room for floor((maxlen-3)/2) rectangles. Is there |
|
381
|
|
|
|
|
|
|
# any value sending somewhat smaller chunks though? 250kbytes is a |
|
382
|
|
|
|
|
|
|
# typical server limit. Xlib ZRCTSPERBATCH is just 256 thin line rects, |
|
383
|
|
|
|
|
|
|
# or WRCTSPERBATCH 10 wides. |
|
384
|
|
|
|
|
|
|
# |
|
385
|
|
|
|
|
|
|
my $maxrects = int (($X->{'maximum_request_length'} - 3) / 2); |
|
386
|
|
|
|
|
|
|
### $maxrects |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
foreach my $aref (\@rects, \@filled) { |
|
389
|
|
|
|
|
|
|
if (@$aref) { |
|
390
|
|
|
|
|
|
|
my $drawable = $self->{'-drawable'}; |
|
391
|
|
|
|
|
|
|
while (@$aref > $maxrects) { |
|
392
|
|
|
|
|
|
|
### splice down from: scalar(@$aref) |
|
393
|
|
|
|
|
|
|
$X->$method ($drawable, $gc, splice @$aref, 0,$maxrects); |
|
394
|
|
|
|
|
|
|
} |
|
395
|
|
|
|
|
|
|
### final: $method, @$aref |
|
396
|
|
|
|
|
|
|
$X->$method ($drawable, $gc, @$aref); |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
$method = 'PolyFillRectangle'; |
|
399
|
|
|
|
|
|
|
} |
|
400
|
|
|
|
|
|
|
} |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
# The Arc requests take the bounding region at |
|
403
|
|
|
|
|
|
|
# left x, y+(h/2) |
|
404
|
|
|
|
|
|
|
# right x+w, y+(h/2) |
|
405
|
|
|
|
|
|
|
# top x+(w/2), y |
|
406
|
|
|
|
|
|
|
# bottom x+(w/2), y+h |
|
407
|
|
|
|
|
|
|
# with w=x2-x1, h=y2-y1. |
|
408
|
|
|
|
|
|
|
# |
|
409
|
|
|
|
|
|
|
# For PolyArc a 1-wide line makes each of those pixels drawn, but a |
|
410
|
|
|
|
|
|
|
# PolyFillArc is only the inside, not the extra 0.5 around the outside, |
|
411
|
|
|
|
|
|
|
# which means the bottom and right endmost pixels not drawn, and others a |
|
412
|
|
|
|
|
|
|
# bit smaller than PolyArc. |
|
413
|
|
|
|
|
|
|
# |
|
414
|
|
|
|
|
|
|
# For now try a PolyArc on top of the PolyFillArc to get the extra 0.5 |
|
415
|
|
|
|
|
|
|
# around the outside. Can it be done better? Prima has this, as long as |
|
416
|
|
|
|
|
|
|
# the drawing mode isn't xor etc where duplicated pixels are bad. |
|
417
|
|
|
|
|
|
|
# |
|
418
|
|
|
|
|
|
|
# One possibility would be to set line width lw=min(w/2,h/2) rounded up to |
|
419
|
|
|
|
|
|
|
# next odd integer, and shrink the bounding box by (lw-1)/2, so a PolyLine |
|
420
|
|
|
|
|
|
|
# centred there goes out to the very edges of the x1,y1,x2,y2 box, not just |
|
421
|
|
|
|
|
|
|
# the centres of those pixels, and being w/2 or h/2 will extend in to cover |
|
422
|
|
|
|
|
|
|
# the centre. The disadvantage would be changing the line width for each |
|
423
|
|
|
|
|
|
|
# draw, or keep another gc, and that might take away the option for the user |
|
424
|
|
|
|
|
|
|
# to set in a '-gc' option to choose between zero-width fast lines and |
|
425
|
|
|
|
|
|
|
# 1-width exact lines. An advantage though would be a single draw operation |
|
426
|
|
|
|
|
|
|
# meaning an "xor" mode in the gc would cover the right pixels. There's |
|
427
|
|
|
|
|
|
|
# something in the PolyArc spec about the bounding box being implementation |
|
428
|
|
|
|
|
|
|
# dependent if width!=height, so maybe this wouldn't work always. |
|
429
|
|
|
|
|
|
|
# |
|
430
|
|
|
|
|
|
|
# The same bounding box centred on the pixels happens in rectangle(), but |
|
431
|
|
|
|
|
|
|
# can be handled there by +1 on the width and height. A +1 doesn't make a |
|
432
|
|
|
|
|
|
|
# filled ellipse come out the same as an outlined ellipse though. |
|
433
|
|
|
|
|
|
|
# |
|
434
|
|
|
|
|
|
|
# same in Window.pm for shape stuff |
|
435
|
|
|
|
|
|
|
sub ellipse { |
|
436
|
|
|
|
|
|
|
my ($self, $x1, $y1, $x2, $y2, $colour, $fill) = @_; |
|
437
|
|
|
|
|
|
|
### Drawable ellipse(): $x1, $y1, $x2, $y2, $colour |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
my $w = $x2 - $x1; |
|
440
|
|
|
|
|
|
|
my $h = $y2 - $y1; |
|
441
|
|
|
|
|
|
|
if ($w <= 1 || $h <= 1) { |
|
442
|
|
|
|
|
|
|
# 1 or 2 pixels wide or high |
|
443
|
|
|
|
|
|
|
shift->rectangle(@_); |
|
444
|
|
|
|
|
|
|
return; |
|
445
|
|
|
|
|
|
|
} |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
unless ($x2 >= 0 && $y2 >= 0 && $x1 <= 0x7FFF && $y1 <= 0x7FFF) { |
|
448
|
|
|
|
|
|
|
### entirely outside max possible drawable ... |
|
449
|
|
|
|
|
|
|
return; |
|
450
|
|
|
|
|
|
|
} |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
if ($x1 < -0x8000 || $x2 > 0x7FFF || $y1 < -0x8000 || $y2 > 0x7FFF) { |
|
453
|
|
|
|
|
|
|
### coordinates would overflow, use superclass ... |
|
454
|
|
|
|
|
|
|
shift->SUPER::ellipse(@_); |
|
455
|
|
|
|
|
|
|
return; |
|
456
|
|
|
|
|
|
|
} |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
### PolyArc: $x1, $y1, $x2-$x1+1, $y2-$y1+1, 0, 360*64 |
|
459
|
|
|
|
|
|
|
my @args = ($self->{'-drawable'}, _gc_colour($self,$colour), |
|
460
|
|
|
|
|
|
|
[ $x1, $y1, $w, $h, 0, 360*64 ]); |
|
461
|
|
|
|
|
|
|
my $X = $self->{'-X'}; |
|
462
|
|
|
|
|
|
|
if ($fill) { |
|
463
|
|
|
|
|
|
|
$X->PolyFillArc (@args); |
|
464
|
|
|
|
|
|
|
} |
|
465
|
|
|
|
|
|
|
$X->PolyArc (@args); |
|
466
|
|
|
|
|
|
|
} |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub diamond { |
|
469
|
|
|
|
|
|
|
my ($self, $x1, $y1, $x2, $y2, $colour, $fill) = @_; |
|
470
|
|
|
|
|
|
|
### Drawable diamond(): $x1, $y1, $x2, $y2, $colour |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
if ($x1==$x2 && $y1==$y2) { |
|
473
|
|
|
|
|
|
|
# 1x1 polygon draws nothing, do it as a point instead |
|
474
|
|
|
|
|
|
|
$self->xy($x1,$y1, $colour); |
|
475
|
|
|
|
|
|
|
return; |
|
476
|
|
|
|
|
|
|
} |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
_diamond_drawable ($self->{'-X'}, |
|
479
|
|
|
|
|
|
|
$self->{'-drawable'}, |
|
480
|
|
|
|
|
|
|
_gc_colour($self,$colour), |
|
481
|
|
|
|
|
|
|
$x1,$y1, $x2,$y2, $fill); |
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# shared by Image::Base::X11::Protocol::Window::diamond() |
|
485
|
|
|
|
|
|
|
sub _diamond_drawable { |
|
486
|
|
|
|
|
|
|
my ($X, $drawable, $gc, $x1, $y1, $x2, $y2, $fill) = @_; |
|
487
|
|
|
|
|
|
|
### _diamond_drawable() ... |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
my $xh = int( ($x2 - $x1)/2 ); |
|
490
|
|
|
|
|
|
|
my $yh = int( ($y2 - $y1)/2 ); |
|
491
|
|
|
|
|
|
|
my $xmid_floor = $x1 + $xh; |
|
492
|
|
|
|
|
|
|
my $xmid_ceil = $x2 - $xh; |
|
493
|
|
|
|
|
|
|
my $ymid_floor = $y1 + $yh; |
|
494
|
|
|
|
|
|
|
my $ymid_ceil = $y2 - $yh; |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
if ($fill) { |
|
497
|
|
|
|
|
|
|
# 1-0 |
|
498
|
|
|
|
|
|
|
# / |
|
499
|
|
|
|
|
|
|
# 2 7 |
|
500
|
|
|
|
|
|
|
# 3 6 |
|
501
|
|
|
|
|
|
|
# \ / |
|
502
|
|
|
|
|
|
|
# 4-5 |
|
503
|
|
|
|
|
|
|
my @xy =(# top |
|
504
|
|
|
|
|
|
|
($xmid_floor == $xmid_ceil ? () : ($xmid_ceil, $y1)), |
|
505
|
|
|
|
|
|
|
$xmid_floor, $y1, |
|
506
|
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
# left |
|
508
|
|
|
|
|
|
|
$x1, $ymid_floor, |
|
509
|
|
|
|
|
|
|
($ymid_floor == $ymid_ceil ? () : ($x1, $ymid_ceil)), |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
# bottom |
|
512
|
|
|
|
|
|
|
$xmid_floor, $y2, |
|
513
|
|
|
|
|
|
|
($xmid_floor == $xmid_ceil ? () : ($xmid_ceil, $y2)), |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
# right |
|
516
|
|
|
|
|
|
|
($ymid_floor == $ymid_ceil ? () : ($x2, $ymid_ceil)), |
|
517
|
|
|
|
|
|
|
$x2, $ymid_floor, |
|
518
|
|
|
|
|
|
|
); |
|
519
|
|
|
|
|
|
|
_convex_poly_clip(\@xy); |
|
520
|
|
|
|
|
|
|
### clipped: @xy |
|
521
|
|
|
|
|
|
|
if (@xy) { |
|
522
|
|
|
|
|
|
|
push @xy, $xy[0],$xy[1]; # back to start |
|
523
|
|
|
|
|
|
|
$X->FillPoly ($drawable, $gc, 'Convex', 'Origin', @xy); |
|
524
|
|
|
|
|
|
|
$X->PolyLine ($drawable, $gc, 'Origin', @xy); |
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
} else { |
|
528
|
|
|
|
|
|
|
# unfilled |
|
529
|
|
|
|
|
|
|
$X->PolySegment ($drawable, $gc, |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# NW A . |
|
532
|
|
|
|
|
|
|
# / \ |
|
533
|
|
|
|
|
|
|
# B . |
|
534
|
|
|
|
|
|
|
_line_clip ($xmid_floor, $y1, $x1, $ymid_floor), |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
# SW B . |
|
537
|
|
|
|
|
|
|
# \ / |
|
538
|
|
|
|
|
|
|
# A . |
|
539
|
|
|
|
|
|
|
_line_clip ($xmid_floor, $y2, $x1, $ymid_ceil), |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
# SE . B |
|
542
|
|
|
|
|
|
|
# \ / |
|
543
|
|
|
|
|
|
|
# . A |
|
544
|
|
|
|
|
|
|
_line_clip ($xmid_ceil, $y2, $x2, $ymid_ceil), |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# NE . A |
|
547
|
|
|
|
|
|
|
# / \ |
|
548
|
|
|
|
|
|
|
# . B |
|
549
|
|
|
|
|
|
|
_line_clip ($xmid_ceil, $y1, $x2, $ymid_floor)); |
|
550
|
|
|
|
|
|
|
} |
|
551
|
|
|
|
|
|
|
} |
|
552
|
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
# not yet a documented feature ... |
|
556
|
|
|
|
|
|
|
sub pixel_to_colour { |
|
557
|
|
|
|
|
|
|
my ($self,$pixel) = @_; |
|
558
|
|
|
|
|
|
|
my $hash = ($self->{'-pixel_to_colour'} ||= do { |
|
559
|
|
|
|
|
|
|
### colour_to_pixel hash: $self->{'-colour_to_pixel'} |
|
560
|
|
|
|
|
|
|
({ reverse %{$self->{'-colour_to_pixel'}} }) # force anon hash |
|
561
|
|
|
|
|
|
|
}); |
|
562
|
|
|
|
|
|
|
return $hash->{$pixel}; |
|
563
|
|
|
|
|
|
|
} |
|
564
|
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
# return a gc XID which is set to draw in $colour |
|
566
|
|
|
|
|
|
|
sub _gc_colour { |
|
567
|
|
|
|
|
|
|
my ($self, $colour) = @_; |
|
568
|
|
|
|
|
|
|
if ($colour eq 'None') { |
|
569
|
|
|
|
|
|
|
$colour = 'black'; |
|
570
|
|
|
|
|
|
|
} |
|
571
|
|
|
|
|
|
|
my $gc = $self->{'-gc'} || $self->{'-gc_created'}; |
|
572
|
|
|
|
|
|
|
if ($colour ne $self->{'-gc_colour'}) { |
|
573
|
|
|
|
|
|
|
### X11-Protocol-Drawable -gc_colour() change: $colour |
|
574
|
|
|
|
|
|
|
my $pixel = $self->colour_to_pixel ($colour); |
|
575
|
|
|
|
|
|
|
$self->{'-gc_colour'} = $colour; |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
if ($pixel != $self->{'-gc_pixel'}) { |
|
578
|
|
|
|
|
|
|
$self->{'-gc_pixel'} = $pixel; |
|
579
|
|
|
|
|
|
|
my $X = $self->{'-X'}; |
|
580
|
|
|
|
|
|
|
if ($gc) { |
|
581
|
|
|
|
|
|
|
### ChangeGC to pixel: $pixel |
|
582
|
|
|
|
|
|
|
$X->ChangeGC ($gc, foreground => $pixel); |
|
583
|
|
|
|
|
|
|
} else { |
|
584
|
|
|
|
|
|
|
$gc = $self->{'-gc_created'} = $X->new_rsrc; |
|
585
|
|
|
|
|
|
|
### CreateGC with pixel ... |
|
586
|
|
|
|
|
|
|
### $gc |
|
587
|
|
|
|
|
|
|
### $pixel |
|
588
|
|
|
|
|
|
|
$X->CreateGC ($gc, $self->{'-drawable'}, foreground => $pixel); |
|
589
|
|
|
|
|
|
|
} |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
} |
|
592
|
|
|
|
|
|
|
return $gc; |
|
593
|
|
|
|
|
|
|
} |
|
594
|
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
# return an allocated pixel number |
|
596
|
|
|
|
|
|
|
# not yet a documented feature ... |
|
597
|
|
|
|
|
|
|
sub colour_to_pixel { |
|
598
|
|
|
|
|
|
|
my ($self, $colour) = @_; |
|
599
|
|
|
|
|
|
|
### X11-Protocol-Drawable _colour_to_pixel(): $colour |
|
600
|
|
|
|
|
|
|
if ($colour =~ /^^\d+$/) { |
|
601
|
|
|
|
|
|
|
return $colour; # numeric pixel value |
|
602
|
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
if ($colour eq 'set') { |
|
604
|
|
|
|
|
|
|
# ENHANCE-ME: maybe all bits set if depth > 1 |
|
605
|
|
|
|
|
|
|
return 1; |
|
606
|
|
|
|
|
|
|
} |
|
607
|
|
|
|
|
|
|
if ($colour eq 'clear') { |
|
608
|
|
|
|
|
|
|
return 0; |
|
609
|
|
|
|
|
|
|
} |
|
610
|
|
|
|
|
|
|
if (defined (my $pixel = $self->{'-colour_to_pixel'}->{$colour})) { |
|
611
|
|
|
|
|
|
|
return $pixel; |
|
612
|
|
|
|
|
|
|
} |
|
613
|
|
|
|
|
|
|
$self->add_colours ($colour); |
|
614
|
|
|
|
|
|
|
return $self->{'-colour_to_pixel'}->{$colour}; |
|
615
|
|
|
|
|
|
|
} |
|
616
|
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
my %colour_to_screen_field |
|
618
|
|
|
|
|
|
|
= ('black' => 'black_pixel', |
|
619
|
|
|
|
|
|
|
'#000000' => 'black_pixel', |
|
620
|
|
|
|
|
|
|
'#000000000000' => 'black_pixel', |
|
621
|
|
|
|
|
|
|
'white' => 'white_pixel', |
|
622
|
|
|
|
|
|
|
'#FFFFFF' => 'white_pixel', |
|
623
|
|
|
|
|
|
|
'#FFFFFFFFFFFF' => 'white_pixel', |
|
624
|
|
|
|
|
|
|
'#ffffff' => 'white_pixel', |
|
625
|
|
|
|
|
|
|
'#ffffffffffff' => 'white_pixel', |
|
626
|
|
|
|
|
|
|
); |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub add_colours { |
|
629
|
|
|
|
|
|
|
my $self = shift; |
|
630
|
|
|
|
|
|
|
### add_colours: @_ |
|
631
|
|
|
|
|
|
|
my $X = $self->{'-X'}; |
|
632
|
|
|
|
|
|
|
my $colormap = $self->get('-colormap') |
|
633
|
|
|
|
|
|
|
|| croak 'No -colormap to add colours to'; |
|
634
|
|
|
|
|
|
|
my $colour_to_pixel = $self->{'-colour_to_pixel'}; |
|
635
|
|
|
|
|
|
|
my $pixel_to_colour = $self->{'-pixel_to_colour'}; |
|
636
|
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
my @queued; |
|
638
|
|
|
|
|
|
|
my @failed_colours; |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
my $old_error_handler = $X->{'error_handler'}; |
|
641
|
|
|
|
|
|
|
my $wait_queue = sub { |
|
642
|
|
|
|
|
|
|
my $elem = shift @queued; |
|
643
|
|
|
|
|
|
|
my $seq = $elem->{'seq'}; |
|
644
|
|
|
|
|
|
|
my $colour = $elem->{'colour'}; |
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
my $err; |
|
647
|
|
|
|
|
|
|
local $X->{'error_handler'} = sub { |
|
648
|
|
|
|
|
|
|
my ($X, $data) = @_; |
|
649
|
|
|
|
|
|
|
my ($type, $err_seq) = unpack("xCSLSCxxxxxxxxxxxxxxxxxxxxx", $data); |
|
650
|
|
|
|
|
|
|
if ($err_seq != $seq) { |
|
651
|
|
|
|
|
|
|
goto &$old_error_handler; |
|
652
|
|
|
|
|
|
|
} |
|
653
|
|
|
|
|
|
|
$err = 1; |
|
654
|
|
|
|
|
|
|
}; |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
### handle: $seq |
|
657
|
|
|
|
|
|
|
$X->handle_input_for ($seq); |
|
658
|
|
|
|
|
|
|
$X->delete_reply ($seq); |
|
659
|
|
|
|
|
|
|
if ($err) { |
|
660
|
|
|
|
|
|
|
push @failed_colours, $colour; |
|
661
|
|
|
|
|
|
|
return; |
|
662
|
|
|
|
|
|
|
} |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
### reply: $X->unpack_reply($elem->{'request_type'}, $elem->{'reply'}) |
|
665
|
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
my ($pixel) = $X->unpack_reply ($elem->{'request_type'}, $elem->{'reply'}); |
|
667
|
|
|
|
|
|
|
$colour_to_pixel->{$colour} = $pixel; |
|
668
|
|
|
|
|
|
|
if ($pixel_to_colour) { |
|
669
|
|
|
|
|
|
|
$pixel_to_colour->{$pixel} = $colour; |
|
670
|
|
|
|
|
|
|
} |
|
671
|
|
|
|
|
|
|
}; |
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
while (@_) { |
|
674
|
|
|
|
|
|
|
my $colour = shift; |
|
675
|
|
|
|
|
|
|
next if defined $colour_to_pixel->{$colour}; # already known |
|
676
|
|
|
|
|
|
|
delete $self->{'-pixel_to_colour'}; |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
# black_pixel or white_pixel of a default colormap |
|
679
|
|
|
|
|
|
|
if (my $field = $colour_to_screen_field{$colour}) { # "black" or "white" |
|
680
|
|
|
|
|
|
|
if (my $screen_info = X11::Protocol::Other::default_colormap_to_screen_info($X,$colormap)) { |
|
681
|
|
|
|
|
|
|
my $pixel = $colour_to_pixel->{$colour} = $screen_info->{$field}; |
|
682
|
|
|
|
|
|
|
if ($pixel_to_colour) { |
|
683
|
|
|
|
|
|
|
$pixel_to_colour->{$pixel} = $colour; |
|
684
|
|
|
|
|
|
|
} |
|
685
|
|
|
|
|
|
|
next; |
|
686
|
|
|
|
|
|
|
} |
|
687
|
|
|
|
|
|
|
} |
|
688
|
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
my $elem = { colour => $colour }; |
|
690
|
|
|
|
|
|
|
my @req; |
|
691
|
|
|
|
|
|
|
# Crib: [:xdigit:] new in 5.6, so only 0-9A-F, and in any case as of |
|
692
|
|
|
|
|
|
|
# perl 5.12.4 [:xdigit:] matches some wide chars but hex() doesn't |
|
693
|
|
|
|
|
|
|
# accept them |
|
694
|
|
|
|
|
|
|
if (my @rgb = X11::Protocol::Other::hexstr_to_rgb($colour)) { |
|
695
|
|
|
|
|
|
|
@req = ('AllocColor', $colormap, map {hex} @rgb); |
|
696
|
|
|
|
|
|
|
} else { |
|
697
|
|
|
|
|
|
|
@req = ('AllocNamedColor', $colormap, $colour); |
|
698
|
|
|
|
|
|
|
} |
|
699
|
|
|
|
|
|
|
$elem->{'request_type'} = $req[0]; |
|
700
|
|
|
|
|
|
|
my $seq = $elem->{'seq'} = $X->send(@req); |
|
701
|
|
|
|
|
|
|
$X->add_reply ($seq, \$elem->{'reply'}); |
|
702
|
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
### $elem |
|
704
|
|
|
|
|
|
|
push @queued, $elem; |
|
705
|
|
|
|
|
|
|
if (@queued > 256) { |
|
706
|
|
|
|
|
|
|
&$wait_queue(); |
|
707
|
|
|
|
|
|
|
} |
|
708
|
|
|
|
|
|
|
} |
|
709
|
|
|
|
|
|
|
while (@queued) { |
|
710
|
|
|
|
|
|
|
&$wait_queue(); |
|
711
|
|
|
|
|
|
|
} |
|
712
|
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
if (@failed_colours) { |
|
714
|
|
|
|
|
|
|
die "Unknown colour(s): ",join(', ', @failed_colours); |
|
715
|
|
|
|
|
|
|
} |
|
716
|
|
|
|
|
|
|
} |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
|
719
|
|
|
|
|
|
|
# clipping to signed 16-bit parameters |
|
720
|
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
use constant _LO => -0x8000; # -32768 |
|
722
|
|
|
|
|
|
|
use constant _HI => 0x7FFF; # +32767 |
|
723
|
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
# $x1,$y1, $x2,$y2 are the endpoints of a line. |
|
725
|
|
|
|
|
|
|
# Return new endpoints which are clipped to within -0x8000 to +0x7FFF which is |
|
726
|
|
|
|
|
|
|
# signed 16-bits for X protocol. |
|
727
|
|
|
|
|
|
|
# If given line is entirely outside the signed 16-bit rectangle then return |
|
728
|
|
|
|
|
|
|
# an empty list. |
|
729
|
|
|
|
|
|
|
# |
|
730
|
|
|
|
|
|
|
sub _line_clip { |
|
731
|
|
|
|
|
|
|
my ($x1,$y1, $x2,$y2) = @_; |
|
732
|
|
|
|
|
|
|
### _line_clip_16bit(): "$x1,$y1, $x2,$y2" |
|
733
|
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
unless (_line_any_positive($x1,$y1, $x2,$y2)) { |
|
735
|
|
|
|
|
|
|
### nothing positive ... |
|
736
|
|
|
|
|
|
|
return; |
|
737
|
|
|
|
|
|
|
} |
|
738
|
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
my ($x1new,$y1new) = _line_end_clip($x1,$y1, $x2,$y2) |
|
740
|
|
|
|
|
|
|
or do { |
|
741
|
|
|
|
|
|
|
### x1,y1 end nothing in range ... |
|
742
|
|
|
|
|
|
|
return; |
|
743
|
|
|
|
|
|
|
}; |
|
744
|
|
|
|
|
|
|
($x2,$y2) = _line_end_clip($x2,$y2, $x1,$y1) |
|
745
|
|
|
|
|
|
|
or return; |
|
746
|
|
|
|
|
|
|
return ($x1new,$y1new, $x2,$y2); |
|
747
|
|
|
|
|
|
|
} |
|
748
|
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
# $x1,$y1, $x2,$y2 are the endpoints of a line. |
|
750
|
|
|
|
|
|
|
# Return new values for the $x2,$y2 end which clips it to within |
|
751
|
|
|
|
|
|
|
# LO <= x2 <= HI |
|
752
|
|
|
|
|
|
|
# LO <= y2 <= HI |
|
753
|
|
|
|
|
|
|
# |
|
754
|
|
|
|
|
|
|
# If the line is entirely outside LO to HI then return an empty list. |
|
755
|
|
|
|
|
|
|
# If x2,y2 is already within LO to HI then return them unchanged. |
|
756
|
|
|
|
|
|
|
# |
|
757
|
|
|
|
|
|
|
# x1,y1 |
|
758
|
|
|
|
|
|
|
# / |
|
759
|
|
|
|
|
|
|
# +-------- if x2 outside |
|
760
|
|
|
|
|
|
|
# | / then |
|
761
|
|
|
|
|
|
|
# |/ move it to x2new=LO |
|
762
|
|
|
|
|
|
|
# x2new,y2new * and y2new=corresponding pos on line |
|
763
|
|
|
|
|
|
|
# /| |
|
764
|
|
|
|
|
|
|
# / | |
|
765
|
|
|
|
|
|
|
# x2,y2 +-------- |
|
766
|
|
|
|
|
|
|
# LO |
|
767
|
|
|
|
|
|
|
# |
|
768
|
|
|
|
|
|
|
# +--------- |
|
769
|
|
|
|
|
|
|
# | if y2 outside, |
|
770
|
|
|
|
|
|
|
# | x1,y1 including moved y2new outside |
|
771
|
|
|
|
|
|
|
# | / then |
|
772
|
|
|
|
|
|
|
# +--*----- move it to y2new=LO |
|
773
|
|
|
|
|
|
|
# /x2new, and x2new=corresponding pos on line |
|
774
|
|
|
|
|
|
|
# / y2new |
|
775
|
|
|
|
|
|
|
# first y2new * |
|
776
|
|
|
|
|
|
|
# / |
|
777
|
|
|
|
|
|
|
# / |
|
778
|
|
|
|
|
|
|
# x2,y2 |
|
779
|
|
|
|
|
|
|
# |
|
780
|
|
|
|
|
|
|
sub _line_end_clip { |
|
781
|
|
|
|
|
|
|
my ($x1,$y1, $x2,$y2) = @_; |
|
782
|
|
|
|
|
|
|
### _line_end_clip(): "$x1,$y1, $x2,$y2" |
|
783
|
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
my ($x2new, $y2new); |
|
785
|
|
|
|
|
|
|
if ($x2 < _LO || $x2 > _HI) { |
|
786
|
|
|
|
|
|
|
# x2 is outside LO to HI, clip to x2=LOorHI and y2 set to corresponding |
|
787
|
|
|
|
|
|
|
my $xlen = $x2 - $x1 |
|
788
|
|
|
|
|
|
|
or return; # xlen==0 means x1==x2 so entirely outside LO to HI |
|
789
|
|
|
|
|
|
|
$x2new = ($x2 < _LO ? _LO : _HI); |
|
790
|
|
|
|
|
|
|
$y2new = floor(($y2*($x2new-$x1) + $y1*($x2-$x2new)) / $xlen + 0.5); |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
### x clip: "to $x2new,$y2new frac ".($y2*($x2new-$x1) + $y1*($x2-$x2new))." / $xlen" |
|
793
|
|
|
|
|
|
|
} else { |
|
794
|
|
|
|
|
|
|
$x2new = $x2; |
|
795
|
|
|
|
|
|
|
$y2new = $y2; |
|
796
|
|
|
|
|
|
|
} |
|
797
|
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
if ($y2new < _LO || $y2new > _HI) { |
|
799
|
|
|
|
|
|
|
my $ylen = $y2 - $y1 |
|
800
|
|
|
|
|
|
|
or return; # ylen==0 means y1==y2 so entirely outside LO to HI |
|
801
|
|
|
|
|
|
|
$y2new = ($y2 < _LO ? _LO : _HI); |
|
802
|
|
|
|
|
|
|
$x2new = floor(($x2*($y2new-$y1) + $x1*($y2-$y2new)) / $ylen + 0.5); |
|
803
|
|
|
|
|
|
|
### y clip: "to $x2new,$y2new left ".($y2new-$y1)." right ".($y2-$y2new) |
|
804
|
|
|
|
|
|
|
if ($x2new < _LO || $x2new > _HI) { |
|
805
|
|
|
|
|
|
|
### x2new outside ... |
|
806
|
|
|
|
|
|
|
return; |
|
807
|
|
|
|
|
|
|
} |
|
808
|
|
|
|
|
|
|
} |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
return ($x2new,$y2new); |
|
811
|
|
|
|
|
|
|
} |
|
812
|
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
# x2,y2 |
|
814
|
|
|
|
|
|
|
# / |
|
815
|
|
|
|
|
|
|
# /\ |
|
816
|
|
|
|
|
|
|
# / \ |
|
817
|
|
|
|
|
|
|
# / +--------- |
|
818
|
|
|
|
|
|
|
# x1,y1 | |
|
819
|
|
|
|
|
|
|
# | |
|
820
|
|
|
|
|
|
|
# |
|
821
|
|
|
|
|
|
|
# perp X= -1-pos, Y=-1 -pos*(x2-x1)/(y2-y1) |
|
822
|
|
|
|
|
|
|
# -pos = X+1 |
|
823
|
|
|
|
|
|
|
# Y = (X+1)*(x2-x1)/(y2-y1) - 1 |
|
824
|
|
|
|
|
|
|
# |
|
825
|
|
|
|
|
|
|
# intersect |
|
826
|
|
|
|
|
|
|
# (X+1)*(x2-x1)/(y2-y1) - 1 = (X-x1)/(x2-x1)*(y2-y1) + y1 |
|
827
|
|
|
|
|
|
|
# (X+1)*(x2-x1)/(y2-y1) = (X-x1)/(x2-x1)*(y2-y1) + (y1+1) |
|
828
|
|
|
|
|
|
|
# (X+1)*(x2-x1) = (X-x1)/(x2-x1)*(y2-y1)*(y2-y1) + (y1+1)*(y2-y1) |
|
829
|
|
|
|
|
|
|
# (X+1)*(x2-x1)*(x2-x1) = (X-x1)*(y2-y1)*(y2-y1) + (y1+1)*(y2-y1)*(x2-x1) |
|
830
|
|
|
|
|
|
|
# X*(x2-x1)^2 + (x2-x1)^2 = X*(y2-y1)^2 - x1*(y2-y1)^2 + (y1+1)*(y2-y1)*(x2-x1) |
|
831
|
|
|
|
|
|
|
# X*(x2-x1)^2 - X*(y2-y1)^2 = -(x2-x1)^2 - x1*(y2-y1)^2 + (y1+1)*(y2-y1)*(x2-x1) |
|
832
|
|
|
|
|
|
|
# |
|
833
|
|
|
|
|
|
|
# line X=x1+pos, Y=y1 + pos*(y2-y1)/(x2-x1) |
|
834
|
|
|
|
|
|
|
# Y=y1 + (X-x1)/(x2-x1)*(y2-y1) |
|
835
|
|
|
|
|
|
|
# eg. X=x1 Y=y1 + 0 |
|
836
|
|
|
|
|
|
|
# eg. X=x2 Y=y1 + 1*(y2-y1) = y2 |
|
837
|
|
|
|
|
|
|
# Y-y1 = (X-x1)/(x2-x1)*(y2-y1) |
|
838
|
|
|
|
|
|
|
# (Y-y1)*(x2-x1) = (X-x1)*(y2-y1) |
|
839
|
|
|
|
|
|
|
# |
|
840
|
|
|
|
|
|
|
# line at X=0 is |
|
841
|
|
|
|
|
|
|
# Y = (-x1)/(x2-x1)*(y2-y1) + y1 |
|
842
|
|
|
|
|
|
|
# for Y <= -1 |
|
843
|
|
|
|
|
|
|
# (-x1)/(x2-x1)*(y2-y1) + y1 <= -1 |
|
844
|
|
|
|
|
|
|
# (-x1)/(x2-x1)*(y2-y1) <= -1-y1 |
|
845
|
|
|
|
|
|
|
# (-x1)*(y2-y1) <= (-1-y1)*(x2-x1) would swap if x2
|
|
846
|
|
|
|
|
|
|
# x1*(y2-y1) >= (y1+1)*(x2-x1) |
|
847
|
|
|
|
|
|
|
# eg. x1=-1;y1=-1; x2=1;y2=1 Y = 0 -2>=0 |
|
848
|
|
|
|
|
|
|
# |
|
849
|
|
|
|
|
|
|
# eg. y1=y2=y 0 < (-1-y)*(x2-x1) |
|
850
|
|
|
|
|
|
|
# (x1+1)*(y2-y1) > (y1+1)*(x2-x1) |
|
851
|
|
|
|
|
|
|
# eg. x1=x2=5 -5*(y2-y1) > (y1+1)*0 no |
|
852
|
|
|
|
|
|
|
# |
|
853
|
|
|
|
|
|
|
# | 5,-10 |
|
854
|
|
|
|
|
|
|
# /| |
|
855
|
|
|
|
|
|
|
# -----/---------- |
|
856
|
|
|
|
|
|
|
# -10,5 | |
|
857
|
|
|
|
|
|
|
# eg. x1=-10;y1=5; x2=5;y2=-10; x1*(y2-y1); (y1+1)*(x2-x1) |
|
858
|
|
|
|
|
|
|
# is 150 < 90 |
|
859
|
|
|
|
|
|
|
# |
|
860
|
|
|
|
|
|
|
# | 10,-5 |
|
861
|
|
|
|
|
|
|
# -------/----- |
|
862
|
|
|
|
|
|
|
# |/ |
|
863
|
|
|
|
|
|
|
# /| |
|
864
|
|
|
|
|
|
|
# -5,10| |
|
865
|
|
|
|
|
|
|
# eg. x1=-5;y1=10; x2=10;y2=-5; x1*(y2-y1); (y1+1)*(x2-x1) |
|
866
|
|
|
|
|
|
|
# is 75 < 165 |
|
867
|
|
|
|
|
|
|
# |
|
868
|
|
|
|
|
|
|
# eg. x1=5;y1=-10; x2=5;y2=10; x1*(y2-y1); (y1+1)*(x2-x1) |
|
869
|
|
|
|
|
|
|
# is 100 < 0 |
|
870
|
|
|
|
|
|
|
# |
|
871
|
|
|
|
|
|
|
sub _line_any_positive { |
|
872
|
|
|
|
|
|
|
my ($x1,$y1, $x2,$y2) = @_; |
|
873
|
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
# swap ends to x1 <= x2 |
|
875
|
|
|
|
|
|
|
($x1,$y1, $x2,$y2) = ($x2,$y2, $x1,$y1) if $x2 < $x1; |
|
876
|
|
|
|
|
|
|
### _line_any_positive() swapped to: "$x1, $y1, $x2, $y2" |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
return (# must have x2 positive, otherwise all X negative |
|
879
|
|
|
|
|
|
|
$x2 > -1 |
|
880
|
|
|
|
|
|
|
&& |
|
881
|
|
|
|
|
|
|
(# if y2 positive then x2,y2 end both positive so line positive |
|
882
|
|
|
|
|
|
|
$y2 > -1 |
|
883
|
|
|
|
|
|
|
|| |
|
884
|
|
|
|
|
|
|
(# else must have y1 positive, otherwise y1 and y2 both negative |
|
885
|
|
|
|
|
|
|
$y1 > -1 |
|
886
|
|
|
|
|
|
|
# now | x2,y2 | x2,y2 x2 pos, y2 neg |
|
887
|
|
|
|
|
|
|
# --------- --------- |
|
888
|
|
|
|
|
|
|
# x1,y1 | | x1,y1 x1 pos or neg, y1 pos |
|
889
|
|
|
|
|
|
|
# see if the X position corresponding to Y=0 is >= -1 |
|
890
|
|
|
|
|
|
|
&& |
|
891
|
|
|
|
|
|
|
$x1*($y2-$y1) < ($y1+1)*($x2-$x1)))); |
|
892
|
|
|
|
|
|
|
} |
|
893
|
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
# (xnew-xp)/(x-xp) = (ylo-yp)/(y-yp) |
|
895
|
|
|
|
|
|
|
# xnew-xp = (ylo-yp)/(y-yp)*(x-xp) |
|
896
|
|
|
|
|
|
|
# xnew = (ylo-yp)/(y-yp)*(x-xp) + xp |
|
897
|
|
|
|
|
|
|
# = x*(ylo-yp)/(y-yp) - xp*(ylo-yp)/(y-yp) + xp |
|
898
|
|
|
|
|
|
|
# = x*(ylo-yp)/(y-yp) + xp*(1 - (ylo-yp)/(y-yp)) |
|
899
|
|
|
|
|
|
|
# = x*(ylo-yp)/(y-yp) + xp*(((y-yp) - (ylo-yp))/(y-yp) |
|
900
|
|
|
|
|
|
|
# = [ x*(ylo-yp) + xp*(y - yp - ylo + yp) ]/(y-yp) |
|
901
|
|
|
|
|
|
|
# = [ x*(ylo-yp) + xp*(y-ylo) ]/(y-yp) |
|
902
|
|
|
|
|
|
|
# |
|
903
|
|
|
|
|
|
|
# x,y |
|
904
|
|
|
|
|
|
|
# / \ |
|
905
|
|
|
|
|
|
|
# / \ |
|
906
|
|
|
|
|
|
|
# / \ |
|
907
|
|
|
|
|
|
|
# xnew,ynew=ylo ------------------ |
|
908
|
|
|
|
|
|
|
# / \ |
|
909
|
|
|
|
|
|
|
# / \ |
|
910
|
|
|
|
|
|
|
# xprev,yprev xnext,ynext |
|
911
|
|
|
|
|
|
|
# |
|
912
|
|
|
|
|
|
|
# x,y |
|
913
|
|
|
|
|
|
|
# / \ |
|
914
|
|
|
|
|
|
|
# / __* xnext,ynext |
|
915
|
|
|
|
|
|
|
# /__-- |
|
916
|
|
|
|
|
|
|
# xnew,ynew=ylo --*--------------- |
|
917
|
|
|
|
|
|
|
# / |
|
918
|
|
|
|
|
|
|
# / |
|
919
|
|
|
|
|
|
|
# xprev,yprev |
|
920
|
|
|
|
|
|
|
# |
|
921
|
|
|
|
|
|
|
# -8,-8 7,-7 |
|
922
|
|
|
|
|
|
|
# *---- ----* |
|
923
|
|
|
|
|
|
|
# | | | | |
|
924
|
|
|
|
|
|
|
# ----* *---- |
|
925
|
|
|
|
|
|
|
# 7,7 -8,8 |
|
926
|
|
|
|
|
|
|
# |
|
927
|
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
# _convex_poly_clip() takes $aref is an arrayref of vertex coordinates |
|
929
|
|
|
|
|
|
|
# $aref = [ $x1,$y1, $x2,$y2, ..., $xn,$yn ]. |
|
930
|
|
|
|
|
|
|
# |
|
931
|
|
|
|
|
|
|
# The polygon is line segment $x1,$y1 to $x2,$y2, etc, and final |
|
932
|
|
|
|
|
|
|
# $xn,$yn back to $x1,$y1 start. |
|
933
|
|
|
|
|
|
|
# |
|
934
|
|
|
|
|
|
|
# Modify the array contents to clip the polygon to signed 16-bit. |
|
935
|
|
|
|
|
|
|
# This might either increase or decrease the total number of vertices. |
|
936
|
|
|
|
|
|
|
# If the polygon is entirely outside 16-bits then leave an empty array. |
|
937
|
|
|
|
|
|
|
# |
|
938
|
|
|
|
|
|
|
sub _convex_poly_clip { |
|
939
|
|
|
|
|
|
|
my ($aref) = @_; |
|
940
|
|
|
|
|
|
|
### _convex_poly_clip(): $aref |
|
941
|
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
foreach (1 .. 4) { # each side |
|
943
|
|
|
|
|
|
|
### side: $_ |
|
944
|
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
for (my $i = 0; $i < $#$aref && $#$aref >= 3; ) { |
|
946
|
|
|
|
|
|
|
### at: "i=$i of ".scalar(@$aref)." ".join(', ',@$aref) |
|
947
|
|
|
|
|
|
|
my $y = $aref->[$i+1]; |
|
948
|
|
|
|
|
|
|
if ($y <= _HI) { |
|
949
|
|
|
|
|
|
|
# This vertex is below the _HI limit, keep it unchanged. |
|
950
|
|
|
|
|
|
|
$i += 2; |
|
951
|
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
} else { |
|
953
|
|
|
|
|
|
|
# This vertex is outside the _HI limit, replace it by zero, one or |
|
954
|
|
|
|
|
|
|
# two new clipped points. |
|
955
|
|
|
|
|
|
|
my ($x,$y) = splice @$aref, $i,2; |
|
956
|
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
{ |
|
958
|
|
|
|
|
|
|
my $yprev = $aref->[$i-1]; # with possible wrap back to $xn,$yn |
|
959
|
|
|
|
|
|
|
if ($yprev <= _HI) { |
|
960
|
|
|
|
|
|
|
my $xprev = $aref->[$i-2]; |
|
961
|
|
|
|
|
|
|
my $xnew = int(($x*(_HI - $yprev) + $xprev*($y - _HI)) / ($y-$yprev) |
|
962
|
|
|
|
|
|
|
+ 0.5); |
|
963
|
|
|
|
|
|
|
splice @$aref, $i,0, $xnew,_HI; |
|
964
|
|
|
|
|
|
|
$i += 2; |
|
965
|
|
|
|
|
|
|
} else { |
|
966
|
|
|
|
|
|
|
# $yprev and $y both above _HI limit, so nothing for segment |
|
967
|
|
|
|
|
|
|
# $yprev to $y, just leave $yprev for the next vertex to |
|
968
|
|
|
|
|
|
|
# consider. (This case only occurs when $i==0 and so $yprev is |
|
969
|
|
|
|
|
|
|
# wrapped back to the last vertex $yn. Any later $i will have |
|
970
|
|
|
|
|
|
|
# $yprev already clipped to $yprev<=_HI.) |
|
971
|
|
|
|
|
|
|
} |
|
972
|
|
|
|
|
|
|
} |
|
973
|
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
{ |
|
975
|
|
|
|
|
|
|
my $inext = $i % scalar(@$aref); |
|
976
|
|
|
|
|
|
|
my $ynext = $aref->[$inext+1]; |
|
977
|
|
|
|
|
|
|
if ($ynext <= _HI) { |
|
978
|
|
|
|
|
|
|
my $xnext = $aref->[$inext]; |
|
979
|
|
|
|
|
|
|
my $xnew = int(($x*(_HI - $ynext) + $xnext*($y - _HI)) / ($y-$ynext) |
|
980
|
|
|
|
|
|
|
+ 0.5); |
|
981
|
|
|
|
|
|
|
splice @$aref, $i,0, $xnew,_HI; |
|
982
|
|
|
|
|
|
|
$i += 2; |
|
983
|
|
|
|
|
|
|
} else { |
|
984
|
|
|
|
|
|
|
# $y and $ynext both above _HI limit, so nothing for segment $y |
|
985
|
|
|
|
|
|
|
# to $ynext |
|
986
|
|
|
|
|
|
|
} |
|
987
|
|
|
|
|
|
|
} |
|
988
|
|
|
|
|
|
|
} |
|
989
|
|
|
|
|
|
|
} |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
# rotate 90 |
|
992
|
|
|
|
|
|
|
for (my $i = 0; $i < $#$aref; $i += 2) { |
|
993
|
|
|
|
|
|
|
($aref->[$i],$aref->[$i+1]) = ($aref->[$i+1], -1 - $aref->[$i]); |
|
994
|
|
|
|
|
|
|
} |
|
995
|
|
|
|
|
|
|
} |
|
996
|
|
|
|
|
|
|
if (@$aref == 2) { |
|
997
|
|
|
|
|
|
|
@$aref = (); |
|
998
|
|
|
|
|
|
|
} |
|
999
|
|
|
|
|
|
|
} |
|
1000
|
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
1; |
|
1003
|
|
|
|
|
|
|
__END__ |