fpvectorial: Now smooth bezier seams 100% correct =)

git-svn-id: trunk@41660 -
This commit is contained in:
sekelsenmat 2013-06-10 11:08:58 +00:00
parent 915f42b9b9
commit 17439e0e35
3 changed files with 77 additions and 16 deletions

View File

@ -201,6 +201,7 @@ type
X2, Y2: Double; X2, Y2: Double;
X3, Y3: Double; X3, Y3: Double;
procedure Move(ADeltaX, ADeltaY: Double); override; procedure Move(ADeltaX, ADeltaY: Double); override;
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
end; end;
{ T3DSegment } { T3DSegment }
@ -1325,9 +1326,10 @@ end;
function TPathSegment.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; function TPathSegment.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc;
APageItem: Pointer): Pointer; APageItem: Pointer): Pointer;
var var
lStr: string; lStr, lTypeStr: string;
begin begin
lStr := Format('[%s]', [Self.ClassName]); lTypeStr := GetEnumName(TypeInfo(TSegmentType), integer(SegmentType));
lStr := Format('[%s] Type=%s', [Self.ClassName, lTypeStr]);
Result := ADestRoutine(lStr, APageItem); Result := ADestRoutine(lStr, APageItem);
end; end;
@ -1352,9 +1354,10 @@ end;
function T2DSegment.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; function T2DSegment.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc;
APageItem: Pointer): Pointer; APageItem: Pointer): Pointer;
var var
lStr: string; lStr, lTypeStr: string;
begin begin
lStr := Format('[%s] X=%f Y=%f', [Self.ClassName, X, Y]); lTypeStr := GetEnumName(TypeInfo(TSegmentType), integer(SegmentType));
lStr := Format('[%s] Type=%s X=%f Y=%f', [Self.ClassName, lTypeStr, X, Y]);
Result := ADestRoutine(lStr, APageItem); Result := ADestRoutine(lStr, APageItem);
end; end;
@ -1369,6 +1372,15 @@ begin
Y3 := Y3 + ADeltaY; Y3 := Y3 + ADeltaY;
end; end;
function T2DBezierSegment.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc;
APageItem: Pointer): Pointer;
var
lStr: string;
begin
lStr := Format('[%s] X=%f Y=%f CX2=%f CY2=%f CX3=%f CY3=%f', [Self.ClassName, X, Y, X2, Y2, X3, Y3]);
Result := ADestRoutine(lStr, APageItem);
end;
{ T3DSegment } { T3DSegment }
procedure T3DSegment.Move(ADeltaX, ADeltaY: Double); procedure T3DSegment.Move(ADeltaX, ADeltaY: Double);
@ -1920,6 +1932,8 @@ var
t: Double; t: Double;
// For polygons // For polygons
Points: array of TPoint; Points: array of TPoint;
MultiPoints: array of array of TPoint;
lCurPoligon, lCurPoligonStartIndex: Integer;
// for elliptical arcs // for elliptical arcs
BoxLeft, BoxTop, BoxRight, BoxBottom: Double; BoxLeft, BoxTop, BoxRight, BoxBottom: Double;
EllipseRect: TRect; EllipseRect: TRect;
@ -1964,6 +1978,9 @@ begin
// //
// For solid paths, draw a polygon for the main internal area // For solid paths, draw a polygon for the main internal area
// //
// If there is a move-to in the middle of the path, we should
// draw then multiple poligons
//
if Brush.Style <> bsClear then if Brush.Style <> bsClear then
begin begin
PrepareForSequentialReading; PrepareForSequentialReading;
@ -1974,25 +1991,43 @@ begin
ADest.Brush.Style := Brush.Style; ADest.Brush.Style := Brush.Style;
ADest.Pen.Style := psClear; ADest.Pen.Style := psClear;
SetLength(Points, Len); SetLength(MultiPoints, 1);
SetLength(MultiPoints[0], Len);
lCurPoligon := 0;
lCurPoligonStartIndex := 0;
for j := 0 to Len - 1 do for j := 0 to Len - 1 do
begin begin
//WriteLn('j = ', j); //WriteLn('j = ', j);
CurSegment := TPathSegment(Next()); CurSegment := TPathSegment(Next());
if (j > 0) and (CurSegment.SegmentType = stMoveTo) then
begin
SetLength(MultiPoints[lCurPoligon], j-lCurPoligonStartIndex);
Inc(lCurPoligon);
SetLength(MultiPoints, lCurPoligon+1);
SetLength(MultiPoints[lCurPoligon], Len);
lCurPoligonStartIndex := j;
end;
CoordX := CoordToCanvasX(Cur2DSegment.X); CoordX := CoordToCanvasX(Cur2DSegment.X);
CoordY := CoordToCanvasY(Cur2DSegment.Y); CoordY := CoordToCanvasY(Cur2DSegment.Y);
Points[j].X := CoordX; MultiPoints[lCurPoligon][j-lCurPoligonStartIndex].X := CoordX;
Points[j].Y := CoordY; MultiPoints[lCurPoligon][j-lCurPoligonStartIndex].Y := CoordY;
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG} {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
Write(Format(' P%d,%d', [CoordY, CoordY])); Write(Format(' P%d,%d', [CoordY, CoordY]));
{$endif} {$endif}
end; end;
ADest.Polygon(Points); // Cut off excess from the last poligon
SetLength(MultiPoints[lCurPoligon], Len-lCurPoligonStartIndex);
// Draw each polygon now
for j := 0 to lCurPoligon do
begin
ADest.Polygon(MultiPoints[j]);
end;
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG} {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
Write(' Now the details '); Write(' Now the details ');

View File

@ -1262,12 +1262,15 @@ begin
lLastCommandToken := lCurTokenType; lLastCommandToken := lCurTokenType;
ReadNextPathCommand(lCurTokenType, i, CurX, CurY, AData, ADoc); ReadNextPathCommand(lCurTokenType, i, CurX, CurY, AData, ADoc);
end end
// In this case we are getting a command without a starting letter
// It is a copy of the last one, or something related to it
else else
begin begin
lTmpTokenType := lLastCommandToken; lTmpTokenType := lLastCommandToken;
if lLastCommandToken = sttMoveTo then lTmpTokenType := sttLineTo; if lLastCommandToken = sttMoveTo then lTmpTokenType := sttLineTo;
if lLastCommandToken = sttRelativeMoveTo then lTmpTokenType := sttRelativeLineTo; if lLastCommandToken = sttRelativeMoveTo then lTmpTokenType := sttRelativeLineTo;
Dec(i);// because there is command token // For bezier I checked that a sttBezierTo upon repetition expects a sttBezierTo
Dec(i);// because there is no command token in this command
ReadNextPathCommand(lTmpTokenType, i, CurX, CurY, AData, ADoc); ReadNextPathCommand(lTmpTokenType, i, CurX, CurY, AData, ADoc);
end; end;
end; end;
@ -1292,16 +1295,19 @@ begin
begin begin
X := FSVGPathTokenizer.Tokens.Items[i+1].Value; X := FSVGPathTokenizer.Tokens.Items[i+1].Value;
Y := FSVGPathTokenizer.Tokens.Items[i+2].Value; Y := FSVGPathTokenizer.Tokens.Items[i+2].Value;
ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y);
// take care of relative or absolute // take care of relative or absolute
if lCurTokenType = sttRelativeMoveTo then // Idiotism in SVG: If the path starts with a relative move to,
// the coordinates are absolute =o source: http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands
if (lCurTokenType = sttRelativeMoveTo) and (i > 0) then
begin begin
ConvertSVGDeltaToFPVDelta(AData, X, Y, X, Y);
CurX := CurX + X; CurX := CurX + X;
CurY := CurY + Y; CurY := CurY + Y;
end end
else else
begin begin
ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y);
CurX := X; CurX := X;
CurY := Y; CurY := Y;
end; end;
@ -1397,8 +1403,16 @@ begin
end; end;
if (i >= 7) and (lCorrectPreviousToken) then if (i >= 7) and (lCorrectPreviousToken) then
begin begin
X2 := 2*FSVGPathTokenizer.Tokens.Items[i-2].Value - FSVGPathTokenizer.Tokens.Items[i-4].Value; if lCurTokenType = sttRelativeSmoothBezierTo then
Y2 := 2*FSVGPathTokenizer.Tokens.Items[i-1].Value - FSVGPathTokenizer.Tokens.Items[i-3].Value; begin
X2 := FSVGPathTokenizer.Tokens.Items[i-2].Value - FSVGPathTokenizer.Tokens.Items[i-4].Value;
Y2 := FSVGPathTokenizer.Tokens.Items[i-1].Value - FSVGPathTokenizer.Tokens.Items[i-3].Value;
end
else
begin
X2 := 2*FSVGPathTokenizer.Tokens.Items[i-2].Value - FSVGPathTokenizer.Tokens.Items[i-4].Value;
Y2 := 2*FSVGPathTokenizer.Tokens.Items[i-1].Value - FSVGPathTokenizer.Tokens.Items[i-3].Value;
end;
end; end;
// Now the non-missing items // Now the non-missing items
X3 := FSVGPathTokenizer.Tokens.Items[i+1].Value; X3 := FSVGPathTokenizer.Tokens.Items[i+1].Value;
@ -1421,14 +1435,25 @@ begin
ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y); ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y);
end; end;
// Covers the case where there is no valid first control point in smooth bezier
// The code is here to be after the conversions
if (lCurTokenType in [sttSmoothBezierTo, sttRelativeSmoothBezierTo]) and if (lCurTokenType in [sttSmoothBezierTo, sttRelativeSmoothBezierTo]) and
((i < 7) or (not lCorrectPreviousToken)) then ((i < 7) or (not lCorrectPreviousToken)) then
begin begin
X2 := CurX; if lCurTokenType = sttRelativeSmoothBezierTo then
Y2 := CurY; begin
X2 := CurX;
Y2 := CurY;
end
else
begin
X2 := 0;
Y2 := 0;
end;
end; end;
if lCurTokenType = sttRelativeBezierTo then // The final step
if lCurTokenType in [sttRelativeBezierTo, sttRelativeSmoothBezierTo] then
begin begin
AData.AddBezierToPath(X2 + CurX, Y2 + CurY, X3 + CurX, Y3 + CurY, X + CurX, Y + CurY); AData.AddBezierToPath(X2 + CurX, Y2 + CurY, X3 + CurX, Y3 + CurY, X + CurX, Y + CurY);
CurX := CurX + X; CurX := CurX + X;

View File

@ -56,6 +56,7 @@ begin
InflateGZ(AFileName, DataStream); InflateGZ(AFileName, DataStream);
DataStream.Position := 0; DataStream.Position := 0;
ReadFromStream(DataStream, AData); ReadFromStream(DataStream, AData);
//DataStream.SaveToFile('/tmp/foo.svg');
finally finally
DataStream.Free; DataStream.Free;
end; end;