Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 10/28/22 in all areas

  1. Uwe Raabe

    Delphifeeds.com??

    That is one reason why I am sceptic when someone claims Delphi should support this feature or have that tool out of the box, while often there already exist 3rd party solutions covering all these. I would rather see Delphi step back and concentrate on its core functionality instead of constantly broadening the target. Either these have to compete for the limited resources or they are going to be abandoned like ever so often. Just buying a tool as a Delphi companion is only the start. It needs constant and sufficient investment to keep it going.
  2. Stefan Glienke

    Delphifeeds.com??

    That is exactly what I respond when someone tells me that Embarcadero should integrate TestInsight or Spring. Parnassus plugins ...
  3. Brandon Staggs

    Delphifeeds.com??

    This is my perception as well. There is a general lack of focus on quality and execution with Delphi and related services. While I appreciate that they are managing to keep up with Android as a target, have iterative improvements to various aspects of the IDE and language, etc., I cannot work with Delphi for a day without having to work around bugs, and the community resources that used to exist have all but disappeared. It looks like a system being barely maintained with a skeleton crew. I know that is unfair to people who have put so much effort into it and continue to develop it, but I am a 20+ year Delphi veteran and while I can manage to work around its quirks and bugs, I would never recommend it to someone starting new. So how much long will all this last? I do my part -- I pay for multi-year subscription and try to make sensible QA reports. But how long will this last?
  4. David Heffernan

    generics

    Stop trolling, that's my job!
  5. Stefan Glienke

    generics

    Doesn't that make it a container? 😜
  6. shineworld

    First Python + DelphiVCL Program

    My First P4D was completed and released 🙂 Thanks to the developers of PyScripter and P4D for these amazing tools.
  7. dummzeuch

    Delphifeeds.com??

    Same story over and over again: There is a good tool / website / whatever Embarcadero buys it (or the person who made it becomes an employee) It goes down the drain
  8. angusj

    Rounded polygon

    Here's my GetSmoothPath() routine. It requires no specific graphics library to use, just a few extra functions (also included below). This function generates an array of control points that's very easily converted into a flattened cubic bezier path using just about any 2D graphics library. (nb: The code below has been written with simplicity as the focus rather than performance.) uses SysUtils, Math; type TPointD = record X, Y: double; end; TPathD = array of TPointD; TArrayOfDouble = array of double; function DistanceSqrd(const pt1, pt2: TPointD): double; begin result := Sqr(pt1.X - pt2.X) + Sqr(pt1.Y - pt2.Y); end; function Distance(const pt1, pt2: TPointD): double; begin Result := Sqrt(DistanceSqrd(pt1, pt2)); end; function OffsetPoint(const pt: TPointD; dx, dy: double): TPointD; begin result.x := pt.x + dx; result.y := pt.y + dy; end; function GetAvgUnitVector(const vec1, vec2: TPointD): TPointD; var inverseHypot: Double; begin Result.X := (vec1.X + vec2.X) * 0.5; Result.y := (vec1.Y + vec2.Y) * 0.5; inverseHypot := 1 / Hypot(Result.X, Result.Y); Result.X := Result.X * inverseHypot; Result.Y := Result.Y * inverseHypot; end; procedure MakeSymmetric(var val1, val2: double); begin val1 := (val1 + val2) * 0.5; val2 := val1; end; function GetUnitVector(const pt1, pt2: TPointD): TPointD; var dx, dy, inverseHypot: Double; begin if (pt1.x = pt2.x) and (pt1.y = pt2.y) then begin Result.X := 0; Result.Y := 0; Exit; end; dx := (pt2.X - pt1.X); dy := (pt2.Y - pt1.Y); inverseHypot := 1 / Hypot(dx, dy); dx := dx * inverseHypot; dy := dy * inverseHypot; Result.X := dx; Result.Y := dy; end; // GetSmoothPath - returns cubic bezier control points // parameters: 1. path for smoothing // 2. whether or not the smoothed path will closed // 3. percent smoothness (0..100) // 4. maximum dist control pts from path pts (0 = no limit) // 5. symmetric vs asymmmetric control pts function GetSmoothPath(const path: TPathD; pathIsClosed: Boolean; percentOffset, maxCtrlOffset: double; symmetric: Boolean): TPathD; var i, len, prev: integer; vec: TPointD; pl: TArrayOfDouble; unitVecs: TPathD; d, d1,d2: double; begin Result := nil; len := Length(path); if len < 3 then Exit; d := Max(0, Min(100, percentOffset))/200; if maxCtrlOffset <= 0 then maxCtrlOffset := MaxDouble; SetLength(Result, len *3 +1); prev := len-1; SetLength(pl, len); SetLength(unitVecs, len); for i := 0 to len -1 do begin pl[i] := Distance(path[prev], path[i]); unitVecs[i] := GetUnitVector(path[prev], path[i]); prev := i; end; Result[len*3] := path[0]; for i := 0 to len -1 do begin if i = len -1 then begin vec := GetAvgUnitVector(unitVecs[i], unitVecs[0]); d2 := pl[0]*d; end else begin vec := GetAvgUnitVector(unitVecs[i], unitVecs[i+1]); d2 := pl[i+1]*d; end; d1 := pl[i]*d; if symmetric then MakeSymmetric(d1, d2); if i = 0 then Result[len*3-1] := OffsetPoint(path[i], -vec.X * Min(maxCtrlOffset, d1), -vec.Y * Min(maxCtrlOffset, d1)) else Result[i*3-1] := OffsetPoint(path[i], -vec.X * Min(maxCtrlOffset, d1), -vec.Y * Min(maxCtrlOffset, d1)); Result[i*3] := path[i]; Result[i*3+1] := OffsetPoint(path[i], vec.X * Min(maxCtrlOffset, d2), vec.Y * Min(maxCtrlOffset, d2)); end; if not pathIsClosed then begin Result[1] := Result[0]; dec(len); Result[len*3-1] := Result[len*3]; SetLength(Result, Len*3 +1); end; end; And here's what it produces ... the path to smooth (black), the cubic bezier control path produced by GetSmoothPath() (blue) and the flattened cubic bezier path (2D graphics library of you choice required) (red). var TPathD path; begin path := MakePath([190,120, 260,270, 560,120, 190,490]); path := GetSmoothPath(path, true, 20, 0, false); path := ThirdParty2DGraphicsLibrary.FlattenCBezier(path); end; var TPathD path; begin path := MakePath([190,120, 260,270, 560,120, 190,490]); path := GetSmoothPath(path, true, 80, 0, false); path := ThirdParty2DGraphicsLibrary.FlattenCBezier(path); end; Edit: The best way to avoid intersections is to make sure you have enough data points before generating your curves.
  9. vfbb

    Rounded polygon

    Here's an example: uses Skia; function MakeCubicSplineInterpolation(const APoints: TArray<TPointF>): ISkPath; var LPathBuilder: ISkPathBuilder; LSegments: Integer; I: Integer; mx: Single; my: Single; LScratches: array of record a, b, c, r, p: TPointF; end; begin LPathBuilder := TSkPathBuilder.Create; if Length(APoints) < 2 then Exit(LPathBuilder.Detach); if Length(APoints) = 2 then begin LPathBuilder.MoveTo(APoints[0]); LPathBuilder.LineTo(APoints[1]); Exit(LPathBuilder.Detach); end; LSegments := Length(APoints) - 1; SetLength(LScratches, LSegments); LScratches[0].a := PointF(0, 0); LScratches[0].b := PointF(2, 2); LScratches[0].c := PointF(1, 1); LScratches[0].r := PointF(APoints[0].X + 2 * APoints[1].X, APoints[0].Y + 2 * APoints[1].Y); for I := 1 to LSegments - 2 do begin LScratches[I].a := PointF(1, 1); LScratches[I].b := PointF(4, 4); LScratches[I].c := PointF(1, 1); LScratches[I].r := PointF(4 * APoints[i].X + 2 * APoints[I + 1].X, 4 * APoints[I].Y + 2 * APoints[I + 1].Y); end; LScratches[LSegments - 1].a := PointF(2, 2); LScratches[LSegments - 1].b := PointF(7, 7); LScratches[LSegments - 1].c := PointF(0, 0); LScratches[LSegments - 1].r := PointF(8 * APoints[LSegments - 1].X + APoints[LSegments].X, 8 * APoints[LSegments - 1].Y + APoints[LSegments].Y); for I := 1 to LSegments - 1 do begin mx := LScratches[I].a.X / LScratches[I - 1].b.X; my := LScratches[I].a.Y / LScratches[I - 1].b.Y; LScratches[I].b := LScratches[I].b - PointF(mx * LScratches[I - 1].c.X, my * LScratches[I - 1].c.Y); LScratches[I].r := LScratches[I].r - PointF(mx * LScratches[I - 1].r.X, my * LScratches[I - 1].r.Y); end; LScratches[LSegments - 1].p := PointF(LScratches[LSegments - 1].r.X / LScratches[LSegments - 1].b.X, LScratches[LSegments - 1].r.Y / LScratches[LSegments - 1].b.Y); for I := Length(APoints) - 3 downto 0 do begin LScratches[I].p := PointF((LScratches[I].r.X - LScratches[I].c.X * LScratches[I + 1].p.X) / LScratches[I].b.X, (LScratches[I].r.Y - LScratches[I].c.Y * LScratches[I + 1].p.Y) / LScratches[I].b.Y); end; LPathBuilder.MoveTo(APoints[0]); for I := 0 to LSegments - 2 do begin LPathBuilder.CubicTo(LScratches[I].p, PointF(2 * APoints[I + 1].X - LScratches[I + 1].p.X, 2 * APoints[I + 1].Y - LScratches[I + 1].p.Y), APoints[I + 1]); end; LPathBuilder.CubicTo(LScratches[LSegments - 1].p, PointF(0.5 * (APoints[LSegments].X + LScratches[LSegments - 1].p.X), 0.5 * (APoints[LSegments].Y + LScratches[LSegments - 1].p.Y)), APoints[LSegments]); Result := LPathBuilder.Detach; end; procedure TForm1.SkPaintBox1Draw(ASender: TObject; const ACanvas: ISkCanvas; const ADest: TRectF; const AOpacity: Single); var LPaint: ISkPaint; LMyPoints: TArray<TPointF>; begin LMyPoints := [PointF(62, 511), PointF(162, 605), PointF(262, 610), PointF(362, 402), PointF(462, 959), PointF(562, 58), PointF(662, 272), PointF(762, 99), PointF(862, 759), PointF(962, 945)]; LPaint := TSkPaint.Create(TSkPaintStyle.Stroke); LPaint.Color := TAlphaColors.Red; LPaint.AntiAlias := True; LPaint.StrokeWidth := 3; LPaint.StrokeCap := TSkStrokeCap.Round; ACanvas.DrawPath(MakeCubicSplineInterpolation(LMyPoints), LPaint); LPaint.StrokeWidth := 10; LPaint.Color := TAlphaColors.Black; ACanvas.DrawPoints(TSkDrawPointsMode.Points, LMyPoints, LPaint); end; Result: Note: You don't need to use Skia, it was just a facilitator for the example.
×