<?xml version="1.0" encoding="UTF-8"?>
<quiz>
<!-- question: 0  -->
  <question type="category">
    <category>
      <text>$course$/top/Grundlagen der mehrdimensionalen Analysis</text>
    </category>
    <info format="moodle_auto_format">
      <text></text>
    </info>
    <idnumber></idnumber>
  </question>

<!-- question: 0  -->
  <question type="category">
    <category>
      <text>$course$/top/Grundlagen der mehrdimensionalen Analysis/Taylor und Approximation von Funktionen</text>
    </category>
    <info format="moodle_auto_format">
      <text></text>
    </info>
    <idnumber></idnumber>
  </question>

<!-- question: 0  -->
  <question type="category">
    <category>
      <text>$course$/top/Grundlagen der mehrdimensionalen Analysis/Taylor und Approximation von Funktionen/Taylorpolynom und Entwicklungspunkt</text>
    </category>
    <info format="moodle_auto_format">
      <text></text>
    </info>
    <idnumber></idnumber>
  </question>

<!-- question: 966524  -->
  <question type="stack">
    <name>
      <text>Entwicklungspunkt (1)</text>
    </name>
    <questiontext format="html">
      <text><![CDATA[<p style="text-align: justify;"> Betrachten Sie die Funktion</p>
<p style="text-align: justify; margin-left:30px">\(\displaystyle {@FuncName@} : \mathbb{R}^2 \to \mathbb{R}\), \((x,y) \mapsto {@SelectedFunction@}\)</p>
<p style="text-align: justify;">
und ein Taylorpolynom \(T_{{@Order@}}{@FuncName@}\) {@NumberWords[Order+1]@} Grades von \({@FuncName@}\).</p>
<hr>
<p style="text-align: justify;">Die folgende Abbildung zeigt den Graphen von \({@FuncName@}\) (Graph <font color="#648FFF">&#x25A1</font>) und den Graphen von  \(T_{{@Order@}}{@FuncName@}\) (Graph <font color="#FE6100">&#x25A1</font>) auf dem Einheitsquadrat \([-1,1]^2\) in der \(x_1 x_2\)-Ebene von \(\mathbb{R}^3\) aufgezeichnet gegen die \(x_3\)-Achse. Sie können das Funktionsargument in der \(x_1 x_2\)-Ebene verschieben (Punkt <font color="#DC267F">&#x25CF</font>). Die zugehörigen Funktionswerte unter \({@FuncName@}\) und \(T_{@FuncName@}\) werden Ihnen durch Angabe der zugehörigen Punkte auf den Graphen angezeigt (Punkt <font color="#648FFF">&#x25CF</font> bzw. Punkt <font color="#FE6100">&#x25CF</font>).</p>
<p style="text-align: justify;">
[[jsxgraph input-ref-ans1="stateRef"]]
const board = JXG.JSXGraph.initBoard(divid, {
  boundingbox: [-1.9, 1.9, 1.9, -1.9],
  axis: false,
  showCopyright: false,
  keepaspectratio: true,
/*  showNavigation: false, */
  fixed: true
});

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- STACK to JSXGraph interface ---- */

var state = {#Argument#};
state[2] = {#SliderPos#}[0]; /* position of slider 'SliderAngleOfProj1' */
state[3] = {#SliderPos#}[1];; /* position of slider 'SliderAngleOfProj2' */
var stateInput = document.getElementById(stateRef);
  if (stateInput.value && stateInput.value != '') {
    state = JSON.parse(stateInput.value);
  }

/* definition of (approximated) function */
var ExFunc = board.jc.snippet('{#SelectedFunction#}', true, 'x,y', true);

/* definition of approximating function */
var StrApproxFunc = '{#ListOfFunctions#}'.substring(1, '{#ListOfFunctions#}'.length - 1);
var SplitStrApproxFunc = StrApproxFunc.split(",");
var MaxOrder = SplitStrApproxFunc.length - 1;

/* order / degree of the polynomial approximation */
var Order = {#Order#}; 

/* initial coordinates of the point of development */
var PointOfDevInit = [{#PointOfDev#}[0], {#PointOfDev#}[1]]; 

/* resolution of the grid */
var ResOfGrid = {#ResOfGrid#};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- colors ---- */

  const Color1 = `hsl(${223}, ${100}%, ${70}%)`; /* #648FFF */
  const Color2 = `hsl(${251}, ${83}%, ${65}%)`; /* #785EF0 */
  const Color3 = `hsl(${331}, ${72}%, ${51}%)`; /* #DC267F */
  const Color4 = `hsl(${23}, ${100}%, ${50}%)`; /* #FE6100 */
  const Color5 = `hsl(${41}, ${100}%, ${50}%)`; /* #FFB000 */

/* ------------------------------------- */
/* --------------------------------------*/

/* draws slider controlling the order of the approximating function */
var SliderOrder = board.create('slider', [
  [-1.3, -1.75],
  [1.2, -1.75],
  [0, Order, MaxOrder]
], {
  withLabel: true,
  highlight: false,
  name: 'order',
  snapWidth: 1,
  visible: false,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});

/* order of the approximating function */
var Order = function(n) {
  return n <= SliderOrder.Value()
};

/* definition of approximating function */
var ApproxFuncList = [];
for (var i = 0; i <= MaxOrder; i++) {
  ApproxFuncList.push(board.jc.snippet(SplitStrApproxFunc[i], true, 'x,y,a,b', true))
}
var ApproxFunc = function(x, y, a, b) {
  return ApproxFuncList[SliderOrder.Value()](x, y, a, b)
};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- general operations on vectors and matrices ---- */

/* vector product */
var NormalVec = function(a, b) {
  return [
    ((a[1] * b[2]) - (a[2] * b[1])),
    ((a[2] * b[0]) - (a[0] * b[2])),
    ((a[0] * b[1]) - (a[1] * b[0]))
  ]
};
/* euclidean scalar product */
var ScalarProd = function(a, b) {
  return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2])
};
/* euclidean norm of vector */
var EuclidNorm = function(a) {
  return Math.sqrt(ScalarProd(a, a))
};
/* multiplication of scalar vectors */
var ScalarMultVec = function(x, a) {
  return [x * a[0], x * a[1], x * a[2]]
};
/* entrywise multiplication of vectors */
var VecMultVec = function(a, b) {
  return [a[0] * b[0], a[1] * b[1], a[2] * b[2]]
};
/* sum of vectors */
var VecSumVec = function(a, b) {
  return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]
};
/* difference of vectors */
var VecSubVec = function(a, b) {
  return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
};
/* euclidean distance of vectors */
var EuclidDist = function(a, b) {
  return EuclidNorm(VecSubVec(a, b))
}

/* multiplication of scalar matrix*/
var ScalarMultMat = function(x, A) {
  return [ScalarMultVec(x, A[0]), ScalarMultVec(x, A[1]), ScalarMultVec(x, A[2])]
}
/* normalizes non-zero vector */
var UnitVec = function(a) {
  let x = Math.sqrt(ScalarProd(a, a));
  let b = ScalarMultVec(x, a);
  return b;
}

/* determinant of matrix*/
var DetOfMat = function(A) {
  return ScalarProd(A[0], NormalVec(A[1], A[2]))
};

/* transpose of matrix */
var TranspOfMat = function(A) {
  let B1 = [A[0][0], A[1][0], A[2][0]];
  let B2 = [A[0][1], A[1][1], A[2][1]];
  let B3 = [A[0][2], A[1][2], A[2][2]];
  return [B1, B2, B3];
}
/* pre-inverse of matrix */
var PreInvOfMat = function(A) {
  let B = TranspOfMat(A);
  let b1 = NormalVec(B[1], B[2]);
  let b2 = NormalVec(B[2], B[0]);
  let b3 = NormalVec(B[0], B[1]);
  let C = [b1, b2, b3];
  return C;
};

/* inverse of matrix */
var InvOfMat = function(A) {
  let B = PreInvOfMat(A);
  let b = 1 / DetOfMat(A);
  return ScalarMultMat(b, B);
};
/* matrix applied as linear map to vector */
var MatMultVec = function(a, A) {
  let b1 = ScalarProd(A[0], a);
  let b2 = ScalarProd(A[1], a);
  let b3 = ScalarProd(A[2], a);
  return [b1, b2, b3];
}

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- sliders for controlling the camera ---- */ 

var SliderAngleOfProj1 = board.create('slider', [
  [-1.75, -1.3],
  [-1.75, 1.3],
  [0.005, state[2], 0.5]
], {
  withLabel: true,
  highlight: false,
  name: 'el',
  postLabel: ' &pi;',
  snapWidth : 0.01,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});
var SliderAngleOfProj2 = board.create('slider', [
  [-1.3, -1.6],
  [1.2, -1.6],
  [-1, state[3], 1]
], {
  withLabel: true,
  highlight: false,
  name: 'az',
  postLabel: ' &pi;',
  snapWidth : 0.01,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});


var AOP1 = function() {
  return SliderAngleOfProj1.Value() * Math.PI
};
var AOP2 = function() {
  return (SliderAngleOfProj2.Value() + 1) * Math.PI
};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- 3D to 2D projection ---- */

/* angles for 2D projection */
var cpsi = function() {
  return Math.cos(AOP2())
};
var spsi = function() {
  return Math.sin(AOP2())
};
var cphi = function() {
  return Math.cos(AOP1())
};
var sphi = function() {
  return Math.sin(AOP1())
};
/* matrix for 2D projection */
var ProjMat2D = function() {
  return [
    [(-1) * cpsi(), spsi(), 0],
    [(-1) * spsi() * sphi(), (-1) * cpsi() * sphi(), cphi()],
    [0, 0, 1]
  ]
};
/* returns 2D coordinates of 3D objects */
var CamProjection = function(a) {
  let Output = MatMultVec(a, ProjMat2D());
  return [Output[0], Output[1]];
}

var CamInv = function(a) {
  let Output = MatMultVec([a[0], a[1], a[2]], InvOfMat(ProjMat2D()));
  return [Output[0], Output[1], Output[2]];
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- coordinate system ---- */

/* 3D coordinates of arrows in dicating the coordinate system */
var AxisCoords = function(h) {
  /* initial coordinates */
  let ICs0 = [0, 0, h];
  let ICs1 = [1.2, 0, h];
  let ICs2 = [0, 1.2, h];
  let ICs3 = [0, 0, 1.2 + h];
  /* ---- */
  let ICs4 = [-1.1, 0, h];
  let ICs5 = [0, -1.1, h];
  return [
    CamProjection(ICs0),
    CamProjection(ICs1),
    CamProjection(ICs2),
    CamProjection(ICs3),
    CamProjection(ICs4),
    CamProjection(ICs5),
  ]
};

/* 3D coordinates of labels of coordinate system*/
var AxisLabelPos = function(h) {
  /* initial coordinates */
  let ICs1 = [1.3, 0, h];
  let ICs2 = [0, 1.3, h];
  let ICs3 = [0, 0, 1.3 + h];
  return [
    CamProjection(ICs1),
    CamProjection(ICs2),
    CamProjection(ICs3)
  ]
};
/* labels of coordinate system*/
var AxisLabel = ['x_1', 'x_2', 'x_3'];

/* draws arrows indicating the coordinates system */
for (let i = 0; i <= 2; i++) {
  board.create('arrow', [
    [() => AxisCoords(0)[0][0], () => AxisCoords(0)[0][1]],
    [() => AxisCoords(0)[i + 1][0], () => AxisCoords(0)[i + 1][1]]
  ], {
    strokecolor: 'black',
    strokeWidth: 1.2,
    layer: 1,
    highlight: false,
    fixed: true,
  });
  /* draws labels of coordinates system */
  board.create('text', [() => AxisLabelPos(0)[i][0], () => AxisLabelPos(0)[i][1], AxisLabel[i]]);
}

/* draws arrows indicating the coordinates system in the domain */
for (let i = 0; i <= 1; i++) {
  board.create('arrow', [
    [() => AxisCoords(-1)[i + 4][0], () => AxisCoords(-1)[i + 4][1]],
    [() => AxisCoords(-1)[i + 1][0], () => AxisCoords(-1)[i + 1][1]]
  ], {
    strokecolor: 'grey',
    strokeWidth: 1.2,
    layer: 1,
    highlight: false,
    fixed: true,
  });
  /* draws labels of coordinates system */
  board.create('text', [() => AxisLabelPos(-1)[i][0], () => AxisLabelPos(-1)[i][1], AxisLabel[i]], {
    strokeColor: 'grey',
  });
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- collection of functions that draw grids and graphs ---- */

/* function that returns 2D coordinates of given 'grid' */
var GridCoordsConv = function(G) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = [CamProjection(G[0][i][0]), CamProjection(G[0][i][1])];
    ICsY[i] = [CamProjection(G[1][i][0]), CamProjection(G[1][i][1])];
  }
  return ([ICsX, ICsY])
}

/* function that draws given 2D grid */
var DrawGrid = function(G) {
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    board.create('segment', [() => G()[0][i][0], () => G()[0][i][1]], {
      strokecolor: 'lightgrey',
      strokeWidth: 1,
      layer: 0,
      highlight: false,
      fixed: true,
    });
    board.create('segment', [() => G()[1][i][0], () => G()[1][i][1]], {
      strokecolor: 'lightgrey',
      strokeWidth: 1,
      layer: 0,
      highlight: false,
      fixed: true,
    });
  }
}

/* function that draws a line segment between points in 3D */
var DrawSegment = function(p, q, C, D) {
  board.create('segment', [() => CamProjection(p()), () => CamProjection(q())], {
    strokecolor: C,
    strokeWidth: 1,
    layer: 0,
    highlight: false,
    fixed: true,
    dash: D,
  });
}

/* function that return parametrization of line segment between points in 3D */
var LineParam = function(p, q) {
  return function(t) {
    return VecSumVec(ScalarMultVec(t, p), ScalarMultVec((1 - t), q))
  }
}

/* function that returns 3D coordinate lines as functions on [0,1] */
var GridParam = function(G) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = LineParam(G()[0][i][0], G()[0][i][1]);
    ICsY[i] = LineParam(G()[1][i][0], G()[1][i][1]);
  }
  return ([ICsX, ICsY])
}

/* function that returns image of 3D coordinate lines as 2D functions on [0,1] */
var ImGridParam = function(P, F) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = function(t) {
      return CamProjection([P[0][i](t)[0], P[0][i](t)[1], F(P[0][i](t)[0], P[0][i](t)[1])])
    };
    ICsY[i] = function(t) {
      return CamProjection([P[1][i](t)[0], P[1][i](t)[1], F(P[1][i](t)[0], P[1][i](t)[1])])
    };
  }
  return ([ICsX, ICsY])
}

/* function that draws image of given 3D grid under given function */
var DrawGraph = function(P, F, C) {
  let ICs = ImGridParam(P, F);
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    board.create('curve', [function(t) {
        return ICs[0][i](t)[0]
      },
      function(t) {
        return ICs[0][i](t)[1]
      },
      0, 1
    ], {
      strokecolor: C,
      strokeWidth: 1,
      layer: 2,
      highlight: false,
      fixed: true,
      doAdvancedPlot: false,
      numberPointsHigh: FidHigh,
      numberPointsLow: FidLow,
    });
    board.create('curve', [function(t) {
        return ICs[1][i](t)[0]
      },
      function(t) {
        return ICs[1][i](t)[1]
      },
      0, 1
    ], {
      strokecolor: C,
      strokeWidth: 1,
      layer: 2,
      highlight: false,
      fixed: true,
      doAdvancedPlot: false,
      numberPointsHigh: FidHigh,
      numberPointsLow: FidLow,
    });
  }
}

/* function that draws the point on the graph a given function for a given 3D point in the domain */
var DrawPoint = function(P, F, C) {
  let ICs3D = function() {
    return [P()[0], P()[1], F(P()[0], P()[1])]
  };
  let ICs2D = function() {
    return CamProjection(ICs3D())
  };
  let IC = board.create('point', [() => ICs2D()[0], () => ICs2D()[1]], {
    color: Color4
  });
  IC.setAttribute({
    showInfobox: false,
    layer: 3,
    color: C,
    highlight: false,
    name: function() {
      return '(' + JXG.toFixed(
          ICs3D()[0], 2) + ', ' +
        JXG.toFixed(
          ICs3D()[1], 2) + ', ' +
        JXG.toFixed(
          ICs3D()[2], 2) + ')'
    }
  });
  DrawSegment(P, ICs3D, 'grey', 2);
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- definition of grid in domain ---- */

var FidHigh = 600 / ResOfGrid;
var FidLow = 200 / ResOfGrid;
var SizeOfGrid = 1;
var StepOfGrid = SizeOfGrid / ResOfGrid;

/* 3D coordinates of grid in domain */
var GridDomain3D = function() {
  /* initial coordinates */
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = [
      [-SizeOfGrid + i * StepOfGrid, -SizeOfGrid, -1],
      [-SizeOfGrid + i * StepOfGrid, SizeOfGrid, -1]
    ];
    ICsY[i] = [
      [-SizeOfGrid, -SizeOfGrid + i * StepOfGrid, -1],
      [SizeOfGrid, -SizeOfGrid + i * StepOfGrid, -1]
    ];
  }
  return ([ICsX, ICsY])
}

/* 2D coordinates of grid in domain */
var GridDomain = function() {
  return GridCoordsConv(GridDomain3D())
};

DrawGrid(GridDomain);

var GridDomainParam = GridParam(GridDomain3D);

/* ------------------------------------- */
/* ------------------------------------- */

/* draws point in domain at which the taylor polynomial is developed */
var PointOfDev = board.create('point', CamProjection([PointOfDevInit[0], PointOfDevInit[1], -1]),{visible: false});
var PointOfDev3D = function() {
/*  return CamInv([PointOfDev.X(), PointOfDev.Y(), -1]) */
  return [PointOfDevInit[0], PointOfDevInit[1], -1]
};

PointOfDev.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return '(' + JXG.toFixed(
        PointOfDev3D()[0], 2) + ', ' +
      JXG.toFixed(
        PointOfDev3D()[1], 2) + ')'
  }
});

/* draws dashed lines to indicate position of PointOfDev and PointOnGraph*/
/* DrawSegment(PointOfDev3D, () => [PointOfDev3D()[0], 0, PointOfDev3D()[2]], 'grey', 2); */
/* DrawSegment(PointOfDev3D, () => [0, PointOfDev3D()[1], PointOfDev3D()[2]], 'grey', 2); */

/* ------------------------------------- */
/* ------------------------------------- */

/* draws arbitrary point in domain to visualize difference between (approximated) function and approximating function */
var ArbPointInDom = board.create('point', CamProjection([state[0], state[1], -1]));
var ArbPointInDom3D = function() {
  return CamInv([ArbPointInDom.X(), ArbPointInDom.Y(), -1])
};

ArbPointInDom.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return '(' + JXG.toFixed(
        ArbPointInDom3D()[0], 2) + ', ' +
      JXG.toFixed(
        ArbPointInDom3D()[1], 2) + ')'
  }
});

/* draws dashed lines to indicate position of PointOfDev and PointOnGraph*/
DrawSegment(ArbPointInDom3D, () => [ArbPointInDom3D()[0], 0, ArbPointInDom3D()[2]], 'grey', 2);
DrawSegment(ArbPointInDom3D, () => [0, ArbPointInDom3D()[1], ArbPointInDom3D()[2]], 'grey', 2);

/* ------------------------------------- */
/* ------------------------------------- */

var PointDefRad = board.create('point', CamProjection([0.3, 0.3, -1]), {
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: false,
  visible : false,
});
var PointDefRad3D = function() {
  return CamInv([PointDefRad.X(), PointDefRad.Y(), -1])
};

var RadiusOfCircle = function() {
  return EuclidDist(ArbPointInDom3D(), PointDefRad3D())
}

PointDefRad.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return JXG.toFixed(RadiusOfCircle(), 2)
  }
});

/* function that draws image of circle at given 3D point with given radius under given function */
var DrawCircleAtPoint = function(P, r, F, C) {
  let ICsX = function(t) {
    return P()[0] + r() * Math.cos(t)
  };
  let ICsY = function(t) {
    return P()[1] + r() * Math.sin(t)
  };
  let ICsZ = function(t) {
    return F(ICsX(t), ICsY(t))
  };
  let UCs = function(t) {
    return CamProjection([ICsX(t), ICsY(t), ICsZ(t)])
  };
  board.create('curve', [function(t) {
      return UCs(t)[0]
    },
    function(t) {
      return UCs(t)[1]
    },
    0, 6.5
  ], {
    strokecolor: C,
    strokeWidth: 1,
    layer: 2,
    highlight: false,
    fixed: true,
    doAdvancedPlot: false,
    numberPointsHigh: FidHigh * 2,
    numberPointsLow: FidLow * 2,
  });
}

/* draw circles at point in domain and their images */

/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, () => -1, Color3); */
/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, ExFunc, Color4); */
/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4); */

/* ------------------------------------- */
/* ------------------------------------- */

/* draws images of points in domain */

/* DrawPoint(PointOfDev3D, ExFunc, 'Grey'); */
DrawPoint(ArbPointInDom3D, ExFunc, Color1);
DrawPoint(ArbPointInDom3D, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4);

/* ------------------------------------- */
/* ------------------------------------- */

/* draw graph of (approximated) function */
DrawGraph(GridDomainParam, ExFunc, Color1)

/* draw graph of approximating function */
DrawGraph(GridDomainParam, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4)

/* ------------------------------------- */
/* ------------------------------------- */

  /* returns point in domain close to given point */
  var ReturnToDomain =
    function(a) {
      let Output = [];
      if (a[0] < -1) {
        Output[0] = -1;
      } else if (a[0] > 1) {
        Output[0] = 1;
      } else {
        Output[0] = a[0];
      }
      if (a[1] < -1) {
        Output[1] = -1;
      } else if (a[1] > 1) {
        Output[1] = 1;
      } else {
        Output[1] = a[1];
      }
      Output[2] = a[2];
      return Output
    };

board.on('move', function() {
  board.suspendUpdate();
  PointOfDev.moveTo(CamProjection(ReturnToDomain(PointOfDev3D())));
  ArbPointInDom.moveTo(CamProjection(ReturnToDomain(ArbPointInDom3D())));
  PointDefRad.moveTo(CamProjection(ReturnToDomain(PointDefRad3D())));
  board.unsuspendUpdate();
});

/* ------------------------------------- */
/* ------------------------------------- */

var newState =  [Math.round(ArbPointInDom3D()[0]*100)/100, Math.round(ArbPointInDom3D()[1]*100)/100, SliderAngleOfProj1.Value(),SliderAngleOfProj2.Value()];
var ClickIndicator = 0;

var SendData = function(){
     newState = [Math.round(ArbPointInDom3D()[0]*100)/100, Math.round(ArbPointInDom3D()[1]*100)/100,SliderAngleOfProj1.Value(),SliderAngleOfProj2.Value()];
     stateInput.value = JSON.stringify(newState);
     stateInput.dispatchEvent(new Event('change'));
}

ArbPointInDom.on('drag', function () {
   SendData();
});

stateInput.style.display = 'none';

/* ------------------------------------- */
/* ------------------------------------- */

/* ensures that all draggable points (e.g. PointOfDev, ArbPointInDom) are rotatated accordingly when angles of projections are changed by sliders */

/* Buffer */
var PointOfDevBuffer = PointOfDev3D();
var ArbPointInDomBuffer = ArbPointInDom3D();
var PointDefRadBuffer = PointDefRad3D();

/* function that updates position of objects */

var UpdatePos = function(){
    let ICs1 = CamProjection(PointOfDevBuffer);
    let ICs2 = CamProjection(ArbPointInDomBuffer);
    let ICs3 = CamProjection(PointDefRadBuffer);
    board.suspendUpdate();
    PointOfDev.moveTo([
      ICs1[0],
      ICs1[1]
    ]);
    ArbPointInDom.moveTo([
      ICs2[0],
      ICs2[1]
    ]);
    PointDefRad.moveTo([
      ICs3[0],
      ICs3[1]
    ]);
    board.unsuspendUpdate();
   SendData();
}

SliderAngleOfProj1.on('down', function() {
  PointOfDevBuffer = PointOfDev3D();
  ArbPointInDomBuffer = ArbPointInDom3D();
  PointDefRadBuffer = PointDefRad3D();
  SliderAngleOfProj1.on('drag', function() {
  UpdatePos()
  });
});

SliderAngleOfProj2.on('down', function() {
  PointOfDevBuffer = PointOfDev3D();
  ArbPointInDomBuffer = ArbPointInDom3D();
  PointDefRadBuffer = PointDefRad3D();
  SliderAngleOfProj2.on('drag', function() {
  UpdatePos()
  });
});

ArbPointInDom.on('down', function() {
  PointDefRadBuffer = VecSubVec(ArbPointInDom3D(), PointDefRad3D());
  ArbPointInDom.on('drag', function() {
    let ICs = CamProjection(VecSubVec(ArbPointInDom3D(), PointDefRadBuffer));
    board.suspendUpdate();
    PointDefRad.moveTo([
      ICs[0],
      ICs[1]
    ]);
    board.unsuspendUpdate();
  });
});

/* ------------------------------------- */
/* ------------------------------------- */

[[/jsxgraph]]</p>
<hr>
<p style="text-align: justify;">Geben Sie mithilfe der obigen Abbildung einen Entwicklungspunkt \((a,b) \in [-1,1]^2\) des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\) an. Verschieben Sie dazu das Funktionsargument in der \(x_1 x_2\)-Ebene (Punkt <font color="#DC267F">&#x25CF</font>) an die Position eines Entwicklungspunktes. [[input:ans1]]</p>
<p style="text-align: justify;">[[validation:ans1]]</p>
<p style="text-align: justify;">[[feedback:prt1]]</p>
<hr>]]></text>
    </questiontext>
    <generalfeedback format="html">
      <text><![CDATA[<p style="text-align: justify;">Ein Taylorpolynom {@NumberWords[Order+1]@} Grades von \({@FuncName@}\) am Entwicklungspunkt \((a,b)\) ist genau der Funktionswert von \({@FuncName@}\) an \((a,b)\). Folglich ist \((a,b)\) genau dann ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\), wenn</p>
<p style="text-align: justify;margin-left:30px">\(\displaystyle
T_{{@Order@}}{@FuncName@}(a,b) = {@FuncName@}(a,b)
\)</p>
<p style="text-align: justify;">ist. Dies ist an dem Punkt \(({@PointOfDev[1]@}, {@PointOfDev[2]@})\) erfüllt.</p>]]></text>
    </generalfeedback>
    <defaultgrade>1.0000000</defaultgrade>
    <penalty>0.0000000</penalty>
    <hidden>0</hidden>
    <idnumber></idnumber>
    <stackversion>
      <text>2023010400</text>
    </stackversion>
    <questionvariables>
      <text><![CDATA[/* --------------------------- */
/* --------------------------- */

/* Darstellung */

NumberWords : ["nullten", "ersten", "zweiten", "dritten", "vierten", "fünften", "sechsten", "siebten", "achten", "neunten", "zehnten", "elften", "zwölften"];

ResOfGrid : 5; /* Gitterabstand (-> Abbildung) */
SliderPos : [0.1,-0.65]; /* Position der Kameraslider bei Initialisierung (-> Abbildung) */

/* --------------------------- */
/* --------------------------- */

/* Definition / Randomisierung */

/* Auswahl der (zu approximierenden) Funktion */

ExpList : random_permutation([0,1,2]);
b1 : ExpList[1];
b2 : 2-b1;
c1 : ExpList[2];
c2 : 2-c1;

a1 : rand([-1,1]);
a2 : rand([-a1,1]);

Polynomial: a1*(x^b1*y^b2 + x^c1*y^c2);

TFunc1: rand([cos(a),sin(a)]);
SelectedFunction: subst(Polynomial, a , TFunc1)

/* --------------------------- */

/* Koordinaten des Entwicklungspunkts 'PointOfDev': Die Koordinaten des Entwicklungspunktes sind so gewählt, dass '[0,0]' kein Entwicklungspunkt des zugehörigen Taylorpolynoms ist (relevant für Ordnung null)*/

ListOfCoord : random_permutation([4,6,8]);
PointOfDevX : float(a1*ListOfCoord[1]/10);
PointOfDevY : float(a2*ListOfCoord[2]/10);

PointOfDev : [PointOfDevX,PointOfDevY]; /* Entwicklungspunkt */

/* --------------------------- */
/* --------------------------- */

/* Definitionen */

FuncName : f; /* Bezeichner der Funktion */
Argument : [0,0]; /* Funktionsargument (-> Abbildung); sollte ungleich 'PointOfDev' gewählt werden */
Order : 0; /* Ordnung der Taylor-Entwicklung (-> Abbildung; kleiner oder gleich 'MaxOrder') */
MaxOrder : 1; /* maximale Ordnung der Taylor-Entwicklung (-> Abbildung; mindestens 1) */

/* --------------------------- */

/* Liste aller Taylor-Polynome bis zur maximalen Ordnung */
ListOfFunctions:[]
IndexOrder: 0;
while length(ListOfFunctions) <= max(MaxOrder,Order) do (
  ListOfFunctions : append(ListOfFunctions,[expand(taylor(SelectedFunction, [x,y], [a,b], IndexOrder))]),
  IndexOrder : IndexOrder + 1
);

/* --------------------------- */

/* Antworten */
TeacherAnswerA : append(PointOfDev, SliderPos);
WrongAnswer : [0,0];

/* --------------------------- */
/* --------------------------- */

/* Hilsfunktionen */

ListSubst(SList,List,Expr) := 
  block([Length, Index, OutPut],
    Length : min(length(SList),length(List)),
    Index : 1,
    Output : Expr,
    while Index <= Length do (
      Output : subst(SList[Index], List[Index], Output),
      Index : Index + 1
    ),
    Output
  );

/* --------------------------- */
/* --------------------------- */

/* Benjamin Herbert Schulz-Rosenberger */]]></text>
    </questionvariables>
    <specificfeedback format="html">
      <text></text>
    </specificfeedback>
    <questionnote>
      <text>\[\textstyle f(x,y)={@ SelectedFunction@}\]</text>
    </questionnote>
    <questionsimplify>1</questionsimplify>
    <assumepositive>0</assumepositive>
    <assumereal>0</assumereal>
    <prtcorrect format="html">
      <text></text>
    </prtcorrect>
    <prtpartiallycorrect format="html">
      <text></text>
    </prtpartiallycorrect>
    <prtincorrect format="html">
      <text></text>
    </prtincorrect>
    <multiplicationsign>none</multiplicationsign>
    <sqrtsign>1</sqrtsign>
    <complexno>i</complexno>
    <inversetrig>cos-1</inversetrig>
    <logicsymbol>lang</logicsymbol>
    <matrixparens>(</matrixparens>
    <variantsselectionseed></variantsselectionseed>
    <input>
      <name>ans1</name>
      <type>algebraic</type>
      <tans>TeacherAnswerA</tans>
      <boxsize>15</boxsize>
      <strictsyntax>1</strictsyntax>
      <insertstars>0</insertstars>
      <syntaxhint></syntaxhint>
      <syntaxattribute>0</syntaxattribute>
      <forbidwords></forbidwords>
      <allowwords></allowwords>
      <forbidfloat>0</forbidfloat>
      <requirelowestterms>0</requirelowestterms>
      <checkanswertype>0</checkanswertype>
      <mustverify>0</mustverify>
      <showvalidation>0</showvalidation>
      <options></options>
    </input>
    <prt>
      <name>prt1</name>
      <value>1.0000000</value>
      <autosimplify>1</autosimplify>
      <feedbackstyle>1</feedbackstyle>
      <feedbackvariables>
        <text><![CDATA[/* --------------------- */

StudentAnswer : [ans1[1],ans1[2]];

/* --------------------- */

/* 'StudentAnswerValue' gibt an, ob 'ans1' in dem Einheitsquadrat [-1,1]^2 enthalten ist. */

StudentAnswerCond : false;
if length(StudentAnswer) = 2 then (
StudentAnswerCond : is(StudentAnswer[1] >= -1) and is(StudentAnswer[1] <= 1) and is(StudentAnswer[2] >= -1) and is(StudentAnswer[2] <= 1)
)

/* --------------------- */

/* 'StudentAnswerValue' gibt an, ob der Funktionswert von 'SelectedFunction' an 'ans1' dem Funktionswert von 'ListOfFunctions[Order+1]' an '[(StudentAnswer[1], StudentAnswer[2],PointOfDev[1],PointOfDev[2])]' entspricht. */
 
StudentAnswerValue : false;
if length(StudentAnswer) = 2 and StudentAnswerCond then (
Dist : abs( ListSubst(StudentAnswer, [x,y], SelectedFunction) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], ListOfFunctions[Order+1])),
StudentAnswerValue : is( Dist < 0.02 )
)

/* --------------------- */]]></text>
      </feedbackvariables>
      <node>
        <name>0</name>
        <answertest>AlgEquiv</answertest>
        <sans>length(StudentAnswer)</sans>
        <tans>2</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>1</truenextnode>
        <trueanswernote>prt1-1-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-1-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\) ist insbesondere ein Element von \(\mathbb{D}_{@FuncName@} \subset \mathbb{R}^2\). Der von Ihnen eingegebene Punkt kann nicht oder nicht eindeutig einem Punkt in \(\mathbb{R}^2\) zugeordnet werden.
</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>1</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerCond</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>2</truenextnode>
        <trueanswernote>prt1-2-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-2-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt liegt nicht (oder nicht eindeutig) in \([-1,1]^2 \subset \mathbb{R}^2\).</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>2</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerValue</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>1</truescore>
        <truepenalty></truepenalty>
        <truenextnode>-1</truenextnode>
        <trueanswernote>prt1-3-T</trueanswernote>
        <truefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\).</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist richtig.</strong></p>]]></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-3-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist kein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\).</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
    </prt>
    <qtest>
      <testcase>1</testcase>
      <testinput>
        <name>ans1</name>
        <value>TeacherAnswerA</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>1.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-3-T</expectedanswernote>
      </expected>
    </qtest>
    <qtest>
      <testcase>2</testcase>
      <testinput>
        <name>ans1</name>
        <value>[2,2]</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>0.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-2-F</expectedanswernote>
      </expected>
    </qtest>
    <qtest>
      <testcase>3</testcase>
      <testinput>
        <name>ans1</name>
        <value>WrongAnswer</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>0.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-3-F</expectedanswernote>
      </expected>
    </qtest>
    <tags>
      <tag><text>Approximation</text>
</tag>
      <tag><text>Taylorpolynom</text>
</tag>
      <tag><text>Entwicklungspunkt</text>
</tag>
    </tags>
  </question>

<!-- question: 966525  -->
  <question type="stack">
    <name>
      <text>Entwicklungspunkt (2)</text>
    </name>
    <questiontext format="html">
      <text><![CDATA[<p style="text-align: justify;"> Betrachten Sie die Funktion</p>
<p style="text-align: justify; margin-left:30px">\(\displaystyle {@FuncName@} : \mathbb{R}^2 \to \mathbb{R}\), \((x,y) \mapsto {@SelectedFunction@}\)</p>
<p style="text-align: justify;">
und ein Taylorpolynom \(T_{{@Order@}}{@FuncName@}\) {@NumberWords1[Order+1]@} Grades von \({@FuncName@}\).</p>
<hr>
<p style="text-align: justify;">Die folgende Abbildung zeigt den Graphen von \({@FuncName@}\) (Graph <font color="#648FFF">&#x25A1</font>) und den Graphen von  \(T_{{@Order@}}{@FuncName@}\) (Graph <font color="#FE6100">&#x25A1</font>) auf dem Einheitsquadrat \([-1,1]^2\) in der \(x_1 x_2\)-Ebene von \(\mathbb{R}^3\) aufgezeichnet gegen die \(x_3\)-Achse. Sie können das Funktionsargument in der \(x_1 x_2\)-Ebene verschieben (Punkt <font color="#DC267F">&#x25CF</font>). Die zugehörigen Funktionswerte unter \({@FuncName@}\) und \(T_{@FuncName@}\) werden Ihnen durch Angabe der zugehörigen Punkte auf den Graphen angezeigt (Punkt <font color="#648FFF">&#x25CF</font> bzw. Punkt <font color="#FE6100">&#x25CF</font>).</p>
<p style="text-align: justify;">
[[jsxgraph input-ref-ans1="stateRef"]]
[[jsxgraph input-ref-ans1="stateRef"]]
const board = JXG.JSXGraph.initBoard(divid, {
  boundingbox: [-1.9, 1.9, 1.9, -1.9],
  axis: false,
  showCopyright: false,
  keepaspectratio: true,
/*  showNavigation: false, */
  fixed: true
});

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- STACK to JSXGraph interface ---- */

var state = {#Argument#};
state[2] = {#SliderPos#}[0]; /* position of slider 'SliderAngleOfProj1' */
state[3] = {#SliderPos#}[1];; /* position of slider 'SliderAngleOfProj2' */
var stateInput = document.getElementById(stateRef);
  if (stateInput.value && stateInput.value != '') {
    state = JSON.parse(stateInput.value);
  }

/* definition of (approximated) function */
var ExFunc = board.jc.snippet('{#SelectedFunction#}', true, 'x,y', true);

/* definition of approximating function */
var StrApproxFunc = '{#ListOfFunctions#}'.substring(1, '{#ListOfFunctions#}'.length - 1);
var SplitStrApproxFunc = StrApproxFunc.split(",");
var MaxOrder = SplitStrApproxFunc.length - 1;

/* order / degree of the polynomial approximation */
var Order = {#Order#}; 

/* initial coordinates of the point of development */
var PointOfDevInit = [{#PointOfDev#}[0], {#PointOfDev#}[1]]; 

/* resolution of the grid */
var ResOfGrid = {#ResOfGrid#};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- colors ---- */

  const Color1 = `hsl(${223}, ${100}%, ${70}%)`; /* #648FFF */
  const Color2 = `hsl(${251}, ${83}%, ${65}%)`; /* #785EF0 */
  const Color3 = `hsl(${331}, ${72}%, ${51}%)`; /* #DC267F */
  const Color4 = `hsl(${23}, ${100}%, ${50}%)`; /* #FE6100 */
  const Color5 = `hsl(${41}, ${100}%, ${50}%)`; /* #FFB000 */

/* ------------------------------------- */
/* --------------------------------------*/

/* draws slider controlling the order of the approximating function */
var SliderOrder = board.create('slider', [
  [-1.3, -1.75],
  [1.2, -1.75],
  [0, Order, MaxOrder]
], {
  withLabel: true,
  highlight: false,
  name: 'order',
  snapWidth: 1,
  visible: false,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});

/* order of the approximating function */
var Order = function(n) {
  return n <= SliderOrder.Value()
};

/* definition of approximating function */
var ApproxFuncList = [];
for (var i = 0; i <= MaxOrder; i++) {
  ApproxFuncList.push(board.jc.snippet(SplitStrApproxFunc[i], true, 'x,y,a,b', true))
}
var ApproxFunc = function(x, y, a, b) {
  return ApproxFuncList[SliderOrder.Value()](x, y, a, b)
};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- general operations on vectors and matrices ---- */

/* vector product */
var NormalVec = function(a, b) {
  return [
    ((a[1] * b[2]) - (a[2] * b[1])),
    ((a[2] * b[0]) - (a[0] * b[2])),
    ((a[0] * b[1]) - (a[1] * b[0]))
  ]
};
/* euclidean scalar product */
var ScalarProd = function(a, b) {
  return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2])
};
/* euclidean norm of vector */
var EuclidNorm = function(a) {
  return Math.sqrt(ScalarProd(a, a))
};
/* multiplication of scalar vectors */
var ScalarMultVec = function(x, a) {
  return [x * a[0], x * a[1], x * a[2]]
};
/* entrywise multiplication of vectors */
var VecMultVec = function(a, b) {
  return [a[0] * b[0], a[1] * b[1], a[2] * b[2]]
};
/* sum of vectors */
var VecSumVec = function(a, b) {
  return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]
};
/* difference of vectors */
var VecSubVec = function(a, b) {
  return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
};
/* euclidean distance of vectors */
var EuclidDist = function(a, b) {
  return EuclidNorm(VecSubVec(a, b))
}

/* multiplication of scalar matrix*/
var ScalarMultMat = function(x, A) {
  return [ScalarMultVec(x, A[0]), ScalarMultVec(x, A[1]), ScalarMultVec(x, A[2])]
}
/* normalizes non-zero vector */
var UnitVec = function(a) {
  let x = Math.sqrt(ScalarProd(a, a));
  let b = ScalarMultVec(x, a);
  return b;
}

/* determinant of matrix*/
var DetOfMat = function(A) {
  return ScalarProd(A[0], NormalVec(A[1], A[2]))
};

/* transpose of matrix */
var TranspOfMat = function(A) {
  let B1 = [A[0][0], A[1][0], A[2][0]];
  let B2 = [A[0][1], A[1][1], A[2][1]];
  let B3 = [A[0][2], A[1][2], A[2][2]];
  return [B1, B2, B3];
}
/* pre-inverse of matrix */
var PreInvOfMat = function(A) {
  let B = TranspOfMat(A);
  let b1 = NormalVec(B[1], B[2]);
  let b2 = NormalVec(B[2], B[0]);
  let b3 = NormalVec(B[0], B[1]);
  let C = [b1, b2, b3];
  return C;
};

/* inverse of matrix */
var InvOfMat = function(A) {
  let B = PreInvOfMat(A);
  let b = 1 / DetOfMat(A);
  return ScalarMultMat(b, B);
};
/* matrix applied as linear map to vector */
var MatMultVec = function(a, A) {
  let b1 = ScalarProd(A[0], a);
  let b2 = ScalarProd(A[1], a);
  let b3 = ScalarProd(A[2], a);
  return [b1, b2, b3];
}

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- sliders for controlling the camera ---- */ 

var SliderAngleOfProj1 = board.create('slider', [
  [-1.75, -1.3],
  [-1.75, 1.3],
  [0.005, state[2], 0.5]
], {
  withLabel: true,
  highlight: false,
  name: 'el',
  postLabel: ' &pi;',
  snapWidth : 0.01,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});
var SliderAngleOfProj2 = board.create('slider', [
  [-1.3, -1.6],
  [1.2, -1.6],
  [-1, state[3], 1]
], {
  withLabel: true,
  highlight: false,
  name: 'az',
  postLabel: ' &pi;',
  snapWidth : 0.01,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});


var AOP1 = function() {
  return SliderAngleOfProj1.Value() * Math.PI
};
var AOP2 = function() {
  return (SliderAngleOfProj2.Value() + 1) * Math.PI
};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- 3D to 2D projection ---- */

/* angles for 2D projection */
var cpsi = function() {
  return Math.cos(AOP2())
};
var spsi = function() {
  return Math.sin(AOP2())
};
var cphi = function() {
  return Math.cos(AOP1())
};
var sphi = function() {
  return Math.sin(AOP1())
};
/* matrix for 2D projection */
var ProjMat2D = function() {
  return [
    [(-1) * cpsi(), spsi(), 0],
    [(-1) * spsi() * sphi(), (-1) * cpsi() * sphi(), cphi()],
    [0, 0, 1]
  ]
};
/* returns 2D coordinates of 3D objects */
var CamProjection = function(a) {
  let Output = MatMultVec(a, ProjMat2D());
  return [Output[0], Output[1]];
}

var CamInv = function(a) {
  let Output = MatMultVec([a[0], a[1], a[2]], InvOfMat(ProjMat2D()));
  return [Output[0], Output[1], Output[2]];
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- coordinate system ---- */

/* 3D coordinates of arrows in dicating the coordinate system */
var AxisCoords = function(h) {
  /* initial coordinates */
  let ICs0 = [0, 0, h];
  let ICs1 = [1.2, 0, h];
  let ICs2 = [0, 1.2, h];
  let ICs3 = [0, 0, 1.2 + h];
  /* ---- */
  let ICs4 = [-1.1, 0, h];
  let ICs5 = [0, -1.1, h];
  return [
    CamProjection(ICs0),
    CamProjection(ICs1),
    CamProjection(ICs2),
    CamProjection(ICs3),
    CamProjection(ICs4),
    CamProjection(ICs5),
  ]
};

/* 3D coordinates of labels of coordinate system*/
var AxisLabelPos = function(h) {
  /* initial coordinates */
  let ICs1 = [1.3, 0, h];
  let ICs2 = [0, 1.3, h];
  let ICs3 = [0, 0, 1.3 + h];
  return [
    CamProjection(ICs1),
    CamProjection(ICs2),
    CamProjection(ICs3)
  ]
};
/* labels of coordinate system*/
var AxisLabel = ['x_1', 'x_2', 'x_3'];

/* draws arrows indicating the coordinates system */
for (let i = 0; i <= 2; i++) {
  board.create('arrow', [
    [() => AxisCoords(0)[0][0], () => AxisCoords(0)[0][1]],
    [() => AxisCoords(0)[i + 1][0], () => AxisCoords(0)[i + 1][1]]
  ], {
    strokecolor: 'black',
    strokeWidth: 1.2,
    layer: 1,
    highlight: false,
    fixed: true,
  });
  /* draws labels of coordinates system */
  board.create('text', [() => AxisLabelPos(0)[i][0], () => AxisLabelPos(0)[i][1], AxisLabel[i]]);
}

/* draws arrows indicating the coordinates system in the domain */
for (let i = 0; i <= 1; i++) {
  board.create('arrow', [
    [() => AxisCoords(-1)[i + 4][0], () => AxisCoords(-1)[i + 4][1]],
    [() => AxisCoords(-1)[i + 1][0], () => AxisCoords(-1)[i + 1][1]]
  ], {
    strokecolor: 'grey',
    strokeWidth: 1.2,
    layer: 1,
    highlight: false,
    fixed: true,
  });
  /* draws labels of coordinates system */
  board.create('text', [() => AxisLabelPos(-1)[i][0], () => AxisLabelPos(-1)[i][1], AxisLabel[i]], {
    strokeColor: 'grey',
  });
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- collection of functions that draw grids and graphs ---- */

/* function that returns 2D coordinates of given 'grid' */
var GridCoordsConv = function(G) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = [CamProjection(G[0][i][0]), CamProjection(G[0][i][1])];
    ICsY[i] = [CamProjection(G[1][i][0]), CamProjection(G[1][i][1])];
  }
  return ([ICsX, ICsY])
}

/* function that draws given 2D grid */
var DrawGrid = function(G) {
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    board.create('segment', [() => G()[0][i][0], () => G()[0][i][1]], {
      strokecolor: 'lightgrey',
      strokeWidth: 1,
      layer: 0,
      highlight: false,
      fixed: true,
    });
    board.create('segment', [() => G()[1][i][0], () => G()[1][i][1]], {
      strokecolor: 'lightgrey',
      strokeWidth: 1,
      layer: 0,
      highlight: false,
      fixed: true,
    });
  }
}

/* function that draws a line segment between points in 3D */
var DrawSegment = function(p, q, C, D) {
  board.create('segment', [() => CamProjection(p()), () => CamProjection(q())], {
    strokecolor: C,
    strokeWidth: 1,
    layer: 0,
    highlight: false,
    fixed: true,
    dash: D,
  });
}

/* function that return parametrization of line segment between points in 3D */
var LineParam = function(p, q) {
  return function(t) {
    return VecSumVec(ScalarMultVec(t, p), ScalarMultVec((1 - t), q))
  }
}

/* function that returns 3D coordinate lines as functions on [0,1] */
var GridParam = function(G) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = LineParam(G()[0][i][0], G()[0][i][1]);
    ICsY[i] = LineParam(G()[1][i][0], G()[1][i][1]);
  }
  return ([ICsX, ICsY])
}

/* function that returns image of 3D coordinate lines as 2D functions on [0,1] */
var ImGridParam = function(P, F) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = function(t) {
      return CamProjection([P[0][i](t)[0], P[0][i](t)[1], F(P[0][i](t)[0], P[0][i](t)[1])])
    };
    ICsY[i] = function(t) {
      return CamProjection([P[1][i](t)[0], P[1][i](t)[1], F(P[1][i](t)[0], P[1][i](t)[1])])
    };
  }
  return ([ICsX, ICsY])
}

/* function that draws image of given 3D grid under given function */
var DrawGraph = function(P, F, C) {
  let ICs = ImGridParam(P, F);
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    board.create('curve', [function(t) {
        return ICs[0][i](t)[0]
      },
      function(t) {
        return ICs[0][i](t)[1]
      },
      0, 1
    ], {
      strokecolor: C,
      strokeWidth: 1,
      layer: 2,
      highlight: false,
      fixed: true,
      doAdvancedPlot: false,
      numberPointsHigh: FidHigh,
      numberPointsLow: FidLow,
    });
    board.create('curve', [function(t) {
        return ICs[1][i](t)[0]
      },
      function(t) {
        return ICs[1][i](t)[1]
      },
      0, 1
    ], {
      strokecolor: C,
      strokeWidth: 1,
      layer: 2,
      highlight: false,
      fixed: true,
      doAdvancedPlot: false,
      numberPointsHigh: FidHigh,
      numberPointsLow: FidLow,
    });
  }
}

/* function that draws the point on the graph a given function for a given 3D point in the domain */
var DrawPoint = function(P, F, C) {
  let ICs3D = function() {
    return [P()[0], P()[1], F(P()[0], P()[1])]
  };
  let ICs2D = function() {
    return CamProjection(ICs3D())
  };
  let IC = board.create('point', [() => ICs2D()[0], () => ICs2D()[1]], {
    color: Color4
  });
  IC.setAttribute({
    showInfobox: false,
    layer: 3,
    color: C,
    highlight: false,
    name: function() {
      return '(' + JXG.toFixed(
          ICs3D()[0], 2) + ', ' +
        JXG.toFixed(
          ICs3D()[1], 2) + ', ' +
        JXG.toFixed(
          ICs3D()[2], 2) + ')'
    }
  });
  DrawSegment(P, ICs3D, 'grey', 2);
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- definition of grid in domain ---- */

var FidHigh = 600 / ResOfGrid;
var FidLow = 200 / ResOfGrid;
var SizeOfGrid = 1;
var StepOfGrid = SizeOfGrid / ResOfGrid;

/* 3D coordinates of grid in domain */
var GridDomain3D = function() {
  /* initial coordinates */
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = [
      [-SizeOfGrid + i * StepOfGrid, -SizeOfGrid, -1],
      [-SizeOfGrid + i * StepOfGrid, SizeOfGrid, -1]
    ];
    ICsY[i] = [
      [-SizeOfGrid, -SizeOfGrid + i * StepOfGrid, -1],
      [SizeOfGrid, -SizeOfGrid + i * StepOfGrid, -1]
    ];
  }
  return ([ICsX, ICsY])
}

/* 2D coordinates of grid in domain */
var GridDomain = function() {
  return GridCoordsConv(GridDomain3D())
};

DrawGrid(GridDomain);

var GridDomainParam = GridParam(GridDomain3D);

/* ------------------------------------- */
/* ------------------------------------- */

/* draws point in domain at which the taylor polynomial is developed */
var PointOfDev = board.create('point', CamProjection([PointOfDevInit[0], PointOfDevInit[1], -1]),{visible: false});
var PointOfDev3D = function() {
/*  return CamInv([PointOfDev.X(), PointOfDev.Y(), -1]) */
  return [PointOfDevInit[0], PointOfDevInit[1], -1]
};

PointOfDev.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return '(' + JXG.toFixed(
        PointOfDev3D()[0], 2) + ', ' +
      JXG.toFixed(
        PointOfDev3D()[1], 2) + ')'
  }
});

/* draws dashed lines to indicate position of PointOfDev and PointOnGraph*/
/* DrawSegment(PointOfDev3D, () => [PointOfDev3D()[0], 0, PointOfDev3D()[2]], 'grey', 2); */
/* DrawSegment(PointOfDev3D, () => [0, PointOfDev3D()[1], PointOfDev3D()[2]], 'grey', 2); */

/* ------------------------------------- */
/* ------------------------------------- */

/* draws arbitrary point in domain to visualize difference between (approximated) function and approximating function */
var ArbPointInDom = board.create('point', CamProjection([state[0], state[1], -1]));
var ArbPointInDom3D = function() {
  return CamInv([ArbPointInDom.X(), ArbPointInDom.Y(), -1])
};

ArbPointInDom.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return '(' + JXG.toFixed(
        ArbPointInDom3D()[0], 2) + ', ' +
      JXG.toFixed(
        ArbPointInDom3D()[1], 2) + ')'
  }
});

/* draws dashed lines to indicate position of PointOfDev and PointOnGraph*/
DrawSegment(ArbPointInDom3D, () => [ArbPointInDom3D()[0], 0, ArbPointInDom3D()[2]], 'grey', 2);
DrawSegment(ArbPointInDom3D, () => [0, ArbPointInDom3D()[1], ArbPointInDom3D()[2]], 'grey', 2);

/* ------------------------------------- */
/* ------------------------------------- */

var PointDefRad = board.create('point', CamProjection([0.3, 0.3, -1]), {
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: false,
  visible : false,
});
var PointDefRad3D = function() {
  return CamInv([PointDefRad.X(), PointDefRad.Y(), -1])
};

var RadiusOfCircle = function() {
  return EuclidDist(ArbPointInDom3D(), PointDefRad3D())
}

PointDefRad.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return JXG.toFixed(RadiusOfCircle(), 2)
  }
});

/* function that draws image of circle at given 3D point with given radius under given function */
var DrawCircleAtPoint = function(P, r, F, C) {
  let ICsX = function(t) {
    return P()[0] + r() * Math.cos(t)
  };
  let ICsY = function(t) {
    return P()[1] + r() * Math.sin(t)
  };
  let ICsZ = function(t) {
    return F(ICsX(t), ICsY(t))
  };
  let UCs = function(t) {
    return CamProjection([ICsX(t), ICsY(t), ICsZ(t)])
  };
  board.create('curve', [function(t) {
      return UCs(t)[0]
    },
    function(t) {
      return UCs(t)[1]
    },
    0, 6.5
  ], {
    strokecolor: C,
    strokeWidth: 1,
    layer: 2,
    highlight: false,
    fixed: true,
    doAdvancedPlot: false,
    numberPointsHigh: FidHigh * 2,
    numberPointsLow: FidLow * 2,
  });
}

/* draw circles at point in domain and their images */

/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, () => -1, Color3); */
/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, ExFunc, Color4); */
/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4); */

/* ------------------------------------- */
/* ------------------------------------- */

/* draws images of points in domain */

/* DrawPoint(PointOfDev3D, ExFunc, 'Grey'); */
DrawPoint(ArbPointInDom3D, ExFunc, Color1);
DrawPoint(ArbPointInDom3D, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4);

/* ------------------------------------- */
/* ------------------------------------- */

/* draw graph of (approximated) function */
DrawGraph(GridDomainParam, ExFunc, Color1)

/* draw graph of approximating function */
DrawGraph(GridDomainParam, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4)

/* ------------------------------------- */
/* ------------------------------------- */

board.on('move', function() {
  board.suspendUpdate();

  /* returns point in domain close to given point */
  const ReturnToDomain =
    function(a) {
      let Output = [];
      if (a[0] < -1) {
        Output[0] = -1;
      } else if (a[0] > 1) {
        Output[0] = 1;
      } else {
        Output[0] = a[0];
      }
      if (a[1] < -1) {
        Output[1] = -1;
      } else if (a[1] > 1) {
        Output[1] = 1;
      } else {
        Output[1] = a[1];
      }
      Output[2] = a[2];
      return Output
    };
  PointOfDev.moveTo(CamProjection(ReturnToDomain(PointOfDev3D())));
  ArbPointInDom.moveTo(CamProjection(ReturnToDomain(ArbPointInDom3D())));
  PointDefRad.moveTo(CamProjection(ReturnToDomain(PointDefRad3D())));
  board.unsuspendUpdate();
});

