1 /*
2 * Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
3 * Copyright (c) 2011 Lukáš Tvrdý <lukast.dev@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This library 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
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "kis_dynamic_sensor.h"
21 #include <QDomElement>
22
23 #include "kis_algebra_2d.h"
24
25 #include "sensors/kis_dynamic_sensors.h"
26 #include "sensors/kis_dynamic_sensor_distance.h"
27 #include "sensors/kis_dynamic_sensor_drawing_angle.h"
28 #include "sensors/kis_dynamic_sensor_time.h"
29 #include "sensors/kis_dynamic_sensor_fade.h"
30 #include "sensors/kis_dynamic_sensor_fuzzy.h"
31
KisDynamicSensor(DynamicSensorType type)32 KisDynamicSensor::KisDynamicSensor(DynamicSensorType type)
33 : m_length(-1)
34 , m_type(type)
35 , m_customCurve(false)
36 , m_active(false)
37 {
38 }
39
~KisDynamicSensor()40 KisDynamicSensor::~KisDynamicSensor()
41 {
42 }
43
createConfigurationWidget(QWidget * parent,QWidget *)44 QWidget* KisDynamicSensor::createConfigurationWidget(QWidget* parent, QWidget*)
45 {
46 Q_UNUSED(parent);
47 return 0;
48 }
49
reset()50 void KisDynamicSensor::reset()
51 {
52 }
53
id2Sensor(const KoID & id,const QString & parentOptionName)54 KisDynamicSensorSP KisDynamicSensor::id2Sensor(const KoID& id, const QString &parentOptionName)
55 {
56 if (id.id() == PressureId.id()) {
57 return new KisDynamicSensorPressure();
58 }
59 else if (id.id() == PressureInId.id()) {
60 return new KisDynamicSensorPressureIn();
61 }
62 else if (id.id() == XTiltId.id()) {
63 return new KisDynamicSensorXTilt();
64 }
65 else if (id.id() == YTiltId.id()) {
66 return new KisDynamicSensorYTilt();
67 }
68 else if (id.id() == TiltDirectionId.id()) {
69 return new KisDynamicSensorTiltDirection();
70 }
71 else if (id.id() == TiltElevationId.id()) {
72 return new KisDynamicSensorTiltElevation();
73 }
74 else if (id.id() == SpeedId.id()) {
75 return new KisDynamicSensorSpeed();
76 }
77 else if (id.id() == DrawingAngleId.id()) {
78 return new KisDynamicSensorDrawingAngle();
79 }
80 else if (id.id() == RotationId.id()) {
81 return new KisDynamicSensorRotation();
82 }
83 else if (id.id() == DistanceId.id()) {
84 return new KisDynamicSensorDistance();
85 }
86 else if (id.id() == TimeId.id()) {
87 return new KisDynamicSensorTime();
88 }
89 else if (id.id() == FuzzyPerDabId.id()) {
90 return new KisDynamicSensorFuzzy(false, parentOptionName);
91 }
92 else if (id.id() == FuzzyPerStrokeId.id()) {
93 return new KisDynamicSensorFuzzy(true, parentOptionName);
94 }
95 else if (id.id() == FadeId.id()) {
96 return new KisDynamicSensorFade();
97 }
98 else if (id.id() == PerspectiveId.id()) {
99 return new KisDynamicSensorPerspective();
100 }
101 else if (id.id() == TangentialPressureId.id()) {
102 return new KisDynamicSensorTangentialPressure();
103 }
104 dbgPlugins << "Unknown transform parameter :" << id.id();
105 return 0;
106 }
107
id2Type(const KoID & id)108 DynamicSensorType KisDynamicSensor::id2Type(const KoID &id)
109 {
110 if (id.id() == PressureId.id()) {
111 return PRESSURE;
112 }
113 else if (id.id() == PressureInId.id()) {
114 return PRESSURE_IN;
115 }
116 else if (id.id() == XTiltId.id()) {
117 return XTILT;
118 }
119 else if (id.id() == YTiltId.id()) {
120 return YTILT;
121 }
122 else if (id.id() == TiltDirectionId.id()) {
123 return TILT_DIRECTION;
124 }
125 else if (id.id() == TiltElevationId.id()) {
126 return TILT_ELEVATATION;
127 }
128 else if (id.id() == SpeedId.id()) {
129 return SPEED;
130 }
131 else if (id.id() == DrawingAngleId.id()) {
132 return ANGLE;
133 }
134 else if (id.id() == RotationId.id()) {
135 return ROTATION;
136 }
137 else if (id.id() == DistanceId.id()) {
138 return DISTANCE;
139 }
140 else if (id.id() == TimeId.id()) {
141 return TIME;
142 }
143 else if (id.id() == FuzzyPerDabId.id()) {
144 return FUZZY_PER_DAB;
145 }
146 else if (id.id() == FuzzyPerStrokeId.id()) {
147 return FUZZY_PER_STROKE;
148 }
149 else if (id.id() == FadeId.id()) {
150 return FADE;
151 }
152 else if (id.id() == PerspectiveId.id()) {
153 return PERSPECTIVE;
154 }
155 else if (id.id() == TangentialPressureId.id()) {
156 return TANGENTIAL_PRESSURE;
157 }
158 return UNKNOWN;
159 }
160
type2Sensor(DynamicSensorType sensorType,const QString & parentOptionName)161 KisDynamicSensorSP KisDynamicSensor::type2Sensor(DynamicSensorType sensorType, const QString &parentOptionName)
162 {
163 switch (sensorType) {
164 case FUZZY_PER_DAB:
165 return new KisDynamicSensorFuzzy(false, parentOptionName);
166 case FUZZY_PER_STROKE:
167 return new KisDynamicSensorFuzzy(true, parentOptionName);
168 case SPEED:
169 return new KisDynamicSensorSpeed();
170 case FADE:
171 return new KisDynamicSensorFade();
172 case DISTANCE:
173 return new KisDynamicSensorDistance();
174 case TIME:
175 return new KisDynamicSensorTime();
176 case ANGLE:
177 return new KisDynamicSensorDrawingAngle();
178 case ROTATION:
179 return new KisDynamicSensorRotation();
180 case PRESSURE:
181 return new KisDynamicSensorPressure();
182 case XTILT:
183 return new KisDynamicSensorXTilt();
184 case YTILT:
185 return new KisDynamicSensorYTilt();
186 case TILT_DIRECTION:
187 return new KisDynamicSensorTiltDirection();
188 case TILT_ELEVATATION:
189 return new KisDynamicSensorTiltElevation();
190 case PERSPECTIVE:
191 return new KisDynamicSensorPerspective();
192 case TANGENTIAL_PRESSURE:
193 return new KisDynamicSensorTangentialPressure();
194 case PRESSURE_IN:
195 return new KisDynamicSensorPressureIn();
196 default:
197 return 0;
198 }
199 }
200
minimumLabel(DynamicSensorType sensorType)201 QString KisDynamicSensor::minimumLabel(DynamicSensorType sensorType)
202 {
203 switch (sensorType) {
204 case FUZZY_PER_DAB:
205 case FUZZY_PER_STROKE:
206 return QString();
207 case FADE:
208 return i18n("0");
209 case DISTANCE:
210 return i18n("0 px");
211 case TIME:
212 return i18n("0 s");
213 case ANGLE:
214 return i18n("0°");
215 case SPEED:
216 return i18n("Slow");
217 case ROTATION:
218 return i18n("0°");
219 case PRESSURE:
220 return i18n("Low");
221 case XTILT:
222 return i18n("-30°");
223 case YTILT:
224 return i18n("-30°");
225 case TILT_DIRECTION:
226 return i18n("0°");
227 case TILT_ELEVATATION:
228 return i18n("90°");
229 case PERSPECTIVE:
230 return i18n("Far");
231 case TANGENTIAL_PRESSURE:
232 case PRESSURE_IN:
233 return i18n("Low");
234 default:
235 return i18n("0.0");
236 }
237 }
238
maximumLabel(DynamicSensorType sensorType,int max)239 QString KisDynamicSensor::maximumLabel(DynamicSensorType sensorType, int max)
240 {
241 switch (sensorType) {
242 case FUZZY_PER_DAB:
243 case FUZZY_PER_STROKE:
244 return QString();
245 case FADE:
246 if (max < 0)
247 return i18n("1000");
248 else
249 return i18n("%1", max);
250 case DISTANCE:
251 if (max < 0)
252 return i18n("30 px");
253 else
254 return i18n("%1 px", max);
255 case TIME:
256 if (max < 0)
257 return i18n("3 s");
258 else
259 return i18n("%1 s", max / 1000);
260 case ANGLE:
261 return i18n("360°");
262 case SPEED:
263 return i18n("Fast");
264 case ROTATION:
265 return i18n("360°");
266 case PRESSURE:
267 return i18n("High");
268 case XTILT:
269 return i18n("30°");
270 case YTILT:
271 return i18n("30°");
272 case TILT_DIRECTION:
273 return i18n("360°");
274 case TILT_ELEVATATION:
275 return i18n("0°");
276 case PERSPECTIVE:
277 return i18n("Near");
278 case TANGENTIAL_PRESSURE:
279 case PRESSURE_IN:
280 return i18n("High");
281 default:
282 return i18n("1.0");
283 };
284 }
285
minimumValue(DynamicSensorType sensorType)286 int KisDynamicSensor::minimumValue(DynamicSensorType sensorType)
287 {
288 switch (sensorType) {
289 case FUZZY_PER_DAB:
290 case FUZZY_PER_STROKE:
291 case FADE:
292 case DISTANCE:
293 case TIME:
294 case ANGLE:
295 case SPEED:
296 case ROTATION:
297 case PRESSURE:
298 case TILT_DIRECTION:
299 case PERSPECTIVE:
300 case PRESSURE_IN:
301 return 0;
302 case XTILT:
303 case YTILT:
304 return -30;
305 case TILT_ELEVATATION:
306 return 90;
307 case TANGENTIAL_PRESSURE:
308 default:
309 return 0;
310 }
311
312 }
313
maximumValue(DynamicSensorType sensorType,int max)314 int KisDynamicSensor::maximumValue(DynamicSensorType sensorType, int max)
315 {
316 switch (sensorType) {
317 case FUZZY_PER_DAB:
318 case FUZZY_PER_STROKE:
319 case SPEED:
320 case PERSPECTIVE:
321 case TANGENTIAL_PRESSURE:
322 case PRESSURE_IN:
323 case PRESSURE:
324 return 100;
325 case FADE:
326 if (max < 0) {
327 return 1000;
328 } else {
329 return max;
330 }
331 case DISTANCE:
332 if (max < 0) {
333 return 30;
334 } else {
335 return max;
336 }
337 case TIME:
338 if (max < 0) {
339 return 3000;
340 } else {
341 return max;
342 }
343 case ANGLE:
344 case ROTATION:
345 case TILT_DIRECTION:
346 return 360;
347 case XTILT:
348 case YTILT:
349 return 30;
350 case TILT_ELEVATATION:
351 return 0;
352 default:
353 return 100;
354 };
355 }
356
valueSuffix(DynamicSensorType sensorType)357 QString KisDynamicSensor::valueSuffix(DynamicSensorType sensorType)
358 {
359 switch (sensorType) {
360 case FUZZY_PER_DAB:
361 case FUZZY_PER_STROKE:
362 case SPEED:
363 case PRESSURE:
364 case PERSPECTIVE:
365 case TANGENTIAL_PRESSURE:
366 case PRESSURE_IN:
367 return i18n("%");
368 case FADE:
369 return QString();
370 case DISTANCE:
371 return i18n(" px");
372 case TIME:
373 return i18n(" ms");
374 case ANGLE:
375 case ROTATION:
376 case XTILT:
377 case YTILT:
378 case TILT_DIRECTION:
379 case TILT_ELEVATATION:
380 return i18n("°");
381 default:
382 return i18n("%");
383 };
384 }
385
createFromXML(const QString & s,const QString & parentOptionName)386 KisDynamicSensorSP KisDynamicSensor::createFromXML(const QString& s, const QString &parentOptionName)
387 {
388 QDomDocument doc;
389 doc.setContent(s);
390 QDomElement e = doc.documentElement();
391 return createFromXML(e, parentOptionName);
392 }
393
createFromXML(const QDomElement & e,const QString & parentOptionName)394 KisDynamicSensorSP KisDynamicSensor::createFromXML(const QDomElement& e, const QString &parentOptionName)
395 {
396 QString id = e.attribute("id", "");
397 KisDynamicSensorSP sensor = id2Sensor(id, parentOptionName);
398 if (sensor) {
399 sensor->fromXML(e);
400 }
401 return sensor;
402 }
403
sensorsIds()404 QList<KoID> KisDynamicSensor::sensorsIds()
405 {
406 QList<KoID> ids;
407
408 ids << PressureId
409 << PressureInId
410 << XTiltId
411 << YTiltId
412 << TiltDirectionId
413 << TiltElevationId
414 << SpeedId
415 << DrawingAngleId
416 << RotationId
417 << DistanceId
418 << TimeId
419 << FuzzyPerDabId
420 << FuzzyPerStrokeId
421 << FadeId
422 << PerspectiveId
423 << TangentialPressureId;
424
425 return ids;
426 }
427
sensorsTypes()428 QList<DynamicSensorType> KisDynamicSensor::sensorsTypes()
429 {
430 QList<DynamicSensorType> sensorTypes;
431 sensorTypes
432 << PRESSURE
433 << PRESSURE_IN
434 << XTILT
435 << YTILT
436 << TILT_DIRECTION
437 << TILT_ELEVATATION
438 << SPEED
439 << ANGLE
440 << ROTATION
441 << DISTANCE
442 << TIME
443 << FUZZY_PER_DAB
444 << FUZZY_PER_STROKE
445 << FADE
446 << PERSPECTIVE
447 << TANGENTIAL_PRESSURE;
448 return sensorTypes;
449 }
450
id(DynamicSensorType sensorType)451 QString KisDynamicSensor::id(DynamicSensorType sensorType)
452 {
453 switch (sensorType) {
454 case FUZZY_PER_DAB:
455 return "fuzzy";
456 case FUZZY_PER_STROKE:
457 return "fuzzystroke";
458 case FADE:
459 return "fade";
460 case DISTANCE:
461 return "distance";
462 case TIME:
463 return "time";
464 case ANGLE:
465 return "drawingangle";
466 case SPEED:
467 return "speed";
468 case ROTATION:
469 return "rotation";
470 case PRESSURE:
471 return "pressure";
472 case XTILT:
473 return "xtilt";
474 case YTILT:
475 return "ytilt";
476 case TILT_DIRECTION:
477 return "ascension";
478 case TILT_ELEVATATION:
479 return "declination";
480 case PERSPECTIVE:
481 return "perspective";
482 case TANGENTIAL_PRESSURE:
483 return "tangentialpressure";
484 case PRESSURE_IN:
485 return "pressurein";
486 case SENSORS_LIST:
487 return "sensorslist";
488 default:
489 return QString();
490 };
491 }
492
493
toXML(QDomDocument & doc,QDomElement & elt) const494 void KisDynamicSensor::toXML(QDomDocument& doc, QDomElement& elt) const
495 {
496 elt.setAttribute("id", id(sensorType()));
497 if (m_customCurve) {
498 QDomElement curve_elt = doc.createElement("curve");
499 QDomText text = doc.createTextNode(m_curve.toString());
500 curve_elt.appendChild(text);
501 elt.appendChild(curve_elt);
502 }
503 }
504
fromXML(const QDomElement & e)505 void KisDynamicSensor::fromXML(const QDomElement& e)
506 {
507 Q_ASSERT(e.attribute("id", "") == id(sensorType()));
508 m_customCurve = false;
509 QDomElement curve_elt = e.firstChildElement("curve");
510 if (!curve_elt.isNull()) {
511 m_customCurve = true;
512 m_curve.fromString(curve_elt.text());
513 }
514 }
515
parameter(const KisPaintInformation & info)516 qreal KisDynamicSensor::parameter(const KisPaintInformation& info)
517 {
518 return parameter(info, m_curve, m_customCurve);
519 }
520
parameter(const KisPaintInformation & info,const KisCubicCurve curve,const bool customCurve)521 qreal KisDynamicSensor::parameter(const KisPaintInformation& info, const KisCubicCurve curve, const bool customCurve)
522 {
523 const qreal val = value(info);
524 if (customCurve) {
525 qreal scaledVal = isAdditive() ? additiveToScaling(val) : val;
526
527 const QVector<qreal> transfer = curve.floatTransfer(256);
528 scaledVal = KisCubicCurve::interpolateLinear(scaledVal, transfer);
529
530 return isAdditive() ? scalingToAdditive(scaledVal) : scaledVal;
531 }
532 else {
533 return val;
534 }
535 }
536
setCurve(const KisCubicCurve & curve)537 void KisDynamicSensor::setCurve(const KisCubicCurve& curve)
538 {
539 m_customCurve = true;
540 m_curve = curve;
541 }
542
curve() const543 const KisCubicCurve& KisDynamicSensor::curve() const
544 {
545 return m_curve;
546 }
547
removeCurve()548 void KisDynamicSensor::removeCurve()
549 {
550 m_customCurve = false;
551 }
552
hasCustomCurve() const553 bool KisDynamicSensor::hasCustomCurve() const
554 {
555 return m_customCurve;
556 }
557
dependsOnCanvasRotation() const558 bool KisDynamicSensor::dependsOnCanvasRotation() const
559 {
560 return true;
561 }
562
isAdditive() const563 bool KisDynamicSensor::isAdditive() const
564 {
565 return false;
566 }
567
isAbsoluteRotation() const568 bool KisDynamicSensor::isAbsoluteRotation() const
569 {
570 return false;
571 }
572
setActive(bool active)573 void KisDynamicSensor::setActive(bool active)
574 {
575 m_active = active;
576 }
577
isActive() const578 bool KisDynamicSensor::isActive() const
579 {
580 return m_active;
581 }
582