282
286
// calculate the bbox of the item
283
287
sp_document_ensure_up_to_date(SP_OBJECT_DOCUMENT(item));
284
NR::Maybe<NR::Rect> bbox = item->getBounds(NR::identity()); // we need "true" bbox without item_i2d_affine
288
Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine
286
if ( !bbox || bbox->isEmpty() )
289
NR::Coord const width = bbox->dimensions()[NR::X];
290
NR::Coord const height = bbox->dimensions()[NR::Y];
293
Geom::Coord const width = bbox->dimensions()[Geom::X];
294
Geom::Coord const height = bbox->dimensions()[Geom::Y];
292
NR::Point const center = bbox->midpoint();
296
Geom::Point const center = bbox->midpoint();
294
298
if (SP_IS_RADIALGRADIENT(gr)) {
295
sp_repr_set_svg_double(repr, "cx", center[NR::X]);
296
sp_repr_set_svg_double(repr, "cy", center[NR::Y]);
297
sp_repr_set_svg_double(repr, "fx", center[NR::X]);
298
sp_repr_set_svg_double(repr, "fy", center[NR::Y]);
299
sp_repr_set_svg_double(repr, "cx", center[Geom::X]);
300
sp_repr_set_svg_double(repr, "cy", center[Geom::Y]);
301
sp_repr_set_svg_double(repr, "fx", center[Geom::X]);
302
sp_repr_set_svg_double(repr, "fy", center[Geom::Y]);
299
303
sp_repr_set_svg_double(repr, "r", width/2);
301
305
// we want it to be elliptic, not circular
302
NR::Matrix squeeze = NR::Matrix (NR::translate (-center)) *
303
NR::Matrix (NR::scale(1, height/width)) *
304
NR::Matrix (NR::translate (center));
306
Geom::Matrix squeeze = Geom::Translate (-center) *
307
Geom::Scale(1, height/width) *
308
Geom::Translate (center);
306
310
gr->gradientTransform = squeeze;
313
sp_repr_set_svg_double(repr, "x1", (center - NR::Point(width/2, 0))[NR::X]);
314
sp_repr_set_svg_double(repr, "y1", (center - NR::Point(width/2, 0))[NR::Y]);
315
sp_repr_set_svg_double(repr, "x2", (center + NR::Point(width/2, 0))[NR::X]);
316
sp_repr_set_svg_double(repr, "y2", (center + NR::Point(width/2, 0))[NR::Y]);
317
sp_repr_set_svg_double(repr, "x1", (center - Geom::Point(width/2, 0))[Geom::X]);
318
sp_repr_set_svg_double(repr, "y1", (center - Geom::Point(width/2, 0))[Geom::Y]);
319
sp_repr_set_svg_double(repr, "x2", (center + Geom::Point(width/2, 0))[Geom::X]);
320
sp_repr_set_svg_double(repr, "y2", (center + Geom::Point(width/2, 0))[Geom::Y]);
319
323
// set the gradientUnits
342
346
// calculate the bbox of the item
343
347
sp_document_ensure_up_to_date(SP_OBJECT_DOCUMENT(item));
344
NR::Matrix bbox2user;
345
NR::Maybe<NR::Rect> bbox = item->getBounds(NR::identity()); // we need "true" bbox without item_i2d_affine
346
if ( bbox && !bbox->isEmpty() ) {
347
bbox2user = NR::Matrix(bbox->dimensions()[NR::X], 0,
348
0, bbox->dimensions()[NR::Y],
349
bbox->min()[NR::X], bbox->min()[NR::Y]);
348
Geom::Matrix bbox2user;
349
Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine
351
bbox2user = Geom::Matrix(bbox->dimensions()[Geom::X], 0,
352
0, bbox->dimensions()[Geom::Y],
353
bbox->min()[Geom::X], bbox->min()[Geom::Y]);
351
355
// would be degenerate otherwise
352
bbox2user = NR::identity();
356
bbox2user = Geom::identity();
355
359
/* skew is the additional transform, defined by the proportions of the item, that we need
386
390
// Matrix to convert points to userspace coords; postmultiply by inverse of skew so
387
391
// as to cancel it out when it's applied to the gradient during rendering
388
NR::Matrix point_convert = bbox2user * skew.inverse();
392
Geom::Matrix point_convert = bbox2user * skew.inverse();
390
394
if (SP_IS_RADIALGRADIENT(gr)) {
391
395
SPRadialGradient *rg = SP_RADIALGRADIENT(gr);
393
397
// original points in the bbox coords
394
NR::Point c_b = NR::Point(rg->cx.computed, rg->cy.computed);
395
NR::Point f_b = NR::Point(rg->fx.computed, rg->fy.computed);
398
Geom::Point c_b = Geom::Point(rg->cx.computed, rg->cy.computed);
399
Geom::Point f_b = Geom::Point(rg->fx.computed, rg->fy.computed);
396
400
double r_b = rg->r.computed;
398
402
// converted points in userspace coords
399
NR::Point c_u = c_b * point_convert;
400
NR::Point f_u = f_b * point_convert;
401
double r_u = r_b * point_convert.expansion();
403
Geom::Point c_u = c_b * point_convert;
404
Geom::Point f_u = f_b * point_convert;
405
double r_u = r_b * point_convert.descrim();
403
sp_repr_set_svg_double(repr, "cx", c_u[NR::X]);
404
sp_repr_set_svg_double(repr, "cy", c_u[NR::Y]);
405
sp_repr_set_svg_double(repr, "fx", f_u[NR::X]);
406
sp_repr_set_svg_double(repr, "fy", f_u[NR::Y]);
407
sp_repr_set_svg_double(repr, "cx", c_u[Geom::X]);
408
sp_repr_set_svg_double(repr, "cy", c_u[Geom::Y]);
409
sp_repr_set_svg_double(repr, "fx", f_u[Geom::X]);
410
sp_repr_set_svg_double(repr, "fy", f_u[Geom::Y]);
407
411
sp_repr_set_svg_double(repr, "r", r_u);
410
414
SPLinearGradient *lg = SP_LINEARGRADIENT(gr);
412
NR::Point p1_b = NR::Point(lg->x1.computed, lg->y1.computed);
413
NR::Point p2_b = NR::Point(lg->x2.computed, lg->y2.computed);
415
NR::Point p1_u = p1_b * point_convert;
416
NR::Point p2_u = p2_b * point_convert;
418
sp_repr_set_svg_double(repr, "x1", p1_u[NR::X]);
419
sp_repr_set_svg_double(repr, "y1", p1_u[NR::Y]);
420
sp_repr_set_svg_double(repr, "x2", p2_u[NR::X]);
421
sp_repr_set_svg_double(repr, "y2", p2_u[NR::Y]);
416
Geom::Point p1_b = Geom::Point(lg->x1.computed, lg->y1.computed);
417
Geom::Point p2_b = Geom::Point(lg->x2.computed, lg->y2.computed);
419
Geom::Point p1_u = p1_b * point_convert;
420
Geom::Point p2_u = p2_b * point_convert;
422
sp_repr_set_svg_double(repr, "x1", p1_u[Geom::X]);
423
sp_repr_set_svg_double(repr, "y1", p1_u[Geom::Y]);
424
sp_repr_set_svg_double(repr, "x2", p2_u[Geom::X]);
425
sp_repr_set_svg_double(repr, "y2", p2_u[Geom::Y]);
424
428
// set the gradientUnits
809
819
p_w (in desktop coordinates). Write_repr if you want the change to become permanent.
812
sp_item_gradient_set_coords (SPItem *item, guint point_type, guint point_i, NR::Point p_w, bool fill_or_stroke, bool write_repr, bool scale)
822
sp_item_gradient_set_coords (SPItem *item, guint point_type, guint point_i, Geom::Point p_w, bool fill_or_stroke, bool write_repr, bool scale)
814
824
SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
830
840
switch (point_type) {
831
841
case POINT_LG_BEGIN:
833
lg->x2.computed += (lg->x1.computed - p[NR::X]);
834
lg->y2.computed += (lg->y1.computed - p[NR::Y]);
843
lg->x2.computed += (lg->x1.computed - p[Geom::X]);
844
lg->y2.computed += (lg->y1.computed - p[Geom::Y]);
836
lg->x1.computed = p[NR::X];
837
lg->y1.computed = p[NR::Y];
846
lg->x1.computed = p[Geom::X];
847
lg->y1.computed = p[Geom::Y];
838
848
if (write_repr) {
840
850
sp_repr_set_svg_double(repr, "x2", lg->x2.computed);
849
859
case POINT_LG_END:
851
lg->x1.computed += (lg->x2.computed - p[NR::X]);
852
lg->y1.computed += (lg->y2.computed - p[NR::Y]);
861
lg->x1.computed += (lg->x2.computed - p[Geom::X]);
862
lg->y1.computed += (lg->y2.computed - p[Geom::Y]);
854
lg->x2.computed = p[NR::X];
855
lg->y2.computed = p[NR::Y];
864
lg->x2.computed = p[Geom::X];
865
lg->y2.computed = p[Geom::Y];
856
866
if (write_repr) {
858
868
sp_repr_set_svg_double(repr, "x1", lg->x1.computed);
867
877
case POINT_LG_MID:
869
879
// using X-coordinates only to determine the offset, assuming p has been snapped to the vector from begin to end.
870
double offset = get_offset_between_points (p, NR::Point(lg->x1.computed, lg->y1.computed), NR::Point(lg->x2.computed, lg->y2.computed));
880
double offset = get_offset_between_points (p, Geom::Point(lg->x1.computed, lg->y1.computed), Geom::Point(lg->x2.computed, lg->y2.computed));
871
881
SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (lg, false);
872
882
sp_gradient_ensure_vector(lg);
873
883
lg->vector.stops.at(point_i).offset = offset;
886
896
} else if (SP_IS_RADIALGRADIENT(gradient)) {
887
897
SPRadialGradient *rg = SP_RADIALGRADIENT(gradient);
888
NR::Point c (rg->cx.computed, rg->cy.computed);
889
NR::Point c_w = c * gradient->gradientTransform * i2d; // now in desktop coords
890
if ((point_type == POINT_RG_R1 || point_type == POINT_RG_R2) && NR::L2 (p_w - c_w) < 1e-3) {
898
Geom::Point c (rg->cx.computed, rg->cy.computed);
899
Geom::Point c_w = c * gradient->gradientTransform * i2d; // now in desktop coords
900
if ((point_type == POINT_RG_R1 || point_type == POINT_RG_R2) && Geom::L2 (p_w - c_w) < 1e-3) {
891
901
// prevent setting a radius too close to the center
894
NR::Matrix new_transform;
904
Geom::Matrix new_transform;
895
905
bool transform_set = false;
897
907
switch (point_type) {
898
908
case POINT_RG_CENTER:
899
rg->fx.computed = p[NR::X] + (rg->fx.computed - rg->cx.computed);
900
rg->fy.computed = p[NR::Y] + (rg->fy.computed - rg->cy.computed);
901
rg->cx.computed = p[NR::X];
902
rg->cy.computed = p[NR::Y];
909
rg->fx.computed = p[Geom::X] + (rg->fx.computed - rg->cx.computed);
910
rg->fy.computed = p[Geom::Y] + (rg->fy.computed - rg->cy.computed);
911
rg->cx.computed = p[Geom::X];
912
rg->cy.computed = p[Geom::Y];
903
913
if (write_repr) {
904
914
sp_repr_set_svg_double(repr, "fx", rg->fx.computed);
905
915
sp_repr_set_svg_double(repr, "fy", rg->fy.computed);
922
932
case POINT_RG_R1:
924
NR::Point r1_w = (c + NR::Point(rg->r.computed, 0)) * gradient->gradientTransform * i2d;
925
double r1_angle = NR::atan2(r1_w - c_w);
926
double move_angle = NR::atan2(p_w - c_w) - r1_angle;
927
double move_stretch = NR::L2(p_w - c_w) / NR::L2(r1_w - c_w);
934
Geom::Point r1_w = (c + Geom::Point(rg->r.computed, 0)) * gradient->gradientTransform * i2d;
935
double r1_angle = Geom::atan2(r1_w - c_w);
936
double move_angle = Geom::atan2(p_w - c_w) - r1_angle;
937
double move_stretch = Geom::L2(p_w - c_w) / Geom::L2(r1_w - c_w);
929
NR::Matrix move = NR::Matrix (NR::translate (-c_w)) *
930
NR::Matrix (NR::rotate(-r1_angle)) *
931
NR::Matrix (NR::scale(move_stretch, scale? move_stretch : 1)) *
932
NR::Matrix (NR::rotate(r1_angle)) *
933
NR::Matrix (NR::rotate(move_angle)) *
934
NR::Matrix (NR::translate (c_w));
939
Geom::Matrix move = Geom::Matrix (Geom::Translate (-c_w)) *
940
Geom::Matrix (Geom::Rotate(-r1_angle)) *
941
Geom::Matrix (Geom::Scale(move_stretch, scale? move_stretch : 1)) *
942
Geom::Matrix (Geom::Rotate(r1_angle)) *
943
Geom::Matrix (Geom::Rotate(move_angle)) *
944
Geom::Matrix (Geom::Translate (c_w));
936
946
new_transform = gradient->gradientTransform * i2d * move * i2d.inverse();
937
947
transform_set = true;
941
951
case POINT_RG_R2:
943
NR::Point r2_w = (c + NR::Point(0, -rg->r.computed)) * gradient->gradientTransform * i2d;
944
double r2_angle = NR::atan2(r2_w - c_w);
945
double move_angle = NR::atan2(p_w - c_w) - r2_angle;
946
double move_stretch = NR::L2(p_w - c_w) / NR::L2(r2_w - c_w);
953
Geom::Point r2_w = (c + Geom::Point(0, -rg->r.computed)) * gradient->gradientTransform * i2d;
954
double r2_angle = Geom::atan2(r2_w - c_w);
955
double move_angle = Geom::atan2(p_w - c_w) - r2_angle;
956
double move_stretch = Geom::L2(p_w - c_w) / Geom::L2(r2_w - c_w);
948
NR::Matrix move = NR::Matrix (NR::translate (-c_w)) *
949
NR::Matrix (NR::rotate(-r2_angle)) *
950
NR::Matrix (NR::scale(move_stretch, scale? move_stretch : 1)) *
951
NR::Matrix (NR::rotate(r2_angle)) *
952
NR::Matrix (NR::rotate(move_angle)) *
953
NR::Matrix (NR::translate (c_w));
958
Geom::Matrix move = Geom::Matrix (Geom::Translate (-c_w)) *
959
Geom::Matrix (Geom::Rotate(-r2_angle)) *
960
Geom::Matrix (Geom::Scale(move_stretch, scale? move_stretch : 1)) *
961
Geom::Matrix (Geom::Rotate(r2_angle)) *
962
Geom::Matrix (Geom::Rotate(move_angle)) *
963
Geom::Matrix (Geom::Translate (c_w));
955
965
new_transform = gradient->gradientTransform * i2d * move * i2d.inverse();
956
966
transform_set = true;
960
970
case POINT_RG_MID1:
962
NR::Point start = NR::Point (rg->cx.computed, rg->cy.computed);
963
NR::Point end = NR::Point (rg->cx.computed + rg->r.computed, rg->cy.computed);
972
Geom::Point start = Geom::Point (rg->cx.computed, rg->cy.computed);
973
Geom::Point end = Geom::Point (rg->cx.computed + rg->r.computed, rg->cy.computed);
964
974
double offset = get_offset_between_points (p, start, end);
965
975
SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (rg, false);
966
976
sp_gradient_ensure_vector(rg);
977
987
case POINT_RG_MID2:
978
NR::Point start = NR::Point (rg->cx.computed, rg->cy.computed);
979
NR::Point end = NR::Point (rg->cx.computed, rg->cy.computed - rg->r.computed);
988
Geom::Point start = Geom::Point (rg->cx.computed, rg->cy.computed);
989
Geom::Point end = Geom::Point (rg->cx.computed, rg->cy.computed - rg->r.computed);
980
990
double offset = get_offset_between_points (p, start, end);
981
991
SPGradient *vector = sp_gradient_get_forked_vector_if_necessary(rg, false);
982
992
sp_gradient_ensure_vector(rg);
1030
1040
in desktop coordinates.
1034
1044
sp_item_gradient_get_coords (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
1036
1046
SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
1048
Geom::Point p (0, 0);
1051
return from_2geom(p);
1043
1053
if (SP_IS_LINEARGRADIENT(gradient)) {
1044
1054
SPLinearGradient *lg = SP_LINEARGRADIENT(gradient);
1045
1055
switch (point_type) {
1046
1056
case POINT_LG_BEGIN:
1047
p = NR::Point (lg->x1.computed, lg->y1.computed);
1057
p = Geom::Point (lg->x1.computed, lg->y1.computed);
1049
1059
case POINT_LG_END:
1050
p = NR::Point (lg->x2.computed, lg->y2.computed);
1060
p = Geom::Point (lg->x2.computed, lg->y2.computed);
1052
1062
case POINT_LG_MID:
1054
1064
gdouble offset = lg->vector.stops.at(point_i).offset;
1055
p = (1-offset) * NR::Point(lg->x1.computed, lg->y1.computed) + offset * NR::Point(lg->x2.computed, lg->y2.computed);
1065
p = (1-offset) * Geom::Point(lg->x1.computed, lg->y1.computed) + offset * Geom::Point(lg->x2.computed, lg->y2.computed);
1060
1070
SPRadialGradient *rg = SP_RADIALGRADIENT(gradient);
1061
1071
switch (point_type) {
1062
1072
case POINT_RG_CENTER:
1063
p = NR::Point (rg->cx.computed, rg->cy.computed);
1073
p = Geom::Point (rg->cx.computed, rg->cy.computed);
1065
1075
case POINT_RG_FOCUS:
1066
p = NR::Point (rg->fx.computed, rg->fy.computed);
1076
p = Geom::Point (rg->fx.computed, rg->fy.computed);
1068
1078
case POINT_RG_R1:
1069
p = NR::Point (rg->cx.computed + rg->r.computed, rg->cy.computed);
1079
p = Geom::Point (rg->cx.computed + rg->r.computed, rg->cy.computed);
1071
1081
case POINT_RG_R2:
1072
p = NR::Point (rg->cx.computed, rg->cy.computed - rg->r.computed);
1082
p = Geom::Point (rg->cx.computed, rg->cy.computed - rg->r.computed);
1074
1084
case POINT_RG_MID1:
1076
1086
gdouble offset = rg->vector.stops.at(point_i).offset;
1077
p = (1-offset) * NR::Point (rg->cx.computed, rg->cy.computed) + offset * NR::Point(rg->cx.computed + rg->r.computed, rg->cy.computed);
1087
p = (1-offset) * Geom::Point (rg->cx.computed, rg->cy.computed) + offset * Geom::Point(rg->cx.computed + rg->r.computed, rg->cy.computed);
1080
1090
case POINT_RG_MID2:
1082
1092
gdouble offset = rg->vector.stops.at(point_i).offset;
1083
p = (1-offset) * NR::Point (rg->cx.computed, rg->cy.computed) + offset * NR::Point(rg->cx.computed, rg->cy.computed - rg->r.computed);
1093
p = (1-offset) * Geom::Point (rg->cx.computed, rg->cy.computed) + offset * Geom::Point(rg->cx.computed, rg->cy.computed - rg->r.computed);
1089
1099
if (SP_GRADIENT(gradient)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1090
1100
sp_document_ensure_up_to_date(SP_OBJECT_DOCUMENT(item));
1091
NR::Maybe<NR::Rect> bbox = item->getBounds(NR::identity()); // we need "true" bbox without item_i2d_affine
1101
Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine
1093
p *= NR::Matrix(bbox->dimensions()[NR::X], 0,
1094
0, bbox->dimensions()[NR::Y],
1095
bbox->min()[NR::X], bbox->min()[NR::Y]);
1103
p *= Geom::Matrix(bbox->dimensions()[Geom::X], 0,
1104
0, bbox->dimensions()[Geom::Y],
1105
bbox->min()[Geom::X], bbox->min()[Geom::Y]);
1098
p *= NR::Matrix(gradient->gradientTransform) * sp_item_i2d_affine(item);
1108
p *= Geom::Matrix(gradient->gradientTransform) * (Geom::Matrix)sp_item_i2d_affine(item);
1109
return from_2geom(p);