* Bug 14544 fixed: scatter and scatter3 canceled upstream drawlater
[scilab.git] / scilab / modules / graphics / macros / scatter3.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) Scilab Enterprises - 2015 - 2012 - Juergen Koch <juergen.koch@hs-esslingen.de>
3 //
4 // Copyright (C) 2012 - 2016 - Scilab Enterprises
5 //
6 // This file is hereby licensed under the terms of the GNU GPL v2.0,
7 // pursuant to article 5.3.4 of the CeCILL v.2.1.
8 // This file was originally licensed under the terms of the CeCILL v2.1,
9 // and continues to be available under such terms.
10 // For more information, see the COPYING file which you should have received
11 // along with this program.
12
13 function polyLine = scatter3(varargin)
14
15     polyLine = 0;
16     [lhs,rhs] = argn(0);
17
18     if ~rhs
19         clf;
20         z = linspace(0,25,200);
21         x = z.*cos(z);
22         y = z.*sin(z);
23         polyLine = scatter3(x,y,z,z,z,"fill","markerEdgeColor","darkblue");
24         set(gca(),"rotation_angles",[60,45])
25         return;
26     end
27
28    //detect and set the current axes now:
29     if type(varargin(1)) == 9 then // graphic handle
30         hdle = varargin(1);
31         if hdle.type == "Axes" then
32             if size(varargin) < 4 then
33                 warning("Not enough input arguments.")
34                 return;
35             else
36                 axesHandle = varargin(1);
37                 X = varargin(2);
38                 Y = varargin(3);
39                 Z = varargin(4);
40                 nextArgin = 5;
41             end
42         else
43             warning("Handle should be an Axes handle.")
44             return;
45         end
46     else
47         if size(varargin) < 3 then
48             warning("Not enough input arguments.")
49             return;
50         else
51             axesHandle = [];
52             X = varargin(1);
53             Y = varargin(2);
54             Z = varargin(3);
55             nextArgin = 4;
56         end
57     end
58
59     if (isempty(X) & isempty(Y) & isempty(Z)) then
60         // nothing has to be done
61         return;
62     end
63
64     if ( isempty(Z) ) then
65         if (~isvector(X) | ~isvector(Y) | size(X) ~= size(Y)) then
66             warning("X and Y must be vectors of the same length.")
67             return;
68         end
69     else
70         if (~isvector(X) | ~isvector(Y) | ~isvector(Z) | or(size(X) ~= size(Y)) | or(size(X) ~= size(Z))) then
71             warning("X, Y and Z must be vectors of the same length.")
72             return;
73         end
74     end
75
76     n = length(X);
77     [S,C,thickness,markStyle,markFg,markBg,fill,scanFailed] = scatterScanVargin(varargin,nextArgin,n);
78     if (scanFailed) then
79         return;
80     end
81
82     f = gcf();
83     old_drawing_mode = f.immediate_drawing;
84     f.immediate_drawing = "off";
85
86     if isempty(Z) then
87         if isempty(axesHandle) then
88             plot(X,Y);
89         else
90             plot(axesHandle,X,Y);
91         end
92         currentEntity = gce();
93         polyLine = currentEntity.children;
94     else
95         if isempty(axesHandle) then
96             param3d(X,Y,Z);
97         else
98             set("current_axes",axesHandle)
99             param3d(X,Y,Z);
100         end
101         polyLine = gce();
102     end
103
104     if polyLine.Type <> "Polyline" then
105         warning("Handle should be a Polyline handle.");
106     else
107         scatterSetPolyline(polyLine,S,C,thickness,markStyle,markFg,markBg,fill);
108
109         if ~isempty(Z) then
110             set(gca(),"cube_scaling","on");
111             set(gca(),"grid",[1 1 1]);
112         end
113     end
114
115     f.immediate_drawing = old_drawing_mode;
116 endfunction
117
118 function [S,C,thickness,markStyle,markFg,markBg,fill,scanFailed] = scatterScanVargin(argins,nextArgin,n)
119
120     scanFailed = %F;
121
122     // check for size argument
123     S = [];
124     if  size(argins) >= nextArgin then
125         if isempty(argins(nextArgin)) then
126             nextArgin = nextArgin + 1;
127         else
128             if type(argins(nextArgin)) == 1 then
129                 [n1,n2] = size(argins(nextArgin));
130                 if (n1 == 1 & n2 == 1) | (n1 == n & n2 == 1) | (n1 == 1 & n2 == n) then
131                     S = argins(nextArgin);
132                     if iscolumn(S) then
133                         S = S.';
134                     end
135                     nextArgin = nextArgin + 1;
136                 else
137                     warning("S must be a scalar or a vector of the same length as X.");
138                     scanFailed = %T;
139                     return;
140                 end
141             end
142         end
143     end
144
145     // check for color argument
146     C = [];
147     if  size(argins) >= nextArgin then
148         if isempty(argins(nextArgin)) then
149             nextArgin = nextArgin + 1;
150         else
151             [n1,n2] = size(argins(nextArgin));
152             if type(argins(nextArgin)) == 1 then
153                 if (n1 == n & n2 == 1) | (n1 == 1 & n2 == n) then
154                     C = scatterLinearColorMap(argins(nextArgin));
155                     nextArgin = nextArgin + 1;
156                 elseif n1 == n & n2 == 3 then
157                     C = addcolor(argins(nextArgin));
158                     nextArgin = nextArgin + 1;
159                 else
160                     warning("C must be a vector or a matrix of the same length as X.");
161                     scanFailed = %T;
162                     return;
163                 end
164                 if iscolumn(C) then
165                     C = C.';
166                 end
167             elseif type(argins(nextArgin)) == 10 then
168                 if n1 == 1 & n2 == 1 then
169                     // check if string specifies a color
170                     colorRGB = name2rgb(argins(nextArgin));
171                     if ~isempty(colorRGB) then
172                         C = addcolor(colorRGB/255);
173                         nextArgin = nextArgin + 1;
174                     end
175                 elseif (n1 == n & n2 == 1) | (n1 == 1 & n2 == n) then
176                     C = addcolor(name2rgb(argins(nextArgin))/255);
177                     if isempty(C) then
178                         warning("Wrong color specified.");
179                         scanFailed = %T;
180                         return;
181                     else
182                          nextArgin = nextArgin + 1;
183                     end
184                 end
185             end
186         end
187     end
188
189     // check for "fill" argument
190     fill = %F;
191     if  size(argins) >= nextArgin then
192         if type(argins(nextArgin)) == 10 then
193             if argins(nextArgin) == "fill" then
194                 fill = %T;
195                 nextArgin = nextArgin + 1;
196             end
197         end
198     end
199
200     // check for marker argument
201     markStyle = 9; // default circle
202     if  size(argins) >= nextArgin then
203         if type(argins(nextArgin)) == 10 then
204             ms = getMarkStyle(argins(nextArgin));
205             if ms >= 0 & ms <= 14 then
206                 markStyle = ms;
207                 nextArgin = nextArgin + 1;
208             end
209         end
210     end
211
212     // check for property-value pairs
213     markFg = -1;
214     markBg = -1;
215     thickness = 1.0; // default
216     while  size(argins) >= nextArgin do
217         if size(argins) == nextArgin then
218             warning("Incorrect number of inputs for property-value pairs.");
219             scanFailed = %T;
220             return;
221         else
222             select argins(nextArgin)
223             case "marker"
224                 markStyle = getMarkStyle(argins(nextArgin+1));
225                 if markStyle == -1 then
226                     warning(strcat([argins(nextArgin+1) " is not a valid value for property marker."]));
227                     scanFailed = %T;
228                     return;
229                 end
230             case "markerStyle"
231                 markStyle = getMarkStyle(argin(nextArgin+1));
232                 if markStyle == -1 then
233                     warning(strcat([argins(nextArgin+1) " is not a valid value for property markerStyle."]));
234                     scanFailed = %T;
235                     return;
236                 end
237             case "markerEdgeColor"
238                 markFg = colorIndex(argins(nextArgin+1));
239                 if markFg == -1 then
240                     warning(strcat([argins(nextArgin+1) " is not a valid value for property markerEdgeColor."]));
241                     scanFailed = %T;
242                     return;
243                 end;
244             case "markerForeground"
245                 markFg = colorIndex(argins(nextArgin+1));
246                 if markFg == -1 then
247                     warning(strcat([argins(nextArgin+1) " is not a valid value for property markerForeground."]));
248                     scanFailed = %T;
249                     return;
250                 end;
251             case "markerFaceColor"
252                 fill = %T;
253                 markBg = colorIndex(argins(nextArgin+1));
254                 if markBg == -1 then
255                     warning(strcat([argins(nextArgin+1) " is not a valid value for property markerFaceColor."]));
256                     scanFailed = %T;
257                     return;
258                 end;
259             case "markerBackground"
260                 fill = %T;
261                 markBg = colorIndex(argins(nextArgin+1));
262                 if markBg == -1 then
263                     warning(strcat([argins(nextArgin+1) " is not a valid value for property markerBackground."]));
264                     scanFailed = %T;
265                     return;
266                 end;
267             case "linewidth"
268                 if type(argins(nextArgin+1)) == 1 then
269                     thickness = argins(nextArgin+1);
270                 else
271                     warning(strcat([argins(nextArgin+1) " is not a valid value for property linewidth."]));
272                     scanFailed = %T;
273                     return;
274                 end
275             case "thickness"
276                 if type(argins(nextArgin+1)) == 1 then
277                     thickness = argins(nextArgin+1);
278                 else
279                     warning(strcat([argins(nextArgin+1) " is not a valid value for property thickness."]));
280                     scanFailed = %T;
281                     return;
282                 end
283             else
284                 warning(strcat(["There is no " argins(nextArgin) " property on the Scatter class."]));
285                 scanFailed = %T;
286                 return;
287             end
288         end
289         nextArgin = nextArgin + 2;
290     end
291
292 endfunction
293
294 function colorInd = colorIndex(colorSpec)
295     colorInd = -1;
296     if type(colorSpec) == 10 & size(colorSpec) == [1 1] then
297         colorRGB = name2rgb(colorSpec);
298         if ~isempty(colorRGB) then
299             colorInd = addcolor(colorRGB/255);
300             return;
301         end
302     elseif type(colorSpec) == 1 & (size(colorSpec) == [1 3] | size(colorSpec) == [3 1]) then
303         colorInd = addcolor(colorSpec);
304         return;
305     end
306     warning("Specified string is an invalid color value.");
307 endfunction
308
309 function markStyle = getMarkStyle(name)
310     if type(name) ~= 10 then
311         markStyle = -1;
312     else
313         select name
314         case "."
315             markStyle = 0;
316         case "+"
317             markStyle = 1;
318         case "x"
319             markStyle = 2;
320         case "circle plus"
321             markStyle = 3;
322         case "filled diamond"
323             markStyle = 4;
324         case "d"
325             markStyle = 5;
326         case "diamond"
327             markStyle = 5;
328         case "^"
329             markStyle = 6;
330         case "v"
331             markStyle = 7;
332         case "diamond plus"
333             markStyle = 8;
334         case "o"
335             markStyle = 9;
336         case "*"
337             markStyle = 10;
338         case "s"
339             markStyle = 11;
340         case "square"
341             markStyle = 11;
342         case ">"
343             markStyle = 12;
344         case "<"
345             markStyle = 13;
346         case "p"
347             markStyle = 14;
348         case "pentagram"
349             markStyle = 14;
350         else
351             markStyle = -1;
352         end
353     end
354 endfunction
355
356 function colorIndex = scatterLinearColorMap(colorValue)
357     cMin = min(colorValue);
358     cMax = max(colorValue);
359     cmap = get(gcf(),"color_map");
360     numColors = size(cmap,1);
361     if (cMax-cMin > %eps) then
362         colorIndex = (numColors-1)*(colorValue - cMin)/(cMax - cMin) + 1;
363     else
364         colorIndex = 1; // default color index
365     end
366 endfunction
367
368 function scatterSetPolyline(polyLine,S,C,thickness,markStyle,markFg,markBg,fill)
369
370     // set mark mode
371     polyLine.line_mode = "off";
372     polyLine.mark_mode = "on";
373
374     // set thickness
375     polyLine.thickness = thickness;
376
377     // set mark style
378     polyLine.mark_style = markStyle;
379
380     // set mark size
381     polyLine.mark_size_unit = "point";
382     if isempty(S) then
383         polyLine.mark_size = 7;
384     else
385         if size(S) == [1 1] | size(S) == [1 n]
386             polyLine.mark_size = ceil(sqrt(4*S/%pi));
387         else
388             warning("S must be a scalar or a vector of the same length as X.");
389             return;
390         end
391     end
392
393     // set mark foreground and background color
394     if isempty(C) then
395         if markFg == -1 then
396             markFg = addcolor(name2rgb("blue")/255); // default
397         end
398         polyLine.mark_foreground = markFg;
399         if markBg == -1 then
400             markBg = markFg;
401         end
402         if fill == %T then
403             polyLine.mark_background = markBg;
404         else
405             polyLine.mark_background = 0; // transparent
406         end
407      else
408         if size(C) == [1 1] then
409             polyLine.mark_foreground = C;
410             if fill == %T then
411                 polyLine.mark_background = C;
412             else
413                 if markBg == -1 then
414                     polyLine.mark_background = 0; // transparent
415                 else
416                     polyLine.mark_background = markBg;
417                 end
418             end
419         else
420             if fill == %T then
421                 if markFg == -1 then
422                     polyLine.mark_foreground = C; // transparent
423                 else
424                     polyLine.mark_foreground = markFg;
425                 end
426                 polyLine.mark_background = C;
427             else
428                 polyLine.mark_foreground = C;
429                 if markBg == -1 then
430                     polyLine.mark_background = 0; // transparent
431                 else
432                     polyLine.mark_background = markBg;
433                 end
434             end
435         end
436     end
437
438 endfunction