1
13693261870
2022-09-16 06df9667ad1465622bf0e423dc3840ef9f93c725
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package websocket.drawboard;
 
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Arc2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
 
/**
 * A message that represents a drawing action.
 * Note that we use primitive types instead of Point, Color etc.
 * to reduce object allocation.<br><br>
 *
 * TODO: But a Color objects needs to be created anyway for drawing this
 * onto a Graphics2D object, so this probably does not save much.
 */
public final class DrawMessage {
 
    private int type;
    private byte colorR, colorG, colorB, colorA;
    private double thickness;
    private double x1, y1, x2, y2;
 
    /**
     * The type.
     *
     * @return 1: Brush<br>2: Line<br>3: Rectangle<br>4: Ellipse
     */
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }
 
    public double getThickness() {
        return thickness;
    }
    public void setThickness(double thickness) {
        this.thickness = thickness;
    }
 
    public byte getColorR() {
        return colorR;
    }
    public void setColorR(byte colorR) {
        this.colorR = colorR;
    }
    public byte getColorG() {
        return colorG;
    }
    public void setColorG(byte colorG) {
        this.colorG = colorG;
    }
    public byte getColorB() {
        return colorB;
    }
    public void setColorB(byte colorB) {
        this.colorB = colorB;
    }
    public byte getColorA() {
        return colorA;
    }
    public void setColorA(byte colorA) {
        this.colorA = colorA;
    }
 
    public double getX1() {
        return x1;
    }
    public void setX1(double x1) {
        this.x1 = x1;
    }
    public double getX2() {
        return x2;
    }
    public void setX2(double x2) {
        this.x2 = x2;
    }
    public double getY1() {
        return y1;
    }
    public void setY1(double y1) {
        this.y1 = y1;
    }
    public double getY2() {
        return y2;
    }
    public void setY2(double y2) {
        this.y2 = y2;
    }
 
 
    public DrawMessage(int type, byte colorR, byte colorG, byte colorB,
            byte colorA, double thickness, double x1, double x2, double y1,
            double y2) {
 
        this.type = type;
        this.colorR = colorR;
        this.colorG = colorG;
        this.colorB = colorB;
        this.colorA = colorA;
        this.thickness = thickness;
        this.x1 = x1;
        this.x2 = x2;
        this.y1 = y1;
        this.y2 = y2;
    }
 
 
    /**
     * Draws this DrawMessage onto the given Graphics2D.
     *
     * @param g The target for the DrawMessage
     */
    public void draw(Graphics2D g) {
 
        g.setStroke(new BasicStroke((float) thickness,
                BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
        g.setColor(new Color(colorR & 0xFF, colorG & 0xFF, colorB & 0xFF,
                colorA & 0xFF));
 
        if (x1 == x2 && y1 == y2) {
            // Always draw as arc to meet the behavior in the HTML5 Canvas.
            Arc2D arc = new Arc2D.Double(x1, y1, 0, 0,
                    0d, 360d, Arc2D.OPEN);
            g.draw(arc);
 
        } else if (type == 1 || type == 2) {
            // Draw a line.
            Line2D line = new Line2D.Double(x1, y1, x2, y2);
            g.draw(line);
 
        } else if (type == 3 || type == 4) {
            double x1 = this.x1, x2 = this.x2,
                    y1 = this.y1, y2 = this.y2;
            if (x1 > x2) {
                x1 = this.x2;
                x2 = this.x1;
            }
            if (y1 > y2) {
                y1 = this.y2;
                y2 = this.y1;
            }
 
            // TODO: If (x1 == x2 || y1 == y2) draw as line.
 
            if (type == 3) {
                // Draw a rectangle.
                Rectangle2D rect = new Rectangle2D.Double(x1, y1,
                        x2 - x1, y2 - y1);
                g.draw(rect);
 
            } else if (type == 4) {
                // Draw an ellipse.
                Arc2D arc = new Arc2D.Double(x1, y1, x2 - x1, y2 - y1,
                        0d, 360d, Arc2D.OPEN);
                g.draw(arc);
 
            }
        }
    }
 
    /**
     * Converts this message into a String representation that
     * can be sent over WebSocket.<br>
     * Since a DrawMessage consists only of numbers,
     * we concatenate those numbers with a ",".
     */
    @Override
    public String toString() {
 
        return type + "," + (colorR & 0xFF) + "," + (colorG & 0xFF) + ","
                + (colorB & 0xFF) + "," + (colorA & 0xFF) + "," + thickness
                + "," + x1 + "," + y1 + "," + x2 + "," + y2;
    }
 
    public static DrawMessage parseFromString(String str)
            throws ParseException {
 
        int type;
        byte[] colors = new byte[4];
        double thickness;
        double[] coords = new double[4];
 
        try {
            String[] elements = str.split(",");
 
            type = Integer.parseInt(elements[0]);
            if (!(type >= 1 && type <= 4)) {
                throw new ParseException("Invalid type: " + type);
            }
 
            for (int i = 0; i < colors.length; i++) {
                colors[i] = (byte) Integer.parseInt(elements[1 + i]);
            }
 
            thickness = Double.parseDouble(elements[5]);
            if (Double.isNaN(thickness) || thickness < 0 || thickness > 100) {
                throw new ParseException("Invalid thickness: " + thickness);
            }
 
            for (int i = 0; i < coords.length; i++) {
                coords[i] = Double.parseDouble(elements[6 + i]);
                if (Double.isNaN(coords[i])) {
                    throw new ParseException("Invalid coordinate: "
                            + coords[i]);
                }
            }
 
        } catch (RuntimeException ex) {
            throw new ParseException(ex);
        }
 
        DrawMessage m = new DrawMessage(type, colors[0], colors[1],
                colors[2], colors[3], thickness, coords[0], coords[2],
                coords[1], coords[3]);
 
        return m;
    }
 
    public static class ParseException extends Exception {
        private static final long serialVersionUID = -6651972769789842960L;
 
        public ParseException(Throwable root) {
            super(root);
        }
 
        public ParseException(String message) {
            super(message);
        }
    }
 
 
 
}