// Numbas version: finer_feedback_settings {"name": "Perpendicular distance between a point and line", "extensions": ["geogebra", "quantities"], "custom_part_types": [{"source": {"pk": 19, "author": {"name": "William Haynes", "pk": 2530}, "edit_page": "/part_type/19/edit"}, "name": "Engineering Accuracy with units", "short_name": "engineering-answer", "description": "

A value with units marked right if within an adjustable % error of the correct value.  Marked close if within a wider margin of error.

", "help_url": "", "input_widget": "string", "input_options": {"correctAnswer": "siground(settings['correctAnswer'],4)", "hint": {"static": true, "value": ""}, "allowEmpty": {"static": true, "value": true}}, "can_be_gap": true, "can_be_step": true, "marking_script": "mark:\nswitch( \n right and good_units and right_sign, add_credit(1.0,'Correct.'),\n right and good_units and not right_sign, add_credit(settings['C2'],'Wrong sign.'),\n right and right_sign and not good_units, add_credit(settings['C2'],'Correct value, but wrong or missing units.'),\n close and good_units, add_credit(settings['C1'],'Close.'),\n close and not good_units, add_credit(settings['C3'],'Answer is close, but wrong or missing units.'),\n incorrect('Wrong answer.')\n)\n\n\ninterpreted_answer:\nqty(student_scalar, student_units)\n\n\n\ncorrect_quantity:\nsettings[\"correctAnswer\"]\n\n\n\ncorrect_units:\nunits(correct_quantity)\n\n\nallowed_notation_styles:\n[\"plain\",\"en\"]\n\nmatch_student_number:\nmatchnumber(studentAnswer,allowed_notation_styles)\n\nstudent_scalar:\nmatch_student_number[1]\n\nstudent_units:\nreplace_regex('ohms','ohm',\n replace_regex('\u00b0', ' deg',\n replace_regex('-', ' ' ,\n studentAnswer[len(match_student_number[0])..len(studentAnswer)])),\"i\")\n\ngood_units:\ntry(\ncompatible(quantity(1, student_units),correct_units),\nmsg,\nfeedback(msg);false)\n\n\nstudent_quantity:\nswitch(not good_units, \n student_scalar * correct_units, \n not right_sign,\n -quantity(student_scalar, student_units),\n quantity(student_scalar,student_units)\n)\n \n\n\npercent_error:\ntry(\nscalar(abs((correct_quantity - student_quantity)/correct_quantity))*100 \n,msg,\nif(student_quantity=correct_quantity,0,100))\n \n\nright:\npercent_error <= settings['right']\n\n\nclose:\nright_sign and percent_error <= settings['close']\n\nright_sign:\nsign(student_scalar) = sign(correct_quantity)", "marking_notes": [{"name": "mark", "description": "This is the main marking note. It should award credit and provide feedback based on the student's answer.", "definition": "switch( \n right and good_units and right_sign, add_credit(1.0,'Correct.'),\n right and good_units and not right_sign, add_credit(settings['C2'],'Wrong sign.'),\n right and right_sign and not good_units, add_credit(settings['C2'],'Correct value, but wrong or missing units.'),\n close and good_units, add_credit(settings['C1'],'Close.'),\n close and not good_units, add_credit(settings['C3'],'Answer is close, but wrong or missing units.'),\n incorrect('Wrong answer.')\n)\n"}, {"name": "interpreted_answer", "description": "A value representing the student's answer to this part.", "definition": "qty(student_scalar, student_units)\n\n"}, {"name": "correct_quantity", "description": "", "definition": "settings[\"correctAnswer\"]\n\n"}, {"name": "correct_units", "description": "", "definition": "units(correct_quantity)\n"}, {"name": "allowed_notation_styles", "description": "", "definition": "[\"plain\",\"en\"]"}, {"name": "match_student_number", "description": "", "definition": "matchnumber(studentAnswer,allowed_notation_styles)"}, {"name": "student_scalar", "description": "", "definition": "match_student_number[1]"}, {"name": "student_units", "description": "

Modify the unit portion of the student's answer by

\n

1. replacing \"ohms\" with \"ohm\"  case insensitive

\n

2. replacing '-' with ' ' 

\n

3. replacing '°' with ' deg' 

\n

to allow answers like 10 ft-lb and 30°

", "definition": "replace_regex('ohms','ohm',\n replace_regex('\u00b0', ' deg',\n replace_regex('-', ' ' ,\n studentAnswer[len(match_student_number[0])..len(studentAnswer)])),\"i\")"}, {"name": "good_units", "description": "", "definition": "try(\ncompatible(quantity(1, student_units),correct_units),\nmsg,\nfeedback(msg);false)\n"}, {"name": "student_quantity", "description": "

This fixes the student answer for two common errors.  

\n

If student_units are wrong  - replace with correct units

\n

If student_scalar has the wrong sign - replace with right sign

\n

If student makes both errors, only one gets fixed.

", "definition": "switch(not good_units, \n student_scalar * correct_units, \n not right_sign,\n -quantity(student_scalar, student_units),\n quantity(student_scalar,student_units)\n)\n \n"}, {"name": "percent_error", "description": "", "definition": "try(\nscalar(abs((correct_quantity - student_quantity)/correct_quantity))*100 \n,msg,\nif(student_quantity=correct_quantity,0,100))\n "}, {"name": "right", "description": "", "definition": "percent_error <= settings['right']\n"}, {"name": "close", "description": "

Only marked close if the student actually has the right sign.

", "definition": "right_sign and percent_error <= settings['close']"}, {"name": "right_sign", "description": "", "definition": "sign(student_scalar) = sign(correct_quantity) "}], "settings": [{"name": "correctAnswer", "label": "Correct Quantity.", "help_url": "", "hint": "The correct answer given as a JME quantity.", "input_type": "code", "default_value": "", "evaluate": true}, {"name": "right", "label": "% Accuracy for right.", "help_url": "", "hint": "Question will be considered correct if the scalar part of the student's answer is within this % of correct value.", "input_type": "code", "default_value": "0.2", "evaluate": true}, {"name": "close", "label": "% Accuracy for close.", "help_url": "", "hint": "Question will be considered close if the scalar part of the student's answer is within this % of correct value.", "input_type": "code", "default_value": "1.0", "evaluate": true}, {"name": "C1", "label": "Close with units.", "help_url": "", "hint": "Partial Credit for close value with appropriate units.  if correct answer is 100 N and close is ±1%,
99  N is accepted.", "input_type": "percent", "default_value": "75"}, {"name": "C2", "label": "No units or wrong sign", "help_url": "", "hint": "Partial credit for forgetting units or using wrong sign.
If the correct answer is 100 N, both 100 and -100 N are accepted.", "input_type": "percent", "default_value": "50"}, {"name": "C3", "label": "Close, no units.", "help_url": "", "hint": "Partial Credit for close value but forgotten units.
This value would be close if the expected units were provided.  If the correct answer is 100 N, and close is ±1%,
99 is accepted.", "input_type": "percent", "default_value": "25"}], "public_availability": "always", "published": true, "extensions": ["quantities"]}], "resources": [["question-resources/perpdist.ggb", "/srv/numbas/media/question-resources/perpdist.ggb"]], "navigation": {"allowregen": true, "showfrontpage": false, "preventleave": false, "typeendtoleave": false}, "question_groups": [{"pickingStrategy": "all-ordered", "questions": [{"name": "Perpendicular distance between a point and line", "tags": [], "metadata": {"description": "

Given a point and a line, determine the distance between them.

", "licence": "Creative Commons Attribution-NonCommercial 4.0 International"}, "statement": "

{show_triangle(applet,debug)}

\n

Determine the perpendicular distance between point $B$ = ({B[0]}, {B[1]}) and a line passing through point $A$ = ({A[0]}, {A[1]})  with a {rise}:{run} slope.  Grid units are {units}.

\n

d: {siground(d,3)} dperp: {siground(dperp,3) } theta: {siground(degrees(theta),3)} 

\n

", "advice": "
    \n
  1. Draw a diagram showing a triangle with sides that are the perpendicular distance $d_\\perp$ and direct distance $d = \\overline{AB}$. 
  2. \n
  3. Use the distance formula to find the length of segment $\\overline{AB}$.
  4. \n
  5. Use trig to find the angle that segment $AB$ makes with the $x$- or $y$- axis.
  6. \n
  7. Use geometry to determine an angle in the triangle.  Note that the angle that $d_\\perp$ makes with the vertical is the same as the angle that the line makes with the horizontal.  Perpendicular lines have negative reciprocal slopes.
  8. \n
  9. Use trig with the known hypotenuse $d$ and the angle to solve for perpendicular distance $d_\\perp$.
  10. \n
", "rulesets": {}, "extensions": ["geogebra", "quantities"], "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"dperp": {"name": "dperp", "group": "Ungrouped variables", "definition": "abs(cross(r,f))", "description": "

perpendicular distance from B to line

", "templateType": "anything", "can_override": false}, "alpha": {"name": "alpha", "group": "Ungrouped variables", "definition": "arctan(Rise/Run)", "description": "

angle line makes with the horizontal

", "templateType": "anything", "can_override": false}, "debug": {"name": "debug", "group": "Ungrouped variables", "definition": "false", "description": "", "templateType": "anything", "can_override": false}, "d": {"name": "d", "group": "Ungrouped variables", "definition": "abs(A-B)", "description": "

distance from A to B

", "templateType": "anything", "can_override": false}, "A": {"name": "A", "group": "input", "definition": "vector(random(-6..6),random(-6..6))", "description": "

point on the line

", "templateType": "anything", "can_override": false}, "B": {"name": "B", "group": "input", "definition": "A + vector(random(-5..5), random(-5..5))", "description": "

the point

", "templateType": "anything", "can_override": false}, "units": {"name": "units", "group": "Ungrouped variables", "definition": "random('in','ft','mm','cm','m')", "description": "", "templateType": "anything", "can_override": false}, "applet": {"name": "applet", "group": "input", "definition": "geogebra_applet('umrzknxw',params)", "description": "", "templateType": "anything", "can_override": false}, "params": {"name": "params", "group": "input", "definition": "[A: A, B: B, Rise: Rise, Run: Run, Z: Z]", "description": "", "templateType": "anything", "can_override": false}, "slopes": {"name": "slopes", "group": "input", "definition": "random([[1,2],[1,3],[1,5],[2,3],[3,4],[5,12]])", "description": "

pick a rise/run ratio for 'nice' choices

", "templateType": "anything", "can_override": false}, "slope": {"name": "slope", "group": "input", "definition": "random([[slopes[0],slopes[1]], [slopes[1],slopes[0]],[-slopes[0],slopes[1]], [-slopes[1],slopes[0]]])", "description": "

permutations of the legal slope

", "templateType": "anything", "can_override": false}, "Rise": {"name": "Rise", "group": "input", "definition": "slope[0]", "description": "

The rise

", "templateType": "anything", "can_override": false}, "Run": {"name": "Run", "group": "input", "definition": "slope[1]", "description": "

The run

", "templateType": "anything", "can_override": false}, "Z": {"name": "Z", "group": "input", "definition": "round(abs(A-B))+1", "description": "

Z sizes the ggb canvas to be large enough to show A and B

", "templateType": "anything", "can_override": false}, "r": {"name": "r", "group": "Ungrouped variables", "definition": "A-B + vector(0,0,0)\n", "description": "

3d vector from B to A

", "templateType": "anything", "can_override": false}, "F": {"name": "F", "group": "Ungrouped variables", "definition": "vector(cos(alpha),sin(alpha),0)", "description": "

3d unit vector  for cross product to find angle theta and dperp

\n

(M= F d sin theta = r x F ), but |F|=1 

", "templateType": "anything", "can_override": true}, "theta": {"name": "theta", "group": "Ungrouped variables", "definition": "degrees(angle(f,r))", "description": "

angle between line and segment d   

", "templateType": "anything", "can_override": false}}, "variablesTest": {"condition": "0.2 < dperp/d < 0.8 and // not too close to 0 or 90\u00b0\nd > 3 // not too small", "maxRuns": 100}, "ungrouped_variables": ["d", "dperp", "debug", "units", "r", "alpha", "F", "theta"], "variable_groups": [{"name": "input", "variables": ["A", "B", "applet", "params", "slopes", "slope", "Rise", "Run", "Z"]}], "functions": {"applets": {"parameters": [], "type": "ggbapplet", "language": "javascript", "definition": "// Create the worksheet. \n// This function returns an object with a container `element` and a `promise` resolving to a GeoGebra applet.\nvar params = {\n material_id: 'ptkds8nz'\n};\nvar result = Numbas.extensions.geogebra.createGeogebraApplet(params);\n\n// Once the applet has loaded, run some commands to manipulate the worksheet.\nresult.promise.then(function(d) {\n var app = d.app;\n question.applet = d;\n \n function setGGBPoint(name, nname=name) {\n // moves point in GGB to Numbas value\n var pt = Numbas.jme.unwrapValue(question.scope.getVariable(nname));\n app.setFixed(name,false,false);\n app.setCoords(name, pt[0], pt[1]);\n app.setFixed(name,true,true);\n }\n \n function setGGBAngle(gname, nname=gname) {\n // Sets angle in GGB to a Numbas Variable given in degrees.\n var v = Math.PI / 180 * Numbas.jme.unwrapValue(question.scope.getVariable(nname));\n app.setValue(gname,v);\n } \n \n \n setGGBPoint(\"A\");\n setGGBPoint(\"B\");\n setGGBAngle(\"\u03b1\",\"alpha\");\n \n \n});\n\n// This function returns the result of `createGeogebraApplet` as an object \n// with the JME data type 'ggbapplet', which can be substituted into the question's content.\nreturn new Numbas.jme.types.ggbapplet(result)"}, "show_triangle": {"parameters": [["app", "ggbapplet"], ["v", "boolean"]], "type": "anything", "language": "javascript", "definition": "// Take an applet, set its perspective to the given string.\n// See https://wiki.geogebra.org/en/SetPerspective_Command for the format of the perspective string.\napp.promise.then(function(d) {\n d.app.setVisible(\"construction\", v);\n d.app.setVisible(\"theta\", v);\n});\nreturn new Numbas.jme.types.ggbapplet(app);"}}, "preamble": {"js": "question.signals.on('adviceDisplayed',function() {\n \n try{\n //var app = question.applet.app;\n var app = Numbas.exam.currentQuestion.scope.variables.applet.app;\n app.setVisible(\"construction\", true);\n app.setVisible(\"theta\", true); \n }\n catch(err){} \n})\n\n", "css": ""}, "parts": [{"type": "gapfill", "useCustomName": true, "customName": "Solutions", "marks": 0, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

Find:

\n

The length of the segment $AB$:

\n

$d = $ [[0]]

\n

The perpendicular distance between the point and the line:

\n

$d_{\\perp} = $ [[1]] 

", "gaps": [{"type": "engineering-answer", "useCustomName": true, "customName": "d", "marks": "10", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "settings": {"correctAnswer": "quantity(abs(d), units)", "right": "0.1", "close": "1.0", "C1": "75", "C2": "50", "C3": "25"}}, {"type": "engineering-answer", "useCustomName": true, "customName": "dperp", "marks": "20", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "settings": {"correctAnswer": "quantity(dperp, units)", "right": "0.1", "close": "1.0", "C1": "75", "C2": "50", "C3": "25"}}], "sortAnswers": false}], "partsMode": "all", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always", "type": "question", "contributors": [{"name": "William Haynes", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/2530/"}]}]}], "contributors": [{"name": "William Haynes", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/2530/"}]}