/* ------------------------------------- */
/* ------------------------------------- */

var newState =  [Math.round(ArbPointInDom3D()[0]*100)/100, Math.round(ArbPointInDom3D()[1]*100)/100, SliderAngleOfProj1.Value(),SliderAngleOfProj2.Value()];
var ClickIndicator = 0;

var SendData = function(){
     newState = [Math.round(ArbPointInDom3D()[0]*100)/100, Math.round(ArbPointInDom3D()[1]*100)/100,SliderAngleOfProj1.Value(),SliderAngleOfProj2.Value()];
     stateInput.value = JSON.stringify(newState);
     stateInput.dispatchEvent(new Event('change'));
}

ArbPointInDom.on('drag', function () {
   SendData();
});

stateInput.style.display = 'none';

/* ------------------------------------- */
/* ------------------------------------- */

/* ensures that all draggable points (e.g. PointOfDev, ArbPointInDom) are rotatated accordingly when angles of projections are changed by sliders */

/* Buffer */
var PointOfDevBuffer = PointOfDev3D();
var ArbPointInDomBuffer = ArbPointInDom3D();
var PointDefRadBuffer = PointDefRad3D();

/* function that updates position of objects */

var UpdatePos = function(){
    let ICs1 = CamProjection(PointOfDevBuffer);
    let ICs2 = CamProjection(ArbPointInDomBuffer);
    let ICs3 = CamProjection(PointDefRadBuffer);
    board.suspendUpdate();
    PointOfDev.moveTo([
      ICs1[0],
      ICs1[1]
    ]);
    ArbPointInDom.moveTo([
      ICs2[0],
      ICs2[1]
    ]);
    PointDefRad.moveTo([
      ICs3[0],
      ICs3[1]
    ]);
    board.unsuspendUpdate();
   SendData();
}

SliderAngleOfProj1.on('down', function() {
  PointOfDevBuffer = PointOfDev3D();
  ArbPointInDomBuffer = ArbPointInDom3D();
  PointDefRadBuffer = PointDefRad3D();
  SliderAngleOfProj1.on('drag', function() {
  UpdatePos()
  });
});

SliderAngleOfProj2.on('down', function() {
  PointOfDevBuffer = PointOfDev3D();
  ArbPointInDomBuffer = ArbPointInDom3D();
  PointDefRadBuffer = PointDefRad3D();
  SliderAngleOfProj2.on('drag', function() {
  UpdatePos()
  });
});

ArbPointInDom.on('down', function() {
  PointDefRadBuffer = VecSubVec(ArbPointInDom3D(), PointDefRad3D());
  ArbPointInDom.on('drag', function() {
    let ICs = CamProjection(VecSubVec(ArbPointInDom3D(), PointDefRadBuffer));
    board.suspendUpdate();
    PointDefRad.moveTo([
      ICs[0],
      ICs[1]
    ]);
    board.unsuspendUpdate();
  });
});

/* ------------------------------------- */
/* ------------------------------------- */

[[/jsxgraph]]</p>
<hr>
<p style="text-align: justify;">Geben Sie mithilfe der obigen Abbildung einen Entwicklungspunkt \((a,b) \in [-1,1]^2\) des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\) an. Verschieben Sie dazu das Funktionsargument in der \(x_1 x_2\)-Ebene (Punkt <font color="#DC267F">&#x25CF</font>) an die Position eines Entwicklungspunktes. [[input:ans1]]</p>
<p style="text-align: justify;">[[validation:ans1]]</p>
<p style="text-align: justify;">[[feedback:prt1]]</p>
<hr>]]></text>
    </questiontext>
    <generalfeedback format="html">
      <text><![CDATA[<p style="text-align: justify;">Ein Taylorpolynom {@NumberWords1[Order+1]@} Grades von \({@FuncName@}\) am Entwicklungspunkt \((a,b)\) ist von der Form</p>
<p style="text-align: justify;margin-left:30px">\(\displaystyle
{@FuncName@}(a,b) + \frac{\partial {@FuncName@}}{\partial x}(a,b)\,x + \frac{\partial {@FuncName@}}{\partial y}(a,b)\,y  
\).</p>
Folglich ist \((a,b)\) genau dann ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\), wenn</p>
<p style="text-align: justify;margin-left:30px">\(\displaystyle
\begin{align}
T_{{@Order@}}{@FuncName@}(a,b) &= {@FuncName@}(a,b),\\
\frac{\partial T_{{@Order@}}{@FuncName@}}{\partial x}(a,b) &= \frac{\partial {@FuncName@}}{\partial x}(a,b),\\
\frac{\partial T_{{@Order@}}{@FuncName@}}{\partial y}(a,b) &= \frac{\partial {@FuncName@}}{\partial y}(a,b)
\end{align}
\)</p>
<p style="text-align: justify;">ist. Dies ist an dem Punkt \(({@PointOfDev[1]@}, {@PointOfDev[2]@})\) erfüllt.</p>]]></text>
    </generalfeedback>
    <defaultgrade>1.0000000</defaultgrade>
    <penalty>0.0000000</penalty>
    <hidden>0</hidden>
    <idnumber></idnumber>
    <stackversion>
      <text>2023010400</text>
    </stackversion>
    <questionvariables>
      <text><![CDATA[/* --------------------------- */
/* --------------------------- */

/* Darstellung */

NumberWords1 : ["nullten", "ersten", "zweiten", "dritten", "vierten", "fünften", "sechsten", "siebten", "achten", "neunten", "zehnten", "elften", "zwölften"];
NumberWords2 : ["nullter", "erster", "zweiter", "dritter", "vierter", "fünfter", "sechster", "siebter", "achter", "neunter", "zehnter", "elfter", "zwölfter"];

ResOfGrid : 5; /* Gitterabstand (-> Abbildung) */
SliderPos : [0.1,-0.65]; /* Position der Kameraslider bei Initialisierung (-> Abbildung) */

/* --------------------------- */
/* --------------------------- */

/* Definition / Randomisierung */

/* Auswahl der (zu approximierenden) Funktion */

ExpList : random_permutation([0,1,2]);
b1 : ExpList[1];
b2 : 2-b1;
c1 : ExpList[2];
c2 : 2-c1;

a1 : rand([-1,1]);
a2 : rand([-a1,1]);

Polynomial: a1*x^b1*y^b2 + a2*x^c1*y^c2;

t1 : rand([1,2]);
TFunc1: [cos(t),sin(t)];
SelectedFunction: subst(Polynomial, t , TFunc1[t1])

/* --------------------------- */

/* Koordinaten des Entwicklungspunkts 'PointOfDev': Die Koordinaten des Entwicklungspunktes sind so gewählt, dass '[0,0]' kein Entwicklungspunkt des zugehörigen Taylorpolynoms ist (relevant für Ordnung null)*/

ListOfCoord : random_permutation([4,6,8]);
PointOfDevX : float(a1*ListOfCoord[1]/10);
PointOfDevY : float(a2*ListOfCoord[2]/10);

PointOfDev : [PointOfDevX,PointOfDevY]; /* Entwicklungspunkt */

/* --------------------------- */
/* --------------------------- */

/* Definitionen */

FuncName : f; /* Bezeichner der Funktion */
Argument : [0,0]; /* Funktionsargument (-> Abbildung); sollte ungleich 'PointOfDev' gewählt werden */
Order : 1; /* Ordnung der Taylor-Entwicklung (-> Abbildung; kleiner oder gleich 'MaxOrder') */
MaxOrder : 1; /* maximale Ordnung der Taylor-Entwicklung (-> Abbildung; mindestens 1) */

/* --------------------------- */

/* Liste aller Taylor-Polynome bis zur maximalen Ordnung */
ListOfFunctions:[]
IndexOrder: 0;
while length(ListOfFunctions) <= max(MaxOrder,Order) do (
  ListOfFunctions : append(ListOfFunctions,[expand(taylor(SelectedFunction, [x,y], [a,b], IndexOrder))]),
  IndexOrder : IndexOrder + 1
);

/* --------------------------- */

/* Antworten */
TeacherAnswerA : append(PointOfDev, SliderPos);
WrongAnswer : [0,0];

/* --------------------------- */
/* --------------------------- */

/* Hilsfunktionen */

ListSubst(SList,List,Expr) := 
  block([Length, Index, OutPut],
    Length : min(length(SList),length(List)),
    Index : 1,
    Output : Expr,
    while Index <= Length do (
      Output : subst(SList[Index], List[Index], Output),
      Index : Index + 1
    ),
    Output
  );

/* --------------------------- */
/* --------------------------- */

/* Benjamin Herbert Schulz-Rosenberger */]]></text>
    </questionvariables>
    <specificfeedback format="html">
      <text></text>
    </specificfeedback>
    <questionnote>
      <text>\[\textstyle f(x,y)={@ SelectedFunction@}\]</text>
    </questionnote>
    <questionsimplify>1</questionsimplify>
    <assumepositive>0</assumepositive>
    <assumereal>0</assumereal>
    <prtcorrect format="html">
      <text></text>
    </prtcorrect>
    <prtpartiallycorrect format="html">
      <text></text>
    </prtpartiallycorrect>
    <prtincorrect format="html">
      <text></text>
    </prtincorrect>
    <multiplicationsign>none</multiplicationsign>
    <sqrtsign>1</sqrtsign>
    <complexno>i</complexno>
    <inversetrig>cos-1</inversetrig>
    <logicsymbol>lang</logicsymbol>
    <matrixparens>(</matrixparens>
    <variantsselectionseed></variantsselectionseed>
    <input>
      <name>ans1</name>
      <type>algebraic</type>
      <tans>TeacherAnswerA</tans>
      <boxsize>15</boxsize>
      <strictsyntax>1</strictsyntax>
      <insertstars>0</insertstars>
      <syntaxhint></syntaxhint>
      <syntaxattribute>0</syntaxattribute>
      <forbidwords></forbidwords>
      <allowwords></allowwords>
      <forbidfloat>0</forbidfloat>
      <requirelowestterms>0</requirelowestterms>
      <checkanswertype>0</checkanswertype>
      <mustverify>0</mustverify>
      <showvalidation>0</showvalidation>
      <options></options>
    </input>
    <prt>
      <name>prt1</name>
      <value>1.0000000</value>
      <autosimplify>1</autosimplify>
      <feedbackstyle>1</feedbackstyle>
      <feedbackvariables>
        <text><![CDATA[/* --------------------- */

StudentAnswer : [ans1[1],ans1[2]];

/* --------------------- */

/* 'StudentAnswerValue' gibt an, ob 'ans1' in dem Einheitsquadrat [-1,1]^2 enthalten ist. */

StudentAnswerCond : false;
if length(StudentAnswer) = 2 then (
StudentAnswerCond : is(StudentAnswer[1] >= -1) and is(StudentAnswer[1] <= 1) and is(StudentAnswer[2] >= -1) and is(StudentAnswer[2] <= 1)
)

/* --------------------- */

/* 'StudentAnswerValue1' gibt an, ob der Funktionswert von 'SelectedFunction' an 'ans1' dem Funktionswert von 'ListOfFunctions[Order+1]' an '[(StudentAnswer[1], StudentAnswer[2],PointOfDev[1],PointOfDev[2])]' entspricht. */
 
StudentAnswerValue1 : false;
if length(StudentAnswer) = 2 and StudentAnswerCond then (
Dist : abs( ListSubst(StudentAnswer, [x,y], SelectedFunction) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], ListOfFunctions[Order+1])),
StudentAnswerValue1 : is( Dist < 0.02 )
)

/* --------------------- */

/* 'StudentAnswerValue2' gibt an, ob der die ersten partiellen Ableitungen von 'SelectedFunction' an 'ans1' den ersten partiellen Ableitungen von 'ListOfFunctions[Order+1]' an '[(StudentAnswer[1], StudentAnswer[2],PointOfDev[1],PointOfDev[2])]' entsprechen. */
 
StudentAnswerValue2 : false;
if length(StudentAnswer) = 2 and StudentAnswerCond and StudentAnswerValue1 then (
DistPartX : abs( ListSubst(StudentAnswer, [x,y], diff(SelectedFunction,x,1)) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], diff(ListOfFunctions[Order+1],x,1))),
DistPartY : abs( ListSubst(StudentAnswer, [x,y], diff(SelectedFunction,y,1)) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], diff(ListOfFunctions[Order+1],y,1))),
StudentAnswerValue2 : is( max(DistPartX, DistPartY) < 0.02 )
)

/* --------------------- */]]></text>
      </feedbackvariables>
      <node>
        <name>0</name>
        <answertest>AlgEquiv</answertest>
        <sans>length(StudentAnswer)</sans>
        <tans>2</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>1</truenextnode>
        <trueanswernote>prt1-1-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-1-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\) ist insbesondere ein Element von \(\mathbb{D}_{@FuncName@} \subset \mathbb{R}^2\). Der von Ihnen eingegebene Punkt kann nicht oder nicht eindeutig einem Punkt in \(\mathbb{R}^2\) zugeordnet werden.
</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>1</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerCond</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>2</truenextnode>
        <trueanswernote>prt1-2-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-2-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt liegt nicht (oder nicht eindeutig) in \([-1,1]^2 \subset \mathbb{R}^2\).</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>2</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerValue1</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>3</truenextnode>
        <trueanswernote>prt1-3-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-3-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist kein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\). Beachten Sie, dass das Taylorpolynom \(T_{{@Order@}}{@FuncName@}\) insbesondere auch eine Approximation {@NumberWords2[Order]@} Ordnung an {@FuncName@} ist.</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>3</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerValue2</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>1</truescore>
        <truepenalty></truepenalty>
        <truenextnode>-1</truenextnode>
        <trueanswernote>prt1-4-T</trueanswernote>
        <truefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\).</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist richtig.</strong></p>]]></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-4-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist kein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\). Beachten Sie, dass für eine  Approximation {@NumberWords2[Order+1]@} Ordnung an {@FuncName@} durch das Taylorpolynom \(T_{{@Order@}}{@FuncName@}\) an einem Entwicklungspunkt \((a,b)\) neben \(T_{{@Order@}}{@FuncName@}(a,b)={@FuncName@}(a,b)\) weitere Eigenschaften gelten.</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
    </prt>
    <qtest>
      <testcase>1</testcase>
      <testinput>
        <name>ans1</name>
        <value>TeacherAnswerA</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>1.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-4-T</expectedanswernote>
      </expected>
    </qtest>
    <qtest>
      <testcase>2</testcase>
      <testinput>
        <name>ans1</name>
        <value>[2,2]</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>0.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-2-F</expectedanswernote>
      </expected>
    </qtest>
    <qtest>
      <testcase>3</testcase>
      <testinput>
        <name>ans1</name>
        <value>WrongAnswer</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>0.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-3-F</expectedanswernote>
      </expected>
    </qtest>
    <tags>
      <tag><text>Approximation</text>
