9

There are many built-in functions that return a function object, such as Interpolation[], BSplineFunction[] ,LinearSolveFunction[] and so on.

enter image description here


Now given that I want to build a function called CAGDBSplineFunction[] like the built-in BSplineFunction[] with the help of Cox-DeBoor algorithm.

First trial, please see here

To achieve the dynamic effect and check the validity of the option like the built-in BSplineFunction

enter image description here

I refactored it as below:

CAGDBSplineFunction::invknots = 
  "Value of option SplineKnots \[Rule] `1` should be a non-decreasing \
   real sequence of length `2`, or a symbol Automatic.";

Options[CAGDBSplineFunction] = 
  {SplineDegree -> Automatic, SplineKnots -> Automatic};

CAGDBSplineFunction /: 
 MakeBoxes[CAGDBSplineFunction[pts_, opts : OptionsPattern[]], _] := 
 Module[{n, sk, sd, range},
  n = Length@pts - 1;
  sk = OptionValue[SplineKnots];
  sd = OptionValue[SplineDegree];
  (*check the validity of the option SplineKnots*)
  If[sk =!= Automatic,
   If[n + 1 + sd != Length[sk] - 1, 
    Message[CAGDBSplineFunction::invknots, sk, n + 2 + sd];
    Return[$Failed]];
    range = Through[{First, Last}@sk],
   range = {0, 1}
  ]
 ]
 InterpretationBox[
   RowBox[{"CAGDBSplineFunction", "[", "{", #1, ",", #2, "}", ",", 
   "\"<>\"", "]"}], CAGDBSplineFunction[pts, opts]] & @@ range
]

TEST

pts = {{0, 0}, {1, 1}, {2, -1}, {3, 0}, {4, -2}, {5, 1}};
f = CAGDBSplineFunction[pts]

enter image description here

However, it seems that the option value cannot be achieved in a MakeBoxes construct.

J.M. gives me the following suggestion:

Don't try to do both display and processing at once. Set a definition for evaluating CAGDBSplineFunction[], and then set a definition for displaying, via MakeBoxes

According to the J.M.'s hint, I add the defintion to CAGDBSplineFunction[]

CAGDBSplineFunction /: 
 MakeBoxes[CAGDBSplineFunction[pts_, opts : OptionsPattern[]], _] := 
  InterpretationBox[
    RowBox[{"CAGDBSplineFunction", "[", "{", #1, ",", #2, "}", ",", 
  "\"<>\"", "]"}], CAGDBSplineFunction[pts, opts]] & @@ 
    CAGDBSplineFunction[pts, opts]

CAGDBSplineFunction[pts_, opts : OptionsPattern[]] :=
 Module[
  {n, sk, sd, range},
  n = Length@pts - 1;
  sk = OptionValue[SplineKnots];
  sd = OptionValue[SplineDegree] /. Automatic -> 3;
  (*check the validity of the option SplineKnots*)
  If[sk =!= Automatic,
   If[n + 1 + sd != Length[sk] - 1, 
    Message[CAGDBSplineFunction::invknots, sk, n + 2 + sd];
    Return[$Failed]];
    range = Through[{First, Last}@sk],
   range = {0, 1}
  ]
 ]

enter image description here

