For a given set of points (examplary quadrant)
n = 5; (* number of inner points*)
p = Table[{Cos[φ], Sin[φ]}, {φ, Join[{0}, RandomReal[{0, Pi/2}, n], {Pi/2}]}];
I want to calculate the optimal controlpoint {kx,ky} of a 3point bezier function(using BezierFunction).
An optimal controlpoint seems to exist for this problem:
Manipulate[
Show[{
ParametricPlot[
BezierFunction[{p[[1]], {kx, ky }, p[[-1]]}][u] // Evaluate, {u, 0, 1}],
ListPlot[p],
Graphics[{Red, Point[{kx, ky}],Text["{kx,ky}", {kx, ky}, {0, -1}]}]}],
{{kx, .7}, 0, 1, Appearance -> "Labeled"}, {{ky, .7}, 0, 1, Appearance -> "Labeled"}]
I tried
some variable bezier parameters(to be optimized too):
ui = Table[u[i], {i, 2, Length[p] - 1}];
general bezier curve with variable control point :
bez[k_ ] := BezierFunction[k]
But optimization gives several errors
NMinimize[Sum[Norm[ bez[{p[[1]], {kx, ky}, p[[-1]]}][u[i]] - p[[i]]],
{i, 2, Length[p] - 1}],
Join[{kx, ky}, ui] ]
(*BezierFunction::invcpts: {{1,0},{kx,ky},{0,1}} should be a rectangular array of
machine-sized real numbers of any depth,
whose dimensions are greater than 1., ...*)
The argument of bez[...] is rectangular, though I don't understand the message.
What's wrong with my attempt? Thanks!
=> SOLUTION: Thanks a lot @SjoerdSmid
With userdefined bezier function bezCurve
bezCurve[{pt : {_, _}}] := pt &;
bezCurve[ctrlPts_?MatrixQ] := bezCurve[ctrlPts] = With[{
b1 = bezCurve[Most[ctrlPts]],b2 = bezCurve[Rest[ctrlPts]]}
, (1 - #)*b1[#] + #*b2[#] &];
bezCurve[ctrlPts_?MatrixQ, t_] := Simplify[bezCurve[ctrlPts][t]];
the optimization is done in ~7seconds
opt = NMinimize[{Sum[Norm[bezCurve[{p[[1]], {kx, ky}, p[[-1]]}][u[i]] - p[[i]]],
{i, 2,Length[p] - 1}],
Join[{0}, ui, {1}] /. List -> Less, 0 <= kx <= 1 , 0 <= ky <= 1},
Join[{kx, ky}, ui ]]
(*{1.22189, {kx -> 0.899875, ky -> 0.999976,
u[2] -> 0.152739, u[3] -> 0.152739,
u[4] -> 0.152739, u[5] -> 0.152739,u[6] -> 0.244299}}*)

bezis wrong. Just test it with any valid argument. – xzczd Oct 31 '19 at 08:44Show[{ParametricPlot[ bez[{p[[1]], {0.75, 0.75 }, p[[-1]]}][u], {u, 0, 1}], ListPlot[p]}]and it looks fine! – Ulrich Neumann Oct 31 '19 at 08:49bezis polluted. CheckDownValues@bez, thenClear@bezand retry. – xzczd Oct 31 '19 at 08:52Clear[bez]; bez[k_] := BezierFunction[k]the function can be plotted but the NMinimze-error is still present. – Ulrich Neumann Oct 31 '19 at 09:03NumericQ /@ {{1, 2}, {3, 4}}. Then, executeSum[Norm[ bez[{p[[1]], {kx, ky}, p[[-1]]}][u[i]] - p[[i]]], {i, 2, Length[p] - 1}]outside ofNMinimize, you'll seeu[5],u[6]therein. – xzczd Oct 31 '19 at 10:34ui. I modified my question. – Ulrich Neumann Oct 31 '19 at 10:42Clear@point; Norm[point - {1, 2}]and think about what's wrong here. – xzczd Oct 31 '19 at 10:51bez[...]is evaluated to a list of size 2, the argument ofNorm[bez[...],p[[i]]]is ok I think. – Ulrich Neumann Oct 31 '19 at 10:59Normwon't wait,NMinimizedoesn't haveHold*Attributes. – xzczd Oct 31 '19 at 11:02