</tag>
      <tag><text>Taylorpolynom</text>
</tag>
      <tag><text>Entwicklungspunkt</text>
</tag>
    </tags>
  </question>

<!-- question: 966526  -->
  <question type="stack">
    <name>
      <text>Entwicklungspunkt (3)</text>
    </name>
    <questiontext format="html">
      <text><![CDATA[<p style="text-align: justify;"> Betrachten Sie die Funktion</p>
<p style="text-align: justify; margin-left:30px">\(\displaystyle {@FuncName@} : \mathbb{R}^2 \to \mathbb{R}\), \((x,y) \mapsto {@SelectedFunction@}\)</p>
<p style="text-align: justify;">
und ein Taylorpolynom \(T_{{@Order@}}{@FuncName@}\) {@NumberWords1[Order+1]@} Grades von \({@FuncName@}\).</p>
<hr>
<p style="text-align: justify;">Die folgende Abbildung zeigt den Graphen von \({@FuncName@}\) (Graph <font color="#648FFF">&#x25A1</font>) und den Graphen von  \(T_{{@Order@}}{@FuncName@}\) (Graph <font color="#FE6100">&#x25A1</font>) auf dem Einheitsquadrat \([-1,1]^2\) in der \(x_1 x_2\)-Ebene von \(\mathbb{R}^3\) aufgezeichnet gegen die \(x_3\)-Achse. Sie können das Funktionsargument in der \(x_1 x_2\)-Ebene verschieben (Punkt <font color="#DC267F">&#x25CF</font>). Die zugehörigen Funktionswerte unter \({@FuncName@}\) und \(T_{@FuncName@}\) werden Ihnen durch Angabe der zugehörigen Punkte auf den Graphen angezeigt (Punkt <font color="#648FFF">&#x25CF</font> bzw. Punkt <font color="#FE6100">&#x25CF</font>).</p>
<p style="text-align: justify;">
[[jsxgraph input-ref-ans1="stateRef"]]
[[jsxgraph input-ref-ans1="stateRef"]]
const board = JXG.JSXGraph.initBoard(divid, {
  boundingbox: [-1.9, 1.9, 1.9, -1.9],
  axis: false,
  showCopyright: false,
  keepaspectratio: true,
/*  showNavigation: false, */
  fixed: true
});

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- STACK to JSXGraph interface ---- */

var state = {#Argument#};
state[2] = {#SliderPos#}[0]; /* position of slider 'SliderAngleOfProj1' */
state[3] = {#SliderPos#}[1];; /* position of slider 'SliderAngleOfProj2' */
var stateInput = document.getElementById(stateRef);
  if (stateInput.value && stateInput.value != '') {
    state = JSON.parse(stateInput.value);
  }

/* definition of (approximated) function */
var ExFunc = board.jc.snippet('{#SelectedFunction#}', true, 'x,y', true);

/* definition of approximating function */
var StrApproxFunc = '{#ListOfFunctions#}'.substring(1, '{#ListOfFunctions#}'.length - 1);
var SplitStrApproxFunc = StrApproxFunc.split(",");
var MaxOrder = SplitStrApproxFunc.length - 1;

/* order / degree of the polynomial approximation */
var Order = {#Order#}; 

/* initial coordinates of the point of development */
var PointOfDevInit = [{#PointOfDev#}[0], {#PointOfDev#}[1]]; 

/* resolution of the grid */
var ResOfGrid = {#ResOfGrid#};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- colors ---- */

  const Color1 = `hsl(${223}, ${100}%, ${70}%)`; /* #648FFF */
  const Color2 = `hsl(${251}, ${83}%, ${65}%)`; /* #785EF0 */
  const Color3 = `hsl(${331}, ${72}%, ${51}%)`; /* #DC267F */
  const Color4 = `hsl(${23}, ${100}%, ${50}%)`; /* #FE6100 */
  const Color5 = `hsl(${41}, ${100}%, ${50}%)`; /* #FFB000 */

/* ------------------------------------- */
/* --------------------------------------*/

/* draws slider controlling the order of the approximating function */
var SliderOrder = board.create('slider', [
  [-1.3, -1.75],
  [1.2, -1.75],
  [0, Order, MaxOrder]
], {
  withLabel: true,
  highlight: false,
  name: 'order',
  snapWidth: 1,
  visible: false,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});

/* order of the approximating function */
var Order = function(n) {
  return n <= SliderOrder.Value()
};

/* definition of approximating function */
var ApproxFuncList = [];
for (var i = 0; i <= MaxOrder; i++) {
  ApproxFuncList.push(board.jc.snippet(SplitStrApproxFunc[i], true, 'x,y,a,b', true))
}
var ApproxFunc = function(x, y, a, b) {
  return ApproxFuncList[SliderOrder.Value()](x, y, a, b)
};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- general operations on vectors and matrices ---- */

/* vector product */
var NormalVec = function(a, b) {
  return [
    ((a[1] * b[2]) - (a[2] * b[1])),
    ((a[2] * b[0]) - (a[0] * b[2])),
    ((a[0] * b[1]) - (a[1] * b[0]))
  ]
};
/* euclidean scalar product */
var ScalarProd = function(a, b) {
  return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2])
};
/* euclidean norm of vector */
var EuclidNorm = function(a) {
  return Math.sqrt(ScalarProd(a, a))
};
/* multiplication of scalar vectors */
var ScalarMultVec = function(x, a) {
  return [x * a[0], x * a[1], x * a[2]]
};
/* entrywise multiplication of vectors */
var VecMultVec = function(a, b) {
  return [a[0] * b[0], a[1] * b[1], a[2] * b[2]]
};
/* sum of vectors */
var VecSumVec = function(a, b) {
  return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]
};
/* difference of vectors */
var VecSubVec = function(a, b) {
  return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
};
/* euclidean distance of vectors */
var EuclidDist = function(a, b) {
  return EuclidNorm(VecSubVec(a, b))
}

/* multiplication of scalar matrix*/
var ScalarMultMat = function(x, A) {
  return [ScalarMultVec(x, A[0]), ScalarMultVec(x, A[1]), ScalarMultVec(x, A[2])]
}
/* normalizes non-zero vector */
var UnitVec = function(a) {
  let x = Math.sqrt(ScalarProd(a, a));
  let b = ScalarMultVec(x, a);
  return b;
}

/* determinant of matrix*/
var DetOfMat = function(A) {
  return ScalarProd(A[0], NormalVec(A[1], A[2]))
};

/* transpose of matrix */
var TranspOfMat = function(A) {
  let B1 = [A[0][0], A[1][0], A[2][0]];
  let B2 = [A[0][1], A[1][1], A[2][1]];
  let B3 = [A[0][2], A[1][2], A[2][2]];
  return [B1, B2, B3];
}
/* pre-inverse of matrix */
var PreInvOfMat = function(A) {
  let B = TranspOfMat(A);
  let b1 = NormalVec(B[1], B[2]);
  let b2 = NormalVec(B[2], B[0]);
  let b3 = NormalVec(B[0], B[1]);
  let C = [b1, b2, b3];
  return C;
};

/* inverse of matrix */
var InvOfMat = function(A) {
  let B = PreInvOfMat(A);
  let b = 1 / DetOfMat(A);
  return ScalarMultMat(b, B);
};
/* matrix applied as linear map to vector */
var MatMultVec = function(a, A) {
  let b1 = ScalarProd(A[0], a);
  let b2 = ScalarProd(A[1], a);
  let b3 = ScalarProd(A[2], a);
  return [b1, b2, b3];
}

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- sliders for controlling the camera ---- */ 

var SliderAngleOfProj1 = board.create('slider', [
  [-1.75, -1.3],
  [-1.75, 1.3],
  [0.005, state[2], 0.5]
], {
  withLabel: true,
  highlight: false,
  name: 'el',
  postLabel: ' &pi;',
  snapWidth : 0.01,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});
var SliderAngleOfProj2 = board.create('slider', [
  [-1.3, -1.6],
  [1.2, -1.6],
  [-1, state[3], 1]
], {
  withLabel: true,
  highlight: false,
  name: 'az',
  postLabel: ' &pi;',
  snapWidth : 0.01,
  moveOnUp: false,
  point1: {frozen: true},
  point2: {frozen: true},
});


var AOP1 = function() {
  return SliderAngleOfProj1.Value() * Math.PI
};
var AOP2 = function() {
  return (SliderAngleOfProj2.Value() + 1) * Math.PI
};

/* ------------------------------------- */
/* --------------------------------------*/

/* ---- 3D to 2D projection ---- */

/* angles for 2D projection */
var cpsi = function() {
  return Math.cos(AOP2())
};
var spsi = function() {
  return Math.sin(AOP2())
};
var cphi = function() {
  return Math.cos(AOP1())
};
var sphi = function() {
  return Math.sin(AOP1())
};
/* matrix for 2D projection */
var ProjMat2D = function() {
  return [
    [(-1) * cpsi(), spsi(), 0],
    [(-1) * spsi() * sphi(), (-1) * cpsi() * sphi(), cphi()],
    [0, 0, 1]
  ]
};
/* returns 2D coordinates of 3D objects */
var CamProjection = function(a) {
  let Output = MatMultVec(a, ProjMat2D());
  return [Output[0], Output[1]];
}

var CamInv = function(a) {
  let Output = MatMultVec([a[0], a[1], a[2]], InvOfMat(ProjMat2D()));
  return [Output[0], Output[1], Output[2]];
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- coordinate system ---- */

/* 3D coordinates of arrows in dicating the coordinate system */
var AxisCoords = function(h) {
  /* initial coordinates */
  let ICs0 = [0, 0, h];
  let ICs1 = [1.2, 0, h];
  let ICs2 = [0, 1.2, h];
  let ICs3 = [0, 0, 1.2 + h];
  /* ---- */
  let ICs4 = [-1.1, 0, h];
  let ICs5 = [0, -1.1, h];
  return [
    CamProjection(ICs0),
    CamProjection(ICs1),
    CamProjection(ICs2),
    CamProjection(ICs3),
    CamProjection(ICs4),
    CamProjection(ICs5),
  ]
};

/* 3D coordinates of labels of coordinate system*/
var AxisLabelPos = function(h) {
  /* initial coordinates */
  let ICs1 = [1.3, 0, h];
  let ICs2 = [0, 1.3, h];
  let ICs3 = [0, 0, 1.3 + h];
  return [
    CamProjection(ICs1),
    CamProjection(ICs2),
    CamProjection(ICs3)
  ]
};
/* labels of coordinate system*/
var AxisLabel = ['x_1', 'x_2', 'x_3'];

/* draws arrows indicating the coordinates system */
for (let i = 0; i <= 2; i++) {
  board.create('arrow', [
    [() => AxisCoords(0)[0][0], () => AxisCoords(0)[0][1]],
    [() => AxisCoords(0)[i + 1][0], () => AxisCoords(0)[i + 1][1]]
  ], {
    strokecolor: 'black',
    strokeWidth: 1.2,
    layer: 1,
    highlight: false,
    fixed: true,
  });
  /* draws labels of coordinates system */
  board.create('text', [() => AxisLabelPos(0)[i][0], () => AxisLabelPos(0)[i][1], AxisLabel[i]]);
}

/* draws arrows indicating the coordinates system in the domain */
for (let i = 0; i <= 1; i++) {
  board.create('arrow', [
    [() => AxisCoords(-1)[i + 4][0], () => AxisCoords(-1)[i + 4][1]],
    [() => AxisCoords(-1)[i + 1][0], () => AxisCoords(-1)[i + 1][1]]
  ], {
    strokecolor: 'grey',
    strokeWidth: 1.2,
    layer: 1,
    highlight: false,
    fixed: true,
  });
  /* draws labels of coordinates system */
  board.create('text', [() => AxisLabelPos(-1)[i][0], () => AxisLabelPos(-1)[i][1], AxisLabel[i]], {
    strokeColor: 'grey',
  });
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- collection of functions that draw grids and graphs ---- */

/* function that returns 2D coordinates of given 'grid' */
var GridCoordsConv = function(G) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = [CamProjection(G[0][i][0]), CamProjection(G[0][i][1])];
    ICsY[i] = [CamProjection(G[1][i][0]), CamProjection(G[1][i][1])];
  }
  return ([ICsX, ICsY])
}

/* function that draws given 2D grid */
var DrawGrid = function(G) {
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    board.create('segment', [() => G()[0][i][0], () => G()[0][i][1]], {
      strokecolor: 'lightgrey',
      strokeWidth: 1,
      layer: 0,
      highlight: false,
      fixed: true,
    });
    board.create('segment', [() => G()[1][i][0], () => G()[1][i][1]], {
      strokecolor: 'lightgrey',
      strokeWidth: 1,
      layer: 0,
      highlight: false,
      fixed: true,
    });
  }
}

/* function that draws a line segment between points in 3D */
var DrawSegment = function(p, q, C, D) {
  board.create('segment', [() => CamProjection(p()), () => CamProjection(q())], {
    strokecolor: C,
    strokeWidth: 1,
    layer: 0,
    highlight: false,
    fixed: true,
    dash: D,
  });
}

/* function that return parametrization of line segment between points in 3D */
var LineParam = function(p, q) {
  return function(t) {
    return VecSumVec(ScalarMultVec(t, p), ScalarMultVec((1 - t), q))
  }
}

/* function that returns 3D coordinate lines as functions on [0,1] */
var GridParam = function(G) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = LineParam(G()[0][i][0], G()[0][i][1]);
    ICsY[i] = LineParam(G()[1][i][0], G()[1][i][1]);
  }
  return ([ICsX, ICsY])
}

/* function that returns image of 3D coordinate lines as 2D functions on [0,1] */
var ImGridParam = function(P, F) {
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = function(t) {
      return CamProjection([P[0][i](t)[0], P[0][i](t)[1], F(P[0][i](t)[0], P[0][i](t)[1])])
    };
    ICsY[i] = function(t) {
      return CamProjection([P[1][i](t)[0], P[1][i](t)[1], F(P[1][i](t)[0], P[1][i](t)[1])])
    };
  }
  return ([ICsX, ICsY])
}

/* function that draws image of given 3D grid under given function */
var DrawGraph = function(P, F, C) {
  let ICs = ImGridParam(P, F);
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    board.create('curve', [function(t) {
        return ICs[0][i](t)[0]
      },
      function(t) {
        return ICs[0][i](t)[1]
      },
      0, 1
    ], {
      strokecolor: C,
      strokeWidth: 1,
      layer: 2,
      highlight: false,
      fixed: true,
      doAdvancedPlot: false,
      numberPointsHigh: FidHigh,
      numberPointsLow: FidLow,
    });
    board.create('curve', [function(t) {
        return ICs[1][i](t)[0]
      },
      function(t) {
        return ICs[1][i](t)[1]
      },
      0, 1
    ], {
      strokecolor: C,
      strokeWidth: 1,
      layer: 2,
      highlight: false,
      fixed: true,
      doAdvancedPlot: false,
      numberPointsHigh: FidHigh,
      numberPointsLow: FidLow,
    });
  }
}

/* function that draws the point on the graph a given function for a given 3D point in the domain */
var DrawPoint = function(P, F, C) {
  let ICs3D = function() {
    return [P()[0], P()[1], F(P()[0], P()[1])]
  };
  let ICs2D = function() {
    return CamProjection(ICs3D())
  };
  let IC = board.create('point', [() => ICs2D()[0], () => ICs2D()[1]], {
    color: Color4
  });
  IC.setAttribute({
    showInfobox: false,
    layer: 3,
    color: C,
    highlight: false,
    name: function() {
      return '(' + JXG.toFixed(
          ICs3D()[0], 2) + ', ' +
        JXG.toFixed(
          ICs3D()[1], 2) + ', ' +
        JXG.toFixed(
          ICs3D()[2], 2) + ')'
    }
  });
  DrawSegment(P, ICs3D, 'grey', 2);
}

/* ------------------------------------- */
/* ------------------------------------- */

/* ---- definition of grid in domain ---- */

var FidHigh = 600 / ResOfGrid;
var FidLow = 200 / ResOfGrid;
var SizeOfGrid = 1;
var StepOfGrid = SizeOfGrid / ResOfGrid;

/* 3D coordinates of grid in domain */
var GridDomain3D = function() {
  /* initial coordinates */
  let ICsX = [];
  let ICsY = [];
  for (let i = 0; i <= 2 * ResOfGrid; i++) {
    ICsX[i] = [
      [-SizeOfGrid + i * StepOfGrid, -SizeOfGrid, -1],
      [-SizeOfGrid + i * StepOfGrid, SizeOfGrid, -1]
    ];
    ICsY[i] = [
      [-SizeOfGrid, -SizeOfGrid + i * StepOfGrid, -1],
      [SizeOfGrid, -SizeOfGrid + i * StepOfGrid, -1]
    ];
  }
  return ([ICsX, ICsY])
}

/* 2D coordinates of grid in domain */
var GridDomain = function() {
  return GridCoordsConv(GridDomain3D())
};

DrawGrid(GridDomain);

var GridDomainParam = GridParam(GridDomain3D);

/* ------------------------------------- */
/* ------------------------------------- */

/* draws point in domain at which the taylor polynomial is developed */
var PointOfDev = board.create('point', CamProjection([PointOfDevInit[0], PointOfDevInit[1], -1]),{visible: false});
var PointOfDev3D = function() {
/*  return CamInv([PointOfDev.X(), PointOfDev.Y(), -1]) */
  return [PointOfDevInit[0], PointOfDevInit[1], -1]
};

PointOfDev.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return '(' + JXG.toFixed(
        PointOfDev3D()[0], 2) + ', ' +
      JXG.toFixed(
        PointOfDev3D()[1], 2) + ')'
  }
});

/* draws dashed lines to indicate position of PointOfDev and PointOnGraph*/
/* DrawSegment(PointOfDev3D, () => [PointOfDev3D()[0], 0, PointOfDev3D()[2]], 'grey', 2); */
/* DrawSegment(PointOfDev3D, () => [0, PointOfDev3D()[1], PointOfDev3D()[2]], 'grey', 2); */

/* ------------------------------------- */
/* ------------------------------------- */

/* draws arbitrary point in domain to visualize difference between (approximated) function and approximating function */
var ArbPointInDom = board.create('point', CamProjection([state[0], state[1], -1]));
var ArbPointInDom3D = function() {
  return CamInv([ArbPointInDom.X(), ArbPointInDom.Y(), -1])
};

ArbPointInDom.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return '(' + JXG.toFixed(
        ArbPointInDom3D()[0], 2) + ', ' +
      JXG.toFixed(
        ArbPointInDom3D()[1], 2) + ')'
  }
});

/* draws dashed lines to indicate position of PointOfDev and PointOnGraph*/
DrawSegment(ArbPointInDom3D, () => [ArbPointInDom3D()[0], 0, ArbPointInDom3D()[2]], 'grey', 2);
DrawSegment(ArbPointInDom3D, () => [0, ArbPointInDom3D()[1], ArbPointInDom3D()[2]], 'grey', 2);

/* ------------------------------------- */
/* ------------------------------------- */

var PointDefRad = board.create('point', CamProjection([0.3, 0.3, -1]), {
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: false,
  visible : false,
});
var PointDefRad3D = function() {
  return CamInv([PointDefRad.X(), PointDefRad.Y(), -1])
};

var RadiusOfCircle = function() {
  return EuclidDist(ArbPointInDom3D(), PointDefRad3D())
}

PointDefRad.setAttribute({
  showInfobox: false,
  layer: 4,
  color: Color3,
  name: function() {
    return JXG.toFixed(RadiusOfCircle(), 2)
  }
});

/* function that draws image of circle at given 3D point with given radius under given function */
var DrawCircleAtPoint = function(P, r, F, C) {
  let ICsX = function(t) {
    return P()[0] + r() * Math.cos(t)
  };
  let ICsY = function(t) {
    return P()[1] + r() * Math.sin(t)
  };
  let ICsZ = function(t) {
    return F(ICsX(t), ICsY(t))
  };
  let UCs = function(t) {
    return CamProjection([ICsX(t), ICsY(t), ICsZ(t)])
  };
  board.create('curve', [function(t) {
      return UCs(t)[0]
    },
    function(t) {
      return UCs(t)[1]
    },
    0, 6.5
  ], {
    strokecolor: C,
    strokeWidth: 1,
    layer: 2,
    highlight: false,
    fixed: true,
    doAdvancedPlot: false,
    numberPointsHigh: FidHigh * 2,
    numberPointsLow: FidLow * 2,
  });
}

/* draw circles at point in domain and their images */

/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, () => -1, Color3); */
/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, ExFunc, Color4); */
/* DrawCircleAtPoint(ArbPointInDom3D, RadiusOfCircle, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4); */

/* ------------------------------------- */
/* ------------------------------------- */

/* draws images of points in domain */

/* DrawPoint(PointOfDev3D, ExFunc, 'Grey'); */
DrawPoint(ArbPointInDom3D, ExFunc, Color1);
DrawPoint(ArbPointInDom3D, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4);

/* ------------------------------------- */
/* ------------------------------------- */

/* draw graph of (approximated) function */
DrawGraph(GridDomainParam, ExFunc, Color1)

/* draw graph of approximating function */
DrawGraph(GridDomainParam, function(x, y) {
  return ApproxFunc(x, y, PointOfDev3D()[0], PointOfDev3D()[1])
}, Color4)

/* ------------------------------------- */
/* ------------------------------------- */

board.on('move', function() {
  board.suspendUpdate();

  /* returns point in domain close to given point */
  const ReturnToDomain =
    function(a) {
      let Output = [];
      if (a[0] < -1) {
        Output[0] = -1;
      } else if (a[0] > 1) {
        Output[0] = 1;
      } else {
        Output[0] = a[0];
      }
      if (a[1] < -1) {
        Output[1] = -1;
      } else if (a[1] > 1) {
        Output[1] = 1;
      } else {
        Output[1] = a[1];
      }
      Output[2] = a[2];
      return Output
    };
  PointOfDev.moveTo(CamProjection(ReturnToDomain(PointOfDev3D())));
  ArbPointInDom.moveTo(CamProjection(ReturnToDomain(ArbPointInDom3D())));
  PointDefRad.moveTo(CamProjection(ReturnToDomain(PointDefRad3D())));
  board.unsuspendUpdate();
});

/* ------------------------------------- */
/* ------------------------------------- */

var newState =  [Math.round(ArbPointInDom3D()[0]*100)/100, Math.round(ArbPointInDom3D()[1]*100)/100, SliderAngleOfProj1.Value(),SliderAngleOfProj2.Value()];
var ClickIndicator = 0;

var SendData = function(){
     newState = [Math.round(ArbPointInDom3D()[0]*100)/100, Math.round(ArbPointInDom3D()[1]*100)/100,SliderAngleOfProj1.Value(),SliderAngleOfProj2.Value()];
     stateInput.value = JSON.stringify(newState);
     stateInput.dispatchEvent(new Event('change'));
}

ArbPointInDom.on('drag', function () {
   SendData();
});

stateInput.style.display = 'none';

/* ------------------------------------- */
/* ------------------------------------- */

/* ensures that all draggable points (e.g. PointOfDev, ArbPointInDom) are rotatated accordingly when angles of projections are changed by sliders */

/* Buffer */
var PointOfDevBuffer = PointOfDev3D();
var ArbPointInDomBuffer = ArbPointInDom3D();
var PointDefRadBuffer = PointDefRad3D();

/* function that updates position of objects */

var UpdatePos = function(){
    let ICs1 = CamProjection(PointOfDevBuffer);
    let ICs2 = CamProjection(ArbPointInDomBuffer);
    let ICs3 = CamProjection(PointDefRadBuffer);
    board.suspendUpdate();
    PointOfDev.moveTo([
      ICs1[0],
      ICs1[1]
    ]);
    ArbPointInDom.moveTo([
      ICs2[0],
      ICs2[1]
    ]);
    PointDefRad.moveTo([
      ICs3[0],
      ICs3[1]
    ]);
    board.unsuspendUpdate();
   SendData();
}

SliderAngleOfProj1.on('down', function() {
  PointOfDevBuffer = PointOfDev3D();
  ArbPointInDomBuffer = ArbPointInDom3D();
  PointDefRadBuffer = PointDefRad3D();
  SliderAngleOfProj1.on('drag', function() {
  UpdatePos()
  });
});

SliderAngleOfProj2.on('down', function() {
  PointOfDevBuffer = PointOfDev3D();
  ArbPointInDomBuffer = ArbPointInDom3D();
  PointDefRadBuffer = PointDefRad3D();
  SliderAngleOfProj2.on('drag', function() {
  UpdatePos()
  });
});

ArbPointInDom.on('down', function() {
  PointDefRadBuffer = VecSubVec(ArbPointInDom3D(), PointDefRad3D());
  ArbPointInDom.on('drag', function() {
    let ICs = CamProjection(VecSubVec(ArbPointInDom3D(), PointDefRadBuffer));
    board.suspendUpdate();
    PointDefRad.moveTo([
      ICs[0],
      ICs[1]
    ]);
    board.unsuspendUpdate();
  });
});

/* ------------------------------------- */
/* ------------------------------------- */

