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;
X3, Y3: Double;
procedure Move(ADeltaX, ADeltaY: Double); override;
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
end;
{ T3DSegment }
@ -1325,9 +1326,10 @@ end;
function TPathSegment.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc;
APageItem: Pointer): Pointer;
var
lStr: string;
lStr, lTypeStr: string;
begin
lStr := Format('[%s]', [Self.ClassName]);
lTypeStr := GetEnumName(TypeInfo(TSegmentType), integer(SegmentType));
lStr := Format('[%s] Type=%s', [Self.ClassName, lTypeStr]);
Result := ADestRoutine(lStr, APageItem);
end;
@ -1352,9 +1354,10 @@ end;
function T2DSegment.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc;
APageItem: Pointer): Pointer;
var
lStr: string;
lStr, lTypeStr: string;
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);
end;
@ -1369,6 +1372,15 @@ begin
Y3 := Y3 + ADeltaY;
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 }
procedure T3DSegment.Move(ADeltaX, ADeltaY: Double);
@ -1920,6 +1932,8 @@ var
t: Double;
// For polygons
Points: array of TPoint;
MultiPoints: array of array of TPoint;
lCurPoligon, lCurPoligonStartIndex: Integer;
// for elliptical arcs
BoxLeft, BoxTop, BoxRight, BoxBottom: Double;
EllipseRect: TRect;
@ -1964,6 +1978,9 @@ begin
//
// 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
begin
PrepareForSequentialReading;
@ -1974,25 +1991,43 @@ begin
ADest.Brush.Style := Brush.Style;
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
begin
//WriteLn('j = ', j);
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);
CoordY := CoordToCanvasY(Cur2DSegment.Y);
Points[j].X := CoordX;
Points[j].Y := CoordY;
MultiPoints[lCurPoligon][j-lCurPoligonStartIndex].X := CoordX;
MultiPoints[lCurPoligon][j-lCurPoligonStartIndex].Y := CoordY;
{$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
Write(Format(' P%d,%d', [CoordY, CoordY]));
{$endif}
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}
Write(' Now the details ');

View File

@ -1262,12 +1262,15 @@ begin
lLastCommandToken := lCurTokenType;
ReadNextPathCommand(lCurTokenType, i, CurX, CurY, AData, ADoc);
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
begin
lTmpTokenType := lLastCommandToken;
if lLastCommandToken = sttMoveTo then lTmpTokenType := sttLineTo;
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);
end;
end;
@ -1292,16 +1295,19 @@ begin
begin
X := FSVGPathTokenizer.Tokens.Items[i+1].Value;
Y := FSVGPathTokenizer.Tokens.Items[i+2].Value;
ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y);
// 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
ConvertSVGDeltaToFPVDelta(AData, X, Y, X, Y);
CurX := CurX + X;
CurY := CurY + Y;
end
else
begin
ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y);
CurX := X;
CurY := Y;
end;
@ -1397,8 +1403,16 @@ begin
end;
if (i >= 7) and (lCorrectPreviousToken) then
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;
if lCurTokenType = sttRelativeSmoothBezierTo then
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;
// Now the non-missing items
X3 := FSVGPathTokenizer.Tokens.Items[i+1].Value;
@ -1421,14 +1435,25 @@ begin
ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y);
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
((i < 7) or (not lCorrectPreviousToken)) then
begin
X2 := CurX;
Y2 := CurY;
if lCurTokenType = sttRelativeSmoothBezierTo then
begin
X2 := CurX;
Y2 := CurY;
end
else
begin
X2 := 0;
Y2 := 0;
end;
end;
if lCurTokenType = sttRelativeBezierTo then
// The final step
if lCurTokenType in [sttRelativeBezierTo, sttRelativeSmoothBezierTo] then
begin
AData.AddBezierToPath(X2 + CurX, Y2 + CurY, X3 + CurX, Y3 + CurY, X + CurX, Y + CurY);
CurX := CurX + X;

View File

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