xyz
  • 605
  • 4
  • 38
  • 117
  • 3
    Something like constructor[pts_, deg_] := excecutor[someStructure[pts, deg]]; excecutor[someStructure[pts_, deg_]][t_] := doSomething[someStructure[pts, deg, t]]; myfun = constructor[{{1, 1}, {2, 2}}, 1]; myfun[t] ? – Dr. belisarius Oct 12 '15 at 06:12
  • 2
    With respect to version 10-style output formatting of such functions, see this. – J. M.'s missing motivation Oct 12 '15 at 06:30
  • 1
    You coud try an approach similar to this. – J. M.'s missing motivation Oct 12 '15 at 07:45
  • That was supposed to be the "simple demo". Did you look at how the function's output format was implemented, and how the evaluation is done? – J. M.'s missing motivation Oct 12 '15 at 08:43
  • 4
    (1) Construction: Define makemyfn[stuff_] to return object myfn[data]. (2) Format myfn with with MakeBoxes as in the linked questions in the comments. (3) Computation: Define sub-value myfn[datastructure_][input_] := (* computation *) for the computation, using whatever patterns for datastructure that are appropriate. -- Which is what belisarius said, but seems to have been ignored? – Michael E2 Oct 12 '15 at 10:25
  • 2
    You could separate the function that creates the function object from the function object itself. Interpolation is distinct from InterpolatingFunction. The insides of the latter are of no concern to users, thus there's no need to do syntax checking on them. – Szabolcs Oct 18 '15 at 15:23
  • 1
    @Szabolcs, thanks a lot for your suggestion, could you give me a specific example? I need to learn how the built-in construct the function object. In addition, the built-in BSplineFunction indeed do the syntax checking. For instance,f = BSplineFunction[{{1, 1}, {2, 3}, {3, -1}, {4, 1}, {5, 0}}, SplineKnots -> {1, 2, 3}] throws the error info BSplineFunction::invknots – xyz Oct 18 '15 at 15:41
  • 1
    In that case, the definition would look like BSplineFunction[pts_, opts : OptionsPattern[]] := Module[{(* stuff *)}, (* stuff *) If[testQ[OptionValue[SplineKnots]], (* throw messages *)]; (* more stuff *) BSplineFunction[(* internal data *)]]. The idea is to have two definitions for BSplineFunction[]: one where it processes data into a definite internal format, and one where its arguments are already in the internal format. The formatting rules are then applied to the latter one. – J. M.'s missing motivation Oct 18 '15 at 16:42

1 Answers1

4

It is not easy to show the domain dynamicly when the domain was been given by the option, for instance, in your function CAGDBSplineFunction,the option SplineKnots -> Automatic.

In the SphericalLinearInterpolation[], the range was given by the arguments, rather than the option. So it is easy to implement the dynamic domain by pure function.

MakeBoxes[SphericalInterpolatingFunction[range_, rest__], _] ^:= 
 InterpretationBox[
  RowBox[
   {"SphericalInterpolatingFunction", "[", "{", #1, ",",
     #2, "}", ",", "\"<>\"", "]"}], 
SphericalInterpolatingFunction[range, rest]] & @@ Map[ToBoxes, range]

To achieve the goal, you should reference the package Splines in your Mathematica install directory

XXX\Wolfram Research\Mathematica\9.0\AddOns\Packages\Splines

For instance, the following code can help you(Notice the defintion of the SubValues of SplineFunction[type, {min, max}, pts,internal])

Format[SplineFunction[t_,r_, b__]] :=
Row[{"SplineFunction[",t,", ", r,", ","<>","]"}]

SplineFunction[type_, {min_, max_}, pts_,internal_][in_?(NumberQ[N[#]]&)] :=
Module[{out},
    If[in < min || in > max,
        Message[SplineFunction::dmval, in];
        out = $Failed,
  (* else *)
   out = evalspline[
     Which[in == max, Min[max, in],
        in == min, Max[min, in],
        True, in], type, pts, internal]
  ];
  out/;out =!= $Failed
]

Format[CAGDBSplineFunction1[pts_, opts : OptionsPattern[]]] :=
 Module[{n, sk, range},
  sk = SplineKnots /. {opts} /. Options[CAGDBSplineFunction];
  If[sk === Automatic, 
    range = {0, 1}, 
    range = Through[{First, Last}@sk]
  ];
 Row[
   {"CAGDBSplineFunction1", "[", "{", sk, , ",", range, "}", ",", 
   "<>", "]"}]    
 ]

pts = {{0, 0}, {1, 1}, {2, -1}, {3, 0}, {4, -2}, {5, 1}};
CAGDBSplineFunction[pts, SplineKnots -> Range[0, 9]]

enter image description here

In addition, you should not use the OptionValue, rather than SplineKnots /. {opts} /. Options[CAGDBSplineFunction]

enter image description here