[[/jsxgraph]]</p>
<hr>
<p style="text-align: justify;">Geben Sie mithilfe der obigen Abbildung einen Entwicklungspunkt \((a,b) \in [-1,1]^2\) des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\) an. Verschieben Sie dazu das Funktionsargument in der \(x_1 x_2\)-Ebene (Punkt <font color="#DC267F">&#x25CF</font>) an die Position eines Entwicklungspunktes. [[input:ans1]]</p>
<p style="text-align: justify;">[[validation:ans1]]</p>
<p style="text-align: justify;">[[feedback:prt1]]</p>
<hr>]]></text>
    </questiontext>
    <generalfeedback format="html">
      <text><![CDATA[<p style="text-align: justify;">Ein Taylorpolynom {@NumberWords1[Order+1]@} Grades von \({@FuncName@}\) am Entwicklungspunkt \((a,b)\) ist von der Form</p>
<p style="text-align: justify;margin-left:30px">\(\displaystyle
{@FuncName@}(a,b)
+ \frac{\partial {@FuncName@}}{\partial x}(a,b)\,x
+ \frac{\partial {@FuncName@}}{\partial y}(a,b)\,y
+ \frac{\partial^2 {@FuncName@}}{\partial x^2}(a,b)\,x^2  
+ \frac{\partial^2 {@FuncName@}}{\partial x \partial y}(a,b)\,x \, y  
+ \frac{\partial^2 {@FuncName@}}{\partial y^2}(a,b)\,y^2  
\).</p>
Folglich ist \((a,b)\) genau dann ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\), wenn</p>
<p style="text-align: justify;margin-left:30px">\(\displaystyle
\begin{align}
T_{{@Order@}}{@FuncName@}(a,b) &= {@FuncName@}(a,b),\\
\frac{\partial T_{{@Order@}}{@FuncName@}}{\partial x}(a,b) &= \frac{\partial {@FuncName@}}{\partial x}(a,b),\\
\frac{\partial T_{{@Order@}}{@FuncName@}}{\partial y}(a,b) &= \frac{\partial {@FuncName@}}{\partial y}(a,b),\\
\frac{\partial^2 T_{{@Order@}}{@FuncName@}}{\partial x^2}(a,b) &= \frac{\partial^2 {@FuncName@}}{\partial x^2}(a,b),\\
\frac{\partial^2 T_{{@Order@}}{@FuncName@}}{\partial x \partial y}(a,b) &= \frac{\partial^2 {@FuncName@}}{\partial x \partial y}(a,b),\\
\frac{\partial^2 T_{{@Order@}}{@FuncName@}}{\partial y^2}(a,b) &= \frac{\partial^2 {@FuncName@}}{\partial y^2}(a,b)
\end{align}
\)</p>
<p style="text-align: justify;">ist. Dies ist an dem Punkt \(({@PointOfDev[1]@}, {@PointOfDev[2]@})\) erfüllt.</p>]]></text>
    </generalfeedback>
    <defaultgrade>1.0000000</defaultgrade>
    <penalty>0.0000000</penalty>
    <hidden>0</hidden>
    <idnumber></idnumber>
    <stackversion>
      <text>2023010400</text>
    </stackversion>
    <questionvariables>
      <text><![CDATA[/* --------------------------- */
/* --------------------------- */

/* Darstellung */

NumberWords1 : ["nullten", "ersten", "zweiten", "dritten", "vierten", "fünften", "sechsten", "siebten", "achten", "neunten", "zehnten", "elften", "zwölften"];
NumberWords2 : ["nullter", "erster", "zweiter", "dritter", "vierter", "fünfter", "sechster", "siebter", "achter", "neunter", "zehnter", "elfter", "zwölfter"];

ResOfGrid : 5; /* Gitterabstand (-> Abbildung) */
SliderPos : [0.1,-0.65]; /* Position der Kameraslider bei Initialisierung (-> Abbildung) */

/* --------------------------- */
/* --------------------------- */

/* Definition / Randomisierung */

/* Auswahl der (zu approximierenden) Funktion */

ExpList : random_permutation([0,1,2]);
b1 : ExpList[1];
b2 : 2-b1;
c1 : ExpList[2];
c2 : 2-c1;

a1 : rand([-1,1]);
a2 : rand([-a1,1]);

Polynomial: a1*x^b1*y^b2 + a2*x^c1*y^c2;

t1 : rand([1,2]);
TFunc1: [cos(t),sin(t)];
SelectedFunction: subst(Polynomial, t , TFunc1[t1])

/* --------------------------- */

/* Koordinaten des Entwicklungspunkts 'PointOfDev': Die Koordinaten des Entwicklungspunktes sind so gewählt, dass '[0,0]' kein Entwicklungspunkt des zugehörigen Taylorpolynoms ist (relevant für Ordnung null)*/

ListOfCoord : random_permutation([4,6,8]);
PointOfDevX : float(a1*ListOfCoord[1]/10);
PointOfDevY : float(a2*ListOfCoord[2]/10);

PointOfDev : [PointOfDevX,PointOfDevY]; /* Entwicklungspunkt */

/* --------------------------- */
/* --------------------------- */

/* Definitionen */

FuncName : f; /* Bezeichner der Funktion */
Argument : [0,0]; /* Funktionsargument (-> Abbildung); sollte ungleich 'PointOfDev' gewählt werden */
Order : 2; /* Ordnung der Taylor-Entwicklung (-> Abbildung; kleiner oder gleich 'MaxOrder') */
MaxOrder : 2; /* maximale Ordnung der Taylor-Entwicklung (-> Abbildung; mindestens 1) */

/* --------------------------- */

/* Liste aller Taylor-Polynome bis zur maximalen Ordnung */
ListOfFunctions:[]
IndexOrder: 0;
while length(ListOfFunctions) <= max(MaxOrder,Order) do (
  ListOfFunctions : append(ListOfFunctions,[expand(taylor(SelectedFunction, [x,y], [a,b], IndexOrder))]),
  IndexOrder : IndexOrder + 1
);

/* --------------------------- */

/* Antworten */
TeacherAnswerA : append(PointOfDev, SliderPos);
WrongAnswer : [0,0];

/* --------------------------- */
/* --------------------------- */

/* Hilsfunktionen */

ListSubst(SList,List,Expr) := 
  block([Length, Index, OutPut],
    Length : min(length(SList),length(List)),
    Index : 1,
    Output : Expr,
    while Index <= Length do (
      Output : subst(SList[Index], List[Index], Output),
      Index : Index + 1
    ),
    Output
  );

/* --------------------------- */
/* --------------------------- */

/* Benjamin Herbert Schulz-Rosenberger */]]></text>
    </questionvariables>
    <specificfeedback format="html">
      <text></text>
    </specificfeedback>
    <questionnote>
      <text>\[\textstyle f(x,y)={@ SelectedFunction@}\]</text>
    </questionnote>
    <questionsimplify>1</questionsimplify>
    <assumepositive>0</assumepositive>
    <assumereal>0</assumereal>
    <prtcorrect format="html">
      <text></text>
    </prtcorrect>
    <prtpartiallycorrect format="html">
      <text></text>
    </prtpartiallycorrect>
    <prtincorrect format="html">
      <text></text>
    </prtincorrect>
    <multiplicationsign>none</multiplicationsign>
    <sqrtsign>1</sqrtsign>
    <complexno>i</complexno>
    <inversetrig>cos-1</inversetrig>
    <logicsymbol>lang</logicsymbol>
    <matrixparens>(</matrixparens>
    <variantsselectionseed></variantsselectionseed>
    <input>
      <name>ans1</name>
      <type>algebraic</type>
      <tans>TeacherAnswerA</tans>
      <boxsize>15</boxsize>
      <strictsyntax>1</strictsyntax>
      <insertstars>0</insertstars>
      <syntaxhint></syntaxhint>
      <syntaxattribute>0</syntaxattribute>
      <forbidwords></forbidwords>
      <allowwords></allowwords>
      <forbidfloat>0</forbidfloat>
      <requirelowestterms>0</requirelowestterms>
      <checkanswertype>0</checkanswertype>
      <mustverify>0</mustverify>
      <showvalidation>0</showvalidation>
      <options></options>
    </input>
    <prt>
      <name>prt1</name>
      <value>1.0000000</value>
      <autosimplify>1</autosimplify>
      <feedbackstyle>1</feedbackstyle>
      <feedbackvariables>
        <text><![CDATA[/* --------------------- */

StudentAnswer : [ans1[1],ans1[2]];

/* --------------------- */

/* 'StudentAnswerValue' gibt an, ob 'ans1' in dem Einheitsquadrat [-1,1]^2 enthalten ist. */

StudentAnswerCond : false;
if length(StudentAnswer) = 2 then (
StudentAnswerCond : is(StudentAnswer[1] >= -1) and is(StudentAnswer[1] <= 1) and is(StudentAnswer[2] >= -1) and is(StudentAnswer[2] <= 1)
)

/* --------------------- */

/* 'StudentAnswerValue1' gibt an, ob der Funktionswert von 'SelectedFunction' an 'ans1' dem Funktionswert von 'ListOfFunctions[Order+1]' an '[(StudentAnswer[1], StudentAnswer[2],PointOfDev[1],PointOfDev[2])]' entspricht. */
 
StudentAnswerValue1 : false;
if length(StudentAnswer) = 2 and StudentAnswerCond then (
Dist : abs( ListSubst(StudentAnswer, [x,y], SelectedFunction) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], ListOfFunctions[Order+1])),
StudentAnswerValue1 : is( Dist < 0.02 )
)

/* --------------------- */

/* 'StudentAnswerValue2' gibt an, ob der die ersten partiellen Ableitungen von 'SelectedFunction' an 'ans1' den ersten partiellen Ableitungen von 'ListOfFunctions[Order+1]' an '[(StudentAnswer[1], StudentAnswer[2],PointOfDev[1],PointOfDev[2])]' entsprechen. */
 
StudentAnswerValue2 : false;
if length(StudentAnswer) = 2 and StudentAnswerCond and StudentAnswerValue1 then (
DistPartX : abs( ListSubst(StudentAnswer, [x,y], diff(SelectedFunction,x,1)) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], diff(ListOfFunctions[Order+1],x,1))),
DistPartY : abs( ListSubst(StudentAnswer, [x,y], diff(SelectedFunction,y,1)) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], diff(ListOfFunctions[Order+1],y,1))),
StudentAnswerValue2 : is( max(DistPartX, DistPartY) < 0.02 )
)

/* --------------------- */

/* 'StudentAnswerValue3' gibt an, ob der die zweiten partiellen Ableitungen von 'SelectedFunction' an 'ans1' den zweiten partiellen Ableitungen von 'ListOfFunctions[Order+1]' an '[(StudentAnswer[1], StudentAnswer[2],PointOfDev[1],PointOfDev[2])]' entsprechen. */
 
StudentAnswerValue3 : false;
if length(StudentAnswer) = 2 and StudentAnswerCond and StudentAnswerValue1 then (
DistPartXX : abs( ListSubst(StudentAnswer, [x,y], diff(SelectedFunction,x,2)) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], diff(ListOfFunctions[Order+1],x,2))),
DistPartXY : abs( ListSubst(StudentAnswer, [x,y], diff(diff(SelectedFunction,x,1),y,1)) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], diff(diff(ListOfFunctions[Order+1],x,1),y,1))),
DistPartYY : abs( ListSubst(StudentAnswer, [x,y], diff(SelectedFunction,y,2)) - ListSubst(append(StudentAnswer, PointOfDev), [x,y,a,b], diff(ListOfFunctions[Order+1],y,2))),
StudentAnswerValue3 : is( max(DistPartXX, DistPartXY, DistPartYY) < 0.02 )
)

/* --------------------- */]]></text>
      </feedbackvariables>
      <node>
        <name>0</name>
        <answertest>AlgEquiv</answertest>
        <sans>length(StudentAnswer)</sans>
        <tans>2</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>1</truenextnode>
        <trueanswernote>prt1-1-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-1-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\) ist insbesondere ein Element von \(\mathbb{D}_{@FuncName@} \subset \mathbb{R}^2\). Der von Ihnen eingegebene Punkt kann nicht oder nicht eindeutig einem Punkt in \(\mathbb{R}^2\) zugeordnet werden.
</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>1</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerCond</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>2</truenextnode>
        <trueanswernote>prt1-2-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-2-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt liegt nicht (oder nicht eindeutig) in \([-1,1]^2 \subset \mathbb{R}^2\).</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>2</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerValue1</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>3</truenextnode>
        <trueanswernote>prt1-3-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-3-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist kein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\). Beachten Sie, dass das Taylorpolynom \(T_{{@Order@}}{@FuncName@}\) insbesondere auch eine Approximation {@NumberWords2[Order-1]@} Ordnung an {@FuncName@} ist.</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>3</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerValue2</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>0</truescore>
        <truepenalty></truepenalty>
        <truenextnode>4</truenextnode>
        <trueanswernote>prt1-4-T</trueanswernote>
        <truefeedback format="html">
          <text></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-4-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist kein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\). Beachten Sie, dass das Taylorpolynom \(T_{{@Order@}}{@FuncName@}\) insbesondere auch eine Approximation {@NumberWords2[Order]@} Ordnung an {@FuncName@} ist.</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
      <node>
        <name>4</name>
        <answertest>AlgEquiv</answertest>
        <sans>StudentAnswerValue3</sans>
        <tans>true</tans>
        <testoptions></testoptions>
        <quiet>1</quiet>
        <truescoremode>+</truescoremode>
        <truescore>1</truescore>
        <truepenalty></truepenalty>
        <truenextnode>-1</truenextnode>
        <trueanswernote>prt1-5-T</trueanswernote>
        <truefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist ein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\).</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist richtig.</strong></p>]]></text>
        </truefeedback>
        <falsescoremode>+</falsescoremode>
        <falsescore>0</falsescore>
        <falsepenalty></falsepenalty>
        <falsenextnode>-1</falsenextnode>
        <falseanswernote>prt1-5-F</falseanswernote>
        <falsefeedback format="html">
          <text><![CDATA[<p style="text-align: justify;">Der von Ihnen eingegebene Punkt ist kein Entwicklungspunkt des Taylorpolynoms \(T_{{@Order@}}{@FuncName@}\) von \({@FuncName@}\). Beachten Sie, dass für eine  Approximation {@NumberWords2[Order+1]@} Ordnung an {@FuncName@} durch das Taylorpolynom \(T_{{@Order@}}{@FuncName@}\) an einem Entwicklungspunkt \((a,b)\) neben \(T_{{@Order@}}{@FuncName@}(a,b)={@FuncName@}(a,b)\), \(\frac{\partial T_{{@Order@}}{@FuncName@}}{\partial x}(a,b)=\frac{\partial {@FuncName@}}{\partial x}(a,b)\) und \(\frac{\partial T_{{@Order@}}{@FuncName@}}{\partial y}(a,b)=\frac{\partial {@FuncName@}}{\partial y}(a,b)\) weitere Eigenschaften gelten.</p>
<p style="text-align: justify;"><strong>Ihre Antwort ist falsch.</strong></p>]]></text>
        </falsefeedback>
      </node>
    </prt>
    <qtest>
      <testcase>1</testcase>
      <testinput>
        <name>ans1</name>
        <value>TeacherAnswerA</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>1.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-5-T</expectedanswernote>
      </expected>
    </qtest>
    <qtest>
      <testcase>2</testcase>
      <testinput>
        <name>ans1</name>
        <value>[2,2]</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>0.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-2-F</expectedanswernote>
      </expected>
    </qtest>
    <qtest>
      <testcase>3</testcase>
      <testinput>
        <name>ans1</name>
        <value>WrongAnswer</value>
      </testinput>
      <expected>
        <name>prt1</name>
        <expectedscore>0.0000000</expectedscore>
        <expectedpenalty></expectedpenalty>
        <expectedanswernote>prt1-3-F</expectedanswernote>
      </expected>
    </qtest>
    <tags>
      <tag><text>Approximation</text>
</tag>
      <tag><text>Taylorpolynom</text>
</tag>
      <tag><text>Entwicklungspunkt</text>
</tag>
    </tags>
  </question>

</quiz>