2
$\begingroup$

Three months ago, I asked a question about How to build a function object like the built-ins?

Today, I used a solution proposed by István Zachar

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

CAGDBSplineFunction::invdeg = 
 "Value of option SplineDegree \[Rule] `1` should be a machine integer 
  or a symbol Automatic.";

CAGDBSplineFunction::invknots = 
 "Value of option SplineKnots \[Rule] `1` should be a valid knots sequence
  or a symbol Automatic.";

CAGDBSplineFunction /:
 MakeBoxes[obj_CAGDBSplineFunction, 
  form : (StandardForm | TraditionalForm)] :=
Module[{o = List @@ obj, n, crtlpts, shown, hidden, opts, options,
  icon = Graphics[{Blue, Circle[]}, ImageSize -> 35], sd, sk},
  ctrlpts = First@o;
  n = Length@crtlpts - 1;
  opts = Rest[o];
  options = Options[CAGDBSplineFunction];
  sd = SplineDegree /. opts /. options;
  sk = SplineKnots /. opts /. options;
  (*check the validness of SplineDegree*)
  If[! IntegerQ[sd],
   Message[CAGDBSplineFunction::invdeg, sd];
   Return[$Failed]
  ];

  (*check the validness of SplineKnots*)
  If[sk === Automatic, 
   sk = 
    Join[
     ConstantArray[0.0, sd + 1],
     Range[n - sd]/(n - sd + 1), ConstantArray[1.0, sd + 1]],
   If[n + 1 + sd != Length[sk] - 1 || ! OrderedQ[sk], 
    Message[CAGDBSplineFunction::invknots, sk, n + 2 + sd];
    Return[$Failed]
   ]
  ];
 shown =
   {{BoxForm`MakeSummaryItem[{"Argument count: ", 1}, form], SpanFromLeft},
    {BoxForm`MakeSummaryItem[{"Output dimention: ", 2}, form]}};
 hidden =
   {{BoxForm`MakeSummaryItem[{"Degree: ", sd}, form]},
    {BoxForm`MakeSummaryItem[{"Knots: ", sk}, form]}, 
    {BoxForm`MakeSummaryItem[{"Control points: ", ctrlpts}, form]}};
 BoxForm`ArrangeSummaryBox[
  CAGDBSplineFunction, o, icon, shown, hidden, form, 
  "Interpretable" -> False]
 ]

Test

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

enter image description here

However, when the option value of SplineDegree is invaid, Mathematcia will throw the following error:

CAGDBSplineFunction[pts, SplineDegree -> 2.3]

enter image description here

An unknown box name (Return) was sent as the BoxForm for the expression. Check the format rules for the expression.

$\endgroup$
  • 3
    $\begingroup$ I don't know what is the question but you may be interested in Return[$Failed, Module] instead of just Return[$Failed]. $\endgroup$ – Kuba Jan 12 '16 at 13:19
  • 2
    $\begingroup$ MakeBoxes is HoldAllComplete, and boxes are for display only. Therefore it is incumbent on you to ensure you pass fully-formed, correct expressions to MakeBoxes, so that within the generated boxes there is no Mathematica code. $\endgroup$ – Oleksandr R. Jan 12 '16 at 13:20
  • $\begingroup$ @Kuba Thanks a lot:) It works well. $\endgroup$ – xyz Jan 12 '16 at 13:29
  • 1
    $\begingroup$ @ShutaoTANG but this check, as pointed by Oleksandr R., should be included in the "kernel" code in the first place. $\endgroup$ – Kuba Jan 12 '16 at 13:42
  • $\begingroup$ @Kuba Sorry, what does the "included in the "kernel" code" mean? $\endgroup$ – xyz Jan 12 '16 at 23:27
3
$\begingroup$

So, extending comments. Quick fix is to use Return[$Failed, Module] here but it's not the right approach.

This SplineDegree should not reach MakeBoxes at all. Here's what should be done.

Imo, the user should not use CAGDBSplineFunction manually to create it, like in case of InterpolatingFunction it is created by something else, here Interpolation.

So in addition to your definitions you should have something like (minimal example):

Options[CAGDBSpline] = Options[CAGDBSplineFunction];

CAGDBSpline[pts_, patt : OptionsPattern[]] := Module[{
   sd = OptionValue@SplineDegree
   },
   If[ IntegerQ @ sd,
     CAGDBSplineFunction[pts, patt],
     Message[CAGDBSplineFunction::invdeg, sd]; $Failed
   ]
]

And CAGDBSpline is what the user should use. Now:

CAGDBSpline[pts, SplineDegree -> 4.5]

CAGDBSpline[pts, SplineDegree -> 1]

CAGDBSplineFunction::invdeg: Value of option SplineDegree -> 4.5` should be a machine integer or a symbol Automatic.

enter image description here

$\endgroup$
  • $\begingroup$ Namely, using another function CAGDBSpline. However, for the built-in BSplineFunction[], pts = {{1, 1}, {2, 3}, {3, -1}, {4, 1}, {5, 0}}; BSplineFunction[pts, SplineDegree -> 3.2] throws the error information BSplineFunction::invdeg. Did you know how to achieve that like BSplineFunction[] ? THX very much. $\endgroup$ – xyz Jan 13 '16 at 10:11
  • 1
    $\begingroup$ @ShutaoTANG They are using something like MakeBoxes[bsp_ BSplineFunction,fmt_]/;UseIcons&&ValidQ[Unevaluated[bsp]]:=makeSplineBoxes[bsp,fmt]; and it is makeSplineBoxes which creates the SummaryBox if ValidQ returns True. $\endgroup$ – Kuba Jan 13 '16 at 10:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.