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