Commit 88c98b9a by Александр Committed by Alexander Kryklia

added multiple regions support

parent 7fcf04ea
...@@ -23,6 +23,7 @@ import abc ...@@ -23,6 +23,7 @@ import abc
import os import os
import subprocess import subprocess
import xml.sax.saxutils as saxutils import xml.sax.saxutils as saxutils
from shapely.geometry import Polygon, Point
# specific library imports # specific library imports
from calc import evaluator, UndefinedVariable from calc import evaluator, UndefinedVariable
...@@ -1720,12 +1721,20 @@ class ImageResponse(LoncapaResponse): ...@@ -1720,12 +1721,20 @@ class ImageResponse(LoncapaResponse):
Lon-CAPA requires that each <imageresponse> has a <foilgroup> inside it. That Lon-CAPA requires that each <imageresponse> has a <foilgroup> inside it. That
doesn't make sense to me (Ike). Instead, let's have it such that <imageresponse> doesn't make sense to me (Ike). Instead, let's have it such that <imageresponse>
should contain one or more <imageinput> stanzas. Each <imageinput> should specify should contain one or more <imageinput> stanzas. Each <imageinput> should specify
a rectangle, given as an attribute, defining the correct answer. a rectangle(s) or region(s), given as an attribute, defining the correct answer.
Rectangle(s) are more prioritized over regions due to simplicity and backward compatibility.
In this example regions will be ignored:
<imageinput src="/static/images/Lecture2/S2_p04.png" width="811" height="610" rectangle="(10,10)-(20,30);(12,12)-(40,60)" regions='[[[10,10], [20,30], [40, 10]], [[100,100], [120,130], [110,150]]]'/>
Regions is list of lists [region1, region2, region3, ...] where regionN is ordered list of points: [[1,1], [100,100], [50,50], [20, 70]].
""" """
snippets = [{'snippet': '''<imageresponse> snippets = [{'snippet': '''<imageresponse>
<imageinput src="image1.jpg" width="200" height="100" rectangle="(10,10)-(20,30)" /> <imageinput src="image1.jpg" width="200" height="100" rectangle="(10,10)-(20,30)" />
<imageinput src="image2.jpg" width="210" height="130" rectangle="(12,12)-(40,60)" /> <imageinput src="image2.jpg" width="210" height="130" rectangle="(12,12)-(40,60)" />
<imageinput src="image2.jpg" width="210" height="130" rectangle="(10,10)-(20,30);(12,12)-(40,60)" /> <imageinput src="image3.jpg" width="210" height="130" rectangle="(10,10)-(20,30);(12,12)-(40,60)" />
<imageinput src="image4.jpg" width="811" height="610" rectangle="(10,10)-(20,30);(12,12)-(40,60)" regions='[[[10,10], [20,30], [40, 10]], [[100,100], [120,130], [110,150]]]'/>
<imageinput src="image5.jpg" width="200" height="200" regions='[[[10,10], [20,30], [40, 10]], [[100,100], [120,130], [110,150]]]' />
</imageresponse>'''}] </imageresponse>'''}]
response_tag = 'imageresponse' response_tag = 'imageresponse'
...@@ -1753,8 +1762,10 @@ class ImageResponse(LoncapaResponse): ...@@ -1753,8 +1762,10 @@ class ImageResponse(LoncapaResponse):
'error grading %s (input=%s)' % (aid, given)) 'error grading %s (input=%s)' % (aid, given))
(gx, gy) = [int(x) for x in m.groups()] (gx, gy) = [int(x) for x in m.groups()]
rectangles, regions = expectedset
if rectangles[aid]: # rectangles part - for backward compatibility
# Check whether given point lies in any of the solution rectangles # Check whether given point lies in any of the solution rectangles
solution_rectangles = expectedset[aid].split(';') solution_rectangles = rectangles[aid].split(';')
for solution_rectangle in solution_rectangles: for solution_rectangle in solution_rectangles:
# parse expected answer # parse expected answer
# TODO: Compile regexp on file load # TODO: Compile regexp on file load
...@@ -1770,12 +1781,18 @@ class ImageResponse(LoncapaResponse): ...@@ -1770,12 +1781,18 @@ class ImageResponse(LoncapaResponse):
if (llx <= gx <= urx) and (lly <= gy <= ury): if (llx <= gx <= urx) and (lly <= gy <= ury):
correct_map.set(aid, 'correct') correct_map.set(aid, 'correct')
break break
else: # rectangles are more prioretized for same id
if regions[aid]:
parsed_region = json.loads(regions[aid])
for region in parsed_region:
if Polygon(region).contains(Point(gx, gy)):
correct_map.set(aid, 'correct')
break
return correct_map return correct_map
def get_answers(self): def get_answers(self):
return dict([(ie.get('id'), ie.get('rectangle')) for ie in self.ielements]) return (dict([(ie.get('id'), ie.get('rectangle')) for ie in self.ielements]),
dict([(ie.get('id'), ie.get('regions')) for ie in self.ielements]))
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# TEMPORARY: List of all response subclasses # TEMPORARY: List of all response subclasses
# FIXME: To be replaced by auto-registration # FIXME: To be replaced by auto-registration
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment