곰픽 채점 기준 수정버전
This commit is contained in:
BIN
00_DPI_2504B_TEST.xlsx
Normal file
BIN
00_DPI_2504B_TEST.xlsx
Normal file
Binary file not shown.
1467
DIC_2504B.json
1467
DIC_2504B.json
File diff suppressed because it is too large
Load Diff
1391
DIC_2505A.json
1391
DIC_2505A.json
File diff suppressed because it is too large
Load Diff
@@ -1,729 +0,0 @@
|
|||||||
{
|
|
||||||
"0": {
|
|
||||||
"1": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"ele": "$[?(@.width == 65 && @.height == 45)]",
|
|
||||||
"type": "size",
|
|
||||||
"value": {
|
|
||||||
"width": 65,
|
|
||||||
"height": 45
|
|
||||||
},
|
|
||||||
"point": 4
|
|
||||||
},
|
|
||||||
"9": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0,
|
|
||||||
"desc": "파일명 확인"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"1": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"ele": "$.children[?(@.name=='한옥')].name",
|
|
||||||
"value": "한옥",
|
|
||||||
"point": 4
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"ele": "$.children[?(@.name=='Traditional Park')].name",
|
|
||||||
"value": "Traditional Park",
|
|
||||||
"point": 4
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"ele": "$.children[?(@.name=='Traditional Park')].text.font.names[0]",
|
|
||||||
"type": "font",
|
|
||||||
"value": "Arial",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"ele": "$.children[?(@.name=='Traditional Park')].text.font.names[0]",
|
|
||||||
"value": "Arial-BoldItalicMT",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"9": {
|
|
||||||
"ele": "$.children[?(@.name=='Traditional Park')].text.font.sizes[0]",
|
|
||||||
"value": 48,
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"10": {
|
|
||||||
"ele": "$.children[?(@.name=='Traditional Park')].text.font.colors[0]",
|
|
||||||
"type": "color",
|
|
||||||
"value": "017e86",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"11": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"12": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"13": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"14": {
|
|
||||||
"ele": "$.children[?(@.name=='전통 문화 공원')].name",
|
|
||||||
"value": "전통 문화 공원",
|
|
||||||
"point": 4
|
|
||||||
},
|
|
||||||
"15": {
|
|
||||||
"ele": "$.children[?(@.name=='전통 문화 공원')].text.font.names[0]",
|
|
||||||
"type": "font",
|
|
||||||
"value": "GungsuhChe",
|
|
||||||
"point": 2,
|
|
||||||
"desc": {
|
|
||||||
"돋움체": "DotumChe",
|
|
||||||
"궁서체": "GungsuhChe",
|
|
||||||
"굴림체": "GulimChe",
|
|
||||||
"휴먼옛체": "YetR"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"16": {
|
|
||||||
"ele": "$.children[?(@.name=='전통 문화 공원')].text.font.sizes[0]",
|
|
||||||
"value": 36,
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"17": {
|
|
||||||
"ele": "$.children[?(@.name=='전통 문화 공원')].text.font.colors[0]",
|
|
||||||
"type": "color",
|
|
||||||
"value": "ffeeca",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"18": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"19": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"20": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"21": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"22": {
|
|
||||||
"ele": "$.children[?(@.name=='맷돌')].name",
|
|
||||||
"value": "맷돌",
|
|
||||||
"point": 4
|
|
||||||
},
|
|
||||||
"23": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"24": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"25": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0
|
|
||||||
},
|
|
||||||
"26": {
|
|
||||||
"ele": "$[?(@.width == 65 && @.height == 35)]",
|
|
||||||
"type": "size",
|
|
||||||
"value": {
|
|
||||||
"width": 65,
|
|
||||||
"height": 35
|
|
||||||
},
|
|
||||||
"point": 5
|
|
||||||
},
|
|
||||||
"27": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0,
|
|
||||||
"desc": "파일명 확인"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"1": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[not(@Length<='5' and @ClipLength='-1')]/@ClipIndex",
|
|
||||||
"type": "mediaOrder",
|
|
||||||
"value": [
|
|
||||||
"동영상.mp4",
|
|
||||||
"이미지2.jpg",
|
|
||||||
"이미지3.jpg",
|
|
||||||
"이미지1.jpg"
|
|
||||||
],
|
|
||||||
"point": 4,
|
|
||||||
"desc": "비디오1 트랙에 있는 클립의 ClipIndex값을 기준으로 CRClipArr에서 Path값을 가져와서 정답 채점, 클립의 ClipIndex값이 -1인 경우와 길이가 5프레임 이하인 경우는 제외한다."
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"ele": "/CROASTERP/CRTrackArr[1]/CRVideoTrackArr[1]/CRTrackList[1]/CRTrackClip[1]/@Speed",
|
|
||||||
"type": "oneAnswer",
|
|
||||||
"value": {
|
|
||||||
"speed": "120"
|
|
||||||
},
|
|
||||||
"point": 2,
|
|
||||||
"desc": "100당 1배속 / 130 = 1.3배속"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']",
|
|
||||||
"type": "startEnd",
|
|
||||||
"media": "동영상.mp4",
|
|
||||||
"value": {
|
|
||||||
"start": "0",
|
|
||||||
"end": "380"
|
|
||||||
},
|
|
||||||
"point": 2,
|
|
||||||
"desc": "시작시간과 재생시간 정답값 입력, 3번문항은 '동영상.mp4' 클립의 길이를 확인하는 문항이므로 media는 수정할 필요가 없다."
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
|
||||||
"type": "effect",
|
|
||||||
"media": "동영상.mp4",
|
|
||||||
"value": {
|
|
||||||
"ID": "70",
|
|
||||||
"VID100": "30",
|
|
||||||
"VID101": "20"
|
|
||||||
},
|
|
||||||
"point": 3,
|
|
||||||
"desc": "value값의 키값(VID___)은 이펙트의 속성종류에 따라 변경되므로 채점기준표작성시 확인 필요"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr/@Name",
|
|
||||||
"search": "청량하고 시원한 폭포",
|
|
||||||
"type": "video.Text",
|
|
||||||
"value": "청량하고 시원한 폭포",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID102",
|
|
||||||
"search": "청량하고 시원한 폭포",
|
|
||||||
"type": "video.Text",
|
|
||||||
"value": "돋움체",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID101",
|
|
||||||
"search": "청량하고 시원한 폭포",
|
|
||||||
"type": "video.Text",
|
|
||||||
"value": "120",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='4']/@VID100",
|
|
||||||
"search": "청량하고 시원한 폭포",
|
|
||||||
"type": "video.Text.Color",
|
|
||||||
"value": "1db0f1",
|
|
||||||
"point": 2,
|
|
||||||
"desc": "컬러값은 RGB로 입력한다, [대소문자, #]허용 (#FFFFFF, ffffff 두 값 모두 허용)"
|
|
||||||
},
|
|
||||||
"9": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr/@*[name()='VID600' or name()='VID601']",
|
|
||||||
"search": "청량하고 시원한 폭포",
|
|
||||||
"type": "video.Location",
|
|
||||||
"value": [
|
|
||||||
"0.27395833",
|
|
||||||
"0.9222222"
|
|
||||||
],
|
|
||||||
"point": 2,
|
|
||||||
"desc": "정답 파일의 자막 좌표를 기준으로 프로그램 내부적으로 0.1까지 오차를 허용한다"
|
|
||||||
},
|
|
||||||
"10": {
|
|
||||||
"ele": "",
|
|
||||||
"search": "청량하고 시원한 폭포",
|
|
||||||
"type": "video.StartTime",
|
|
||||||
"value": 170,
|
|
||||||
"point": 2,
|
|
||||||
"desc": "내부적으로 자막의 시작시간과 길이를 계산"
|
|
||||||
},
|
|
||||||
"11": {
|
|
||||||
"ele": "",
|
|
||||||
"search": "청량하고 시원한 폭포",
|
|
||||||
"type": "video.Length",
|
|
||||||
"value": 150,
|
|
||||||
"point": 2,
|
|
||||||
"desc": "내부적으로 자막의 시작시간과 길이를 계산"
|
|
||||||
},
|
|
||||||
"12": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Mute",
|
|
||||||
"type": "Mute",
|
|
||||||
"media": "동영상.mp4",
|
|
||||||
"value": "1",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"13": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
|
||||||
"type": "imageLength",
|
|
||||||
"media": "이미지2.jpg",
|
|
||||||
"value": "150",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"14": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
|
||||||
"type": "imageOverlay",
|
|
||||||
"media": "이미지2.jpg",
|
|
||||||
"value": {
|
|
||||||
"ID": "103",
|
|
||||||
"VID102": "7"
|
|
||||||
},
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"15": {
|
|
||||||
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
|
||||||
"type": "clipTransition",
|
|
||||||
"media": "이미지2.jpg",
|
|
||||||
"value": {
|
|
||||||
"ID": "11",
|
|
||||||
"Range": "500:530",
|
|
||||||
"Type": "2"
|
|
||||||
},
|
|
||||||
"point": 2,
|
|
||||||
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
|
||||||
},
|
|
||||||
"16": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
|
||||||
"type": "imageLength",
|
|
||||||
"media": "이미지3.jpg",
|
|
||||||
"value": "150",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"17": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
|
||||||
"type": "imageOverlay",
|
|
||||||
"media": "이미지3.jpg",
|
|
||||||
"value": {
|
|
||||||
"ID": "184",
|
|
||||||
"VID102": "30"
|
|
||||||
},
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"18": {
|
|
||||||
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
|
||||||
"type": "clipTransition",
|
|
||||||
"media": "이미지3.jpg",
|
|
||||||
"value": {
|
|
||||||
"ID": "19",
|
|
||||||
"Range": "650:680",
|
|
||||||
"Type": "2"
|
|
||||||
},
|
|
||||||
"point": 2,
|
|
||||||
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
|
||||||
},
|
|
||||||
"19": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
|
||||||
"type": "imageLength",
|
|
||||||
"media": "이미지1.jpg",
|
|
||||||
"value": "180",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"20": {
|
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
|
||||||
"type": "imageOverlay",
|
|
||||||
"media": "이미지1.jpg",
|
|
||||||
"value": {
|
|
||||||
"ID": "67",
|
|
||||||
"VID102": "30"
|
|
||||||
},
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"21": {
|
|
||||||
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
|
||||||
"type": "clipTransition",
|
|
||||||
"media": "이미지1.jpg",
|
|
||||||
"value": {
|
|
||||||
"ID": "10",
|
|
||||||
"Range": "800:860",
|
|
||||||
"Type": "2"
|
|
||||||
},
|
|
||||||
"point": 2,
|
|
||||||
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
|
||||||
},
|
|
||||||
"22": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr/@Name",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
|
||||||
"type": "video.Text",
|
|
||||||
"value": "전통 공원 (Traditional Park)",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"23": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID102",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
|
||||||
"type": "video.Text",
|
|
||||||
"value": "궁서체",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"24": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID101",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
|
||||||
"type": "video.Text",
|
|
||||||
"value": "140",
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"25": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='4']/@VID100",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
|
||||||
"type": "video.Text.Color",
|
|
||||||
"value": "fd5721",
|
|
||||||
"point": 2,
|
|
||||||
"desc": "컬러값은 RGB로 입력한다, [대소문자, #]허용 (#FFFFFF, ffffff 두 값 모두 허용)"
|
|
||||||
},
|
|
||||||
"26": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='2']",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
|
||||||
"type": "video.Text.Outline",
|
|
||||||
"value": {
|
|
||||||
"width": "30",
|
|
||||||
"color": "fff9c4"
|
|
||||||
},
|
|
||||||
"point": 2,
|
|
||||||
"desc": "두께는 XML에서는 소수점으로 표기되지만, 프로그램 내부적으로 변환하여 사용하므로 현재 파일에서는 정수로 작성"
|
|
||||||
},
|
|
||||||
"27": {
|
|
||||||
"ele": "//CROwneUnit[{index}]/CRCUnitArr",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
|
||||||
"type": "opening.Text.FadeInEffect",
|
|
||||||
"value": {
|
|
||||||
"ID": "4",
|
|
||||||
"PlayTime": "2"
|
|
||||||
},
|
|
||||||
"point": 3,
|
|
||||||
"desc": "오프닝자막의 나타나기 효과를 확인하는 문항. id속성은 VID505, playtime속성은 VID507으로 XML 내부에 표기되어 있다."
|
|
||||||
},
|
|
||||||
"28": {
|
|
||||||
"ele": "",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
|
||||||
"type": "opening.StartTime",
|
|
||||||
"value": 0,
|
|
||||||
"point": 2,
|
|
||||||
"desc": "오프닝자막의 시작시간 value 속성만 수정"
|
|
||||||
},
|
|
||||||
"29": {
|
|
||||||
"ele": "",
|
|
||||||
"search": "전통 공원 (Traditional Park)",
|
|
||||||
"type": "opening.Length",
|
|
||||||
"value": 120,
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"30": {
|
|
||||||
"ele": "",
|
|
||||||
"type": "audio.StartTime",
|
|
||||||
"media": "음악.mp3",
|
|
||||||
"value": 0,
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"31": {
|
|
||||||
"ele": "//CRTrackList[@Name='오디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']",
|
|
||||||
"type": "audio.EndTime",
|
|
||||||
"media": "음악.mp3",
|
|
||||||
"value": 810,
|
|
||||||
"point": 2
|
|
||||||
},
|
|
||||||
"32": {
|
|
||||||
"ele": "//CRTrackList[@Name='오디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
|
||||||
"type": "audio.Effect",
|
|
||||||
"media": "음악.mp3",
|
|
||||||
"value": {
|
|
||||||
"ID": "1",
|
|
||||||
"PlayTime": "90"
|
|
||||||
},
|
|
||||||
"point": 2,
|
|
||||||
"desc": "ID속성-페이드인:0 / 페이드아웃:1"
|
|
||||||
},
|
|
||||||
"33": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0,
|
|
||||||
"desc": "파일명 확인"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"1": {
|
|
||||||
"type": "multi",
|
|
||||||
"ele": "//Document/Width/@value | //Document/Height/@value",
|
|
||||||
"value": [
|
|
||||||
"650",
|
|
||||||
"350"
|
|
||||||
],
|
|
||||||
"point": 5,
|
|
||||||
"desc": "캔버스 사이즈 650*350"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 5,
|
|
||||||
"desc": "자유 변형 문항은 채점 불가"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"type": "isExist",
|
|
||||||
"ele": "//Layer/Name/@value",
|
|
||||||
"value": "Flower",
|
|
||||||
"point": 5,
|
|
||||||
"desc": "Flower 레이어가 있는지 여부 체크"
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"type": "multiValue",
|
|
||||||
"ele": "//Layer[Name[@value='{layer}']]/Effects/Item[EffectData/{option}]/Name/@value | //Layer[Name[@value='{layer}']]/Effects/Item/EffectData/{option}/@value",
|
|
||||||
"layer": "Flower",
|
|
||||||
"option": "VibranceValue",
|
|
||||||
"value": [
|
|
||||||
"39",
|
|
||||||
"생동감"
|
|
||||||
],
|
|
||||||
"point": 5,
|
|
||||||
"desc": "Flower 레이어의 효과 체크"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 6,
|
|
||||||
"desc": "올가미 도구/이미지 문항은 채점 불가"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer/Effects/Item/Name/@value",
|
|
||||||
"value": "세피아",
|
|
||||||
"point": 6,
|
|
||||||
"desc": "세피아 효과가 있는지 여부 체크"
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"type": "exact",
|
|
||||||
"ele": "//Layer/Shapes/Shape/shape_type/@value",
|
|
||||||
"value": "ELLIPSE",
|
|
||||||
"point": 3,
|
|
||||||
"desc": "레이어 쉐이프 타입이 타원인지 체크"
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"type": "size",
|
|
||||||
"ele": "//Layer//op_points",
|
|
||||||
"value": {
|
|
||||||
"width": 120,
|
|
||||||
"height": 120
|
|
||||||
},
|
|
||||||
"point": 3,
|
|
||||||
"desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점"
|
|
||||||
},
|
|
||||||
"9": {
|
|
||||||
"type": "color",
|
|
||||||
"ele": "//Layer//Shape[contains(draw_type/@value, 'Interior')]/secondary_color/@value",
|
|
||||||
"value": "7097bb",
|
|
||||||
"point": 6,
|
|
||||||
"desc": "색상 코드 비교 시 소문자로 입력할 것"
|
|
||||||
},
|
|
||||||
"10": {
|
|
||||||
"type": "multiValue",
|
|
||||||
"ele": "//Layer/BlendOp/@value | //Layer/Opacity/@value",
|
|
||||||
"value": [
|
|
||||||
"반사",
|
|
||||||
"80"
|
|
||||||
],
|
|
||||||
"point": 6,
|
|
||||||
"desc": "혼합모드(색 회피율, 불투명도 : 80)"
|
|
||||||
},
|
|
||||||
"11": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0,
|
|
||||||
"desc": "기본설정"
|
|
||||||
},
|
|
||||||
"12": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0,
|
|
||||||
"desc": "파일명 확인"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"1": {
|
|
||||||
"type": "multi",
|
|
||||||
"ele": "//Document/Width/@value | //Document/Height/@value",
|
|
||||||
"value": [
|
|
||||||
"650",
|
|
||||||
"450"
|
|
||||||
],
|
|
||||||
"point": 5,
|
|
||||||
"desc": "캔버스 사이즈 650*450"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 5,
|
|
||||||
"desc": "배경색 문항은 채점 불가"
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer/MaskOpType/@value",
|
|
||||||
"value": "Layering",
|
|
||||||
"point": 6
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 6,
|
|
||||||
"desc": "가로방향 흐릿하게 문항은 채점 불가"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer//shape_type/@value",
|
|
||||||
"value": "ROUNDED_RECTANGLE",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"type": "size",
|
|
||||||
"ele": "//Layer//op_points",
|
|
||||||
"value": {
|
|
||||||
"width": 400,
|
|
||||||
"height": 60
|
|
||||||
},
|
|
||||||
"point": 3,
|
|
||||||
"desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점"
|
|
||||||
},
|
|
||||||
"7": {
|
|
||||||
"type": "gradient",
|
|
||||||
"ele": "//Layer/Shapes/Shape",
|
|
||||||
"startColor": "gradient_start_color/@value",
|
|
||||||
"endColor": "gradient_end_color/@value",
|
|
||||||
"value": {
|
|
||||||
"startColor": "ffe000",
|
|
||||||
"endColor": "34a159"
|
|
||||||
},
|
|
||||||
"point": 6
|
|
||||||
},
|
|
||||||
"8": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer//Shape[shape_type/@value='TEXT']/lines/Item/@value",
|
|
||||||
"value": "흰 꽃 사이 노란 꽃",
|
|
||||||
"point": 5
|
|
||||||
},
|
|
||||||
"9": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Name/@value",
|
|
||||||
"value": "맑은 고딕",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"10": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/{style}/@value",
|
|
||||||
"style": "Italic",
|
|
||||||
"value": "True",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"11": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Size/@value",
|
|
||||||
"value": "30",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"12": {
|
|
||||||
"type": "color",
|
|
||||||
"ele": "//Layer//Shape[shape_type/@value='TEXT'][contains(draw_type/@value, 'Interior')]/secondary_color/@value",
|
|
||||||
"value": "b46ef8",
|
|
||||||
"point": 3,
|
|
||||||
"desc": "색상 코드 비교 시 소문자로 입력할 것"
|
|
||||||
},
|
|
||||||
"13": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer//Shape[shape_type/@value='TEXT']/outline_peninfo/Width/@value",
|
|
||||||
"value": "7",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"14": {
|
|
||||||
"type": "color",
|
|
||||||
"ele": "//Layer//Shape[shape_type/@value='TEXT'][contains(draw_type/@value, 'Outline')]/primary_color/@value",
|
|
||||||
"value": "ffffff",
|
|
||||||
"point": 3,
|
|
||||||
"desc": "색상 코드 비교 시 소문자로 입력할 것"
|
|
||||||
},
|
|
||||||
"15": {
|
|
||||||
"ele": "//Layer[MaskOpType/@value='Clipping'][last()]",
|
|
||||||
"point": 6,
|
|
||||||
"desc": "클리핑 마스크 항목은 별도 레이어로 추가되고 해당 속성을 추가해놓은 레이어가 있는지 여부 체크 함"
|
|
||||||
},
|
|
||||||
"16": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer/Shapes/Shape/shape_type/@value",
|
|
||||||
"value": "RECTANGLE",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"17": {
|
|
||||||
"type": "size",
|
|
||||||
"ele": "//Layer//op_points",
|
|
||||||
"value": {
|
|
||||||
"width": 150,
|
|
||||||
"height": 150
|
|
||||||
},
|
|
||||||
"point": 3,
|
|
||||||
"desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점"
|
|
||||||
},
|
|
||||||
"18": {
|
|
||||||
"type": "exists",
|
|
||||||
"ele": "//Layer//outline_peninfo/Width/@value",
|
|
||||||
"value": "7",
|
|
||||||
"point": 3
|
|
||||||
},
|
|
||||||
"19": {
|
|
||||||
"type": "color",
|
|
||||||
"ele": "//Layer//Shape[contains(draw_type/@value, 'Outline')]/primary_color/@value",
|
|
||||||
"value": "e8e88e",
|
|
||||||
"point": 3,
|
|
||||||
"desc": "색상 코드 비교 시 소문자로 입력할 것(채우기:secondary_color, 외곽선:primary_color)"
|
|
||||||
},
|
|
||||||
"20": {
|
|
||||||
"type": "shadow",
|
|
||||||
"ele": {
|
|
||||||
"shadow": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]",
|
|
||||||
"width": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_width/@value",
|
|
||||||
"distance": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_distance/@value",
|
|
||||||
"blur": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_blur/@value",
|
|
||||||
"angle": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_angle/@value"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"width": "3",
|
|
||||||
"distance": "5",
|
|
||||||
"blur": "1",
|
|
||||||
"angle": "320"
|
|
||||||
},
|
|
||||||
"point": 5,
|
|
||||||
"desc": "그림자 속성이 있는 경우 그림자 속성의 너비, 거리, 흐림 정도, 각도를 비교하여 정답 채점"
|
|
||||||
},
|
|
||||||
"21": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0,
|
|
||||||
"desc": "기본설정"
|
|
||||||
},
|
|
||||||
"22": {
|
|
||||||
"ele": "none",
|
|
||||||
"point": 0,
|
|
||||||
"desc": "파일명 확인"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -501,7 +501,7 @@
|
|||||||
"layer": "Flower",
|
"layer": "Flower",
|
||||||
"option": "VibranceValue",
|
"option": "VibranceValue",
|
||||||
"value": [
|
"value": [
|
||||||
"39",
|
"40",
|
||||||
"생동감"
|
"생동감"
|
||||||
],
|
],
|
||||||
"point": 5,
|
"point": 5,
|
||||||
|
|||||||
737
DIC_곰픽채점기준표.json
Normal file
737
DIC_곰픽채점기준표.json
Normal file
@@ -0,0 +1,737 @@
|
|||||||
|
{
|
||||||
|
"0": {
|
||||||
|
"1": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"ele": "$[?(@.width == 65 && @.height == 45)]",
|
||||||
|
"type": "size",
|
||||||
|
"value": {
|
||||||
|
"width": 65,
|
||||||
|
"height": 45
|
||||||
|
},
|
||||||
|
"point": 4
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0,
|
||||||
|
"desc": "파일명 확인"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"1": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"ele": "$.children[?(@.name=='꽃잎들')].name",
|
||||||
|
"value": "꽃잎들",
|
||||||
|
"point": 4
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"ele": "$.children[?(@.name=='Flower Rock')].name",
|
||||||
|
"value": "Flower Rock",
|
||||||
|
"point": 4
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"ele": "$.children[?(@.name=='Flower Rock')].text.font.names[0]",
|
||||||
|
"type": "font",
|
||||||
|
"value": "Arial",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"ele": "$.children[?(@.name=='Flower Rock')].text.font.names[0]",
|
||||||
|
"value": "Arial-BoldItalicMT",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"ele": "$.children[?(@.name=='Flower Rock')].text.font.sizes[0]",
|
||||||
|
"value": 48,
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"ele": "$.children[?(@.name=='Flower Rock')].text.font.colors[0]",
|
||||||
|
"type": "color",
|
||||||
|
"value": "d6f592",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"12": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"13": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"14": {
|
||||||
|
"ele": "$.children[?(@.name=='꽃과 바위')].name",
|
||||||
|
"value": "꽃과 바위",
|
||||||
|
"point": 4
|
||||||
|
},
|
||||||
|
"15": {
|
||||||
|
"ele": "$.children[?(@.name=='꽃과 바위')].text.font.names[0]",
|
||||||
|
"type": "font",
|
||||||
|
"value": "GungsuhChe",
|
||||||
|
"point": 2,
|
||||||
|
"desc": {
|
||||||
|
"돋움체": "DotumChe",
|
||||||
|
"궁서체": "GungsuhChe",
|
||||||
|
"굴림체": "GulimChe",
|
||||||
|
"휴먼옛체": "YetR"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"16": {
|
||||||
|
"ele": "$.children[?(@.name=='꽃과 바위')].text.font.sizes[0]",
|
||||||
|
"value": 36,
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"17": {
|
||||||
|
"ele": "$.children[?(@.name=='꽃과 바위')].text.font.colors[0]",
|
||||||
|
"type": "color",
|
||||||
|
"value": "0d17d5",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"18": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"19": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"20": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"21": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"22": {
|
||||||
|
"ele": "$.children[?(@.name=='노랑꽃')].name",
|
||||||
|
"value": "노랑꽃",
|
||||||
|
"point": 4
|
||||||
|
},
|
||||||
|
"23": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"24": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"25": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0
|
||||||
|
},
|
||||||
|
"26": {
|
||||||
|
"ele": "$[?(@.width == 65 && @.height == 35)]",
|
||||||
|
"type": "size",
|
||||||
|
"value": {
|
||||||
|
"width": 65,
|
||||||
|
"height": 35
|
||||||
|
},
|
||||||
|
"point": 5
|
||||||
|
},
|
||||||
|
"27": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0,
|
||||||
|
"desc": "파일명 확인"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"1": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[not(@Length<='5' and @ClipLength='-1')]/@ClipIndex",
|
||||||
|
"type": "mediaOrder",
|
||||||
|
"value": ["동영상.mp4", "이미지3.jpg", "이미지1.jpg", "이미지2.jpg"],
|
||||||
|
"point": 4,
|
||||||
|
"desc": "비디오1 트랙에 있는 클립의 ClipIndex값을 기준으로 CRClipArr에서 Path값을 가져와서 정답 채점, 클립의 ClipIndex값이 -1인 경우와 길이가 5프레임 이하인 경우는 제외한다."
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"ele": "/CROASTERP/CRTrackArr[1]/CRVideoTrackArr[1]/CRTrackList[1]/CRTrackClip[1]/@Speed",
|
||||||
|
"type": "oneAnswer",
|
||||||
|
"value": {
|
||||||
|
"speed": "140"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "100당 1배속 / 130 = 1.3배속"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']",
|
||||||
|
"type": "startEnd",
|
||||||
|
"media": "동영상.mp4",
|
||||||
|
"value": {
|
||||||
|
"start": "0",
|
||||||
|
"end": "370"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "시작시간과 재생시간 정답값 입력, 3번문항은 '동영상.mp4' 클립의 길이를 확인하는 문항이므로 media는 수정할 필요가 없다."
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
|
"type": "effect",
|
||||||
|
"media": "동영상.mp4",
|
||||||
|
"value": {
|
||||||
|
"ID": "44",
|
||||||
|
"VID100": "8",
|
||||||
|
"VID103": "0.89999998"
|
||||||
|
},
|
||||||
|
"point": 3,
|
||||||
|
"desc": "value값의 키값(VID___)은 이펙트의 속성종류에 따라 변경되므로 채점기준표작성시 확인 필요"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr/@Name",
|
||||||
|
"search": "화단의 꽃들",
|
||||||
|
"type": "video.Text",
|
||||||
|
"value": "화단의 꽃들",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID102",
|
||||||
|
"search": "화단의 꽃들",
|
||||||
|
"type": "video.Text",
|
||||||
|
"value": "돋움체",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID101",
|
||||||
|
"search": "화단의 꽃들",
|
||||||
|
"type": "video.Text",
|
||||||
|
"value": "110",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='4']/@VID100",
|
||||||
|
"search": "화단의 꽃들",
|
||||||
|
"type": "video.Text.Color",
|
||||||
|
"value": "ff531b",
|
||||||
|
"point": 2,
|
||||||
|
"desc": "컬러값은 RGB로 입력한다, [대소문자, #]허용 (#FFFFFF, ffffff 두 값 모두 허용)"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr/@*[name()='VID600' or name()='VID601']",
|
||||||
|
"search": "화단의 꽃들",
|
||||||
|
"type": "video.Location",
|
||||||
|
"value": ["0.38333333", "0.92962962"],
|
||||||
|
"point": 2,
|
||||||
|
"desc": "정답 파일의 자막 좌표를 기준으로 프로그램 내부적으로 0.1까지 오차를 허용한다"
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"ele": "",
|
||||||
|
"search": "화단의 꽃들",
|
||||||
|
"type": "video.StartTime",
|
||||||
|
"value": 170,
|
||||||
|
"point": 2,
|
||||||
|
"desc": "내부적으로 자막의 시작시간과 길이를 계산"
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"ele": "",
|
||||||
|
"search": "화단의 꽃들",
|
||||||
|
"type": "video.Length",
|
||||||
|
"value": 150,
|
||||||
|
"point": 2,
|
||||||
|
"desc": "내부적으로 자막의 시작시간과 길이를 계산"
|
||||||
|
},
|
||||||
|
"12": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Mute",
|
||||||
|
"type": "Mute",
|
||||||
|
"media": "동영상.mp4",
|
||||||
|
"value": "1",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"13": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
||||||
|
"type": "imageLength",
|
||||||
|
"media": "이미지3.jpg",
|
||||||
|
"value": "180",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"14": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
|
"type": "imageOverlay",
|
||||||
|
"media": "이미지3.jpg",
|
||||||
|
"value": {
|
||||||
|
"ID": "67",
|
||||||
|
"VID102": "40"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "오버레이 속성 키값(VID10X) 확인하고 변경"
|
||||||
|
},
|
||||||
|
"15": {
|
||||||
|
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
||||||
|
"type": "clipTransition",
|
||||||
|
"media": "이미지3.jpg",
|
||||||
|
"value": {
|
||||||
|
"ID": "10",
|
||||||
|
"Range": "490:550",
|
||||||
|
"Type": "2"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
||||||
|
},
|
||||||
|
"16": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
||||||
|
"type": "imageLength",
|
||||||
|
"media": "이미지1.jpg",
|
||||||
|
"value": "180",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"17": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
|
"type": "imageOverlay",
|
||||||
|
"media": "이미지1.jpg",
|
||||||
|
"value": {
|
||||||
|
"ID": "103",
|
||||||
|
"VID102": "7"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "오버레이 속성 키값(VID10X) 확인하고 변경"
|
||||||
|
},
|
||||||
|
"18": {
|
||||||
|
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
||||||
|
"type": "clipTransition",
|
||||||
|
"media": "이미지1.jpg",
|
||||||
|
"value": {
|
||||||
|
"ID": "12",
|
||||||
|
"Range": "670:730",
|
||||||
|
"Type": "2"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
||||||
|
},
|
||||||
|
"19": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
||||||
|
"type": "imageLength",
|
||||||
|
"media": "이미지2.jpg",
|
||||||
|
"value": "150",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"20": {
|
||||||
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
|
"type": "imageOverlay",
|
||||||
|
"media": "이미지2.jpg",
|
||||||
|
"value": {
|
||||||
|
"ID": "102",
|
||||||
|
"VID101": "3"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "오버레이 속성 키값(VID10X) 확인하고 변경"
|
||||||
|
},
|
||||||
|
"21": {
|
||||||
|
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
||||||
|
"type": "clipTransition",
|
||||||
|
"media": "이미지2.jpg",
|
||||||
|
"value": {
|
||||||
|
"ID": "0",
|
||||||
|
"Range": "850:880",
|
||||||
|
"Type": "2"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
||||||
|
},
|
||||||
|
"22": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr/@Name",
|
||||||
|
"search": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"type": "video.Text",
|
||||||
|
"value": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"23": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID102",
|
||||||
|
"search": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"type": "video.Text",
|
||||||
|
"value": "궁서체",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"24": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool[@Type='1']/GCUnit/@VID101",
|
||||||
|
"search": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"type": "video.Text",
|
||||||
|
"value": "140",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"25": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='4']/@VID100",
|
||||||
|
"search": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"type": "video.Text.Color",
|
||||||
|
"value": "ec008c",
|
||||||
|
"point": 2,
|
||||||
|
"desc": "컬러값은 RGB로 입력한다, [대소문자, #]허용 (#FFFFFF, ffffff 두 값 모두 허용)"
|
||||||
|
},
|
||||||
|
"26": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr//GCUnitPool/GCUnit[@Type='2']",
|
||||||
|
"search": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"type": "video.Text.Outline",
|
||||||
|
"value": {
|
||||||
|
"width": "40",
|
||||||
|
"color": "fff9c4"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "두께는 XML에서는 소수점으로 표기되지만, 프로그램 내부적으로 변환하여 사용하므로 현재 파일에서는 정수로 작성"
|
||||||
|
},
|
||||||
|
"27": {
|
||||||
|
"ele": "//CROwneUnit[{index}]/CRCUnitArr",
|
||||||
|
"search": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"type": "opening.Text.FadeInEffect",
|
||||||
|
"value": {
|
||||||
|
"ID": "14",
|
||||||
|
"PlayTime": "2"
|
||||||
|
},
|
||||||
|
"point": 3,
|
||||||
|
"desc": "오프닝자막의 나타나기 효과를 확인하는 문항. id속성은 VID505, playtime속성은 VID507으로 XML 내부에 표기되어 있다."
|
||||||
|
},
|
||||||
|
"28": {
|
||||||
|
"ele": "",
|
||||||
|
"search": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"type": "opening.StartTime",
|
||||||
|
"value": 0,
|
||||||
|
"point": 2,
|
||||||
|
"desc": "오프닝자막의 시작시간 value 속성만 수정"
|
||||||
|
},
|
||||||
|
"29": {
|
||||||
|
"ele": "",
|
||||||
|
"search": "아름다운 꽃 축제 (Happy Flower Festival)",
|
||||||
|
"type": "opening.Length",
|
||||||
|
"value": 120,
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"30": {
|
||||||
|
"ele": "",
|
||||||
|
"type": "audio.StartTime",
|
||||||
|
"media": "음악.mp3",
|
||||||
|
"value": 0,
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"31": {
|
||||||
|
"ele": "//CRTrackList[@Name='오디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']",
|
||||||
|
"type": "audio.EndTime",
|
||||||
|
"media": "음악.mp3",
|
||||||
|
"value": "870",
|
||||||
|
"point": 2
|
||||||
|
},
|
||||||
|
"32": {
|
||||||
|
"ele": "//CRTrackList[@Name='오디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
|
"type": "audio.Effect",
|
||||||
|
"media": "음악.mp3",
|
||||||
|
"value": {
|
||||||
|
"ID": "1",
|
||||||
|
"PlayTime": "60"
|
||||||
|
},
|
||||||
|
"point": 2,
|
||||||
|
"desc": "ID속성-페이드인:0 / 페이드아웃: 1"
|
||||||
|
},
|
||||||
|
"33": {
|
||||||
|
"ele": "none",
|
||||||
|
"point": 0,
|
||||||
|
"desc": "파일명 확인"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"1": {
|
||||||
|
"type": "canvas.Size",
|
||||||
|
"ele": "//Document/Width/@value | //Document/Height/@value",
|
||||||
|
"value": ["650", "350"],
|
||||||
|
"point": 5,
|
||||||
|
"desc": "캔버스 사이즈 650*350"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"type": "none",
|
||||||
|
"ele": "",
|
||||||
|
"point": 5,
|
||||||
|
"desc": "자유 변형 문항은 채점 불가"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"type": "layer.exists",
|
||||||
|
"ele": "//Layer/Name/@value",
|
||||||
|
"value": "Flower",
|
||||||
|
"point": 5,
|
||||||
|
"desc": "Flower 레이어가 있는지 여부 체크"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"type": "layer.Effects",
|
||||||
|
"ele": "//Layer[Name[@value='{search}']]/Effects/Item",
|
||||||
|
"search": "Flower",
|
||||||
|
"value": {
|
||||||
|
"name": "생동감",
|
||||||
|
"option": {
|
||||||
|
"생동감": "40"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"point": 5,
|
||||||
|
"desc": {
|
||||||
|
"흑백": "강도",
|
||||||
|
"밝기/대비": ["밝기", "대비"],
|
||||||
|
"노출": "노출",
|
||||||
|
"색조/채도": ["색조", "채도", "명도"],
|
||||||
|
"감마":["리프트","감마","게인"],
|
||||||
|
"세피아":["U","V"],
|
||||||
|
"생동감": "생동감"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"type": "none",
|
||||||
|
"ele": "",
|
||||||
|
"point": 6,
|
||||||
|
"desc": "올가미 도구/이미지 문항은 채점 불가"
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer/Effects/Item/Name/@value",
|
||||||
|
"value": "세피아",
|
||||||
|
"point": 6,
|
||||||
|
"desc": "세피아 효과가 있는지 여부 체크"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer/Shapes/Shape/shape_type/@value",
|
||||||
|
"value": "ELLIPSE",
|
||||||
|
"point": 3,
|
||||||
|
"desc": "레이어 쉐이프 타입이 타원인지 체크"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"type": "shape.size",
|
||||||
|
"ele": "//Layer//op_points",
|
||||||
|
"value": {
|
||||||
|
"width": 120,
|
||||||
|
"height": 120
|
||||||
|
},
|
||||||
|
"point": 3,
|
||||||
|
"desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점"
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"type": "shape.color",
|
||||||
|
"ele": "//Layer//Shape[contains(draw_type/@value, 'Interior')]/secondary_color/@value",
|
||||||
|
"value": "7097BB",
|
||||||
|
"point": 6,
|
||||||
|
"desc": ""
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"type": "layer.blend.opacity",
|
||||||
|
"ele": "//Layer",
|
||||||
|
"value": {
|
||||||
|
"BlendOp": "반사",
|
||||||
|
"Opacity": "80"
|
||||||
|
},
|
||||||
|
"point": 6
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"type": "none",
|
||||||
|
"ele": "",
|
||||||
|
"point": 0,
|
||||||
|
"desc": "기본설정"
|
||||||
|
},
|
||||||
|
"12": {
|
||||||
|
"type": "none",
|
||||||
|
"ele": "",
|
||||||
|
"point": 0,
|
||||||
|
"desc": "파일명 확인"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"1": {
|
||||||
|
"type": "canvas.Size",
|
||||||
|
"ele": "//Document/Width/@value | //Document/Height/@value",
|
||||||
|
"value": ["650", "450"],
|
||||||
|
"point": 5,
|
||||||
|
"desc": "캔버스 사이즈 650*450"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"type": "none",
|
||||||
|
"ele": "",
|
||||||
|
"point": 5,
|
||||||
|
"desc": "배경색 문항은 채점 불가"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer/MaskOpType/@value",
|
||||||
|
"value": "Layering",
|
||||||
|
"point": 6,
|
||||||
|
"desc": "레이어 마스크 설정 확인"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"type": "none",
|
||||||
|
"ele": "",
|
||||||
|
"point": 6,
|
||||||
|
"desc": "가로방향 흐릿하게 문항은 채점 불가"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer//shape_type/@value",
|
||||||
|
"value": "ROUNDED_RECTANGLE",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"type": "shape.size",
|
||||||
|
"ele": "//Layer//op_points",
|
||||||
|
"value": {
|
||||||
|
"width": 400,
|
||||||
|
"height": 60
|
||||||
|
},
|
||||||
|
"point": 3,
|
||||||
|
"desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"type": "gradient.color",
|
||||||
|
"ele": "//Layer/Shapes/Shape",
|
||||||
|
"startColor": "gradient_start_color/@value",
|
||||||
|
"endColor": "gradient_end_color/@value",
|
||||||
|
"value": {
|
||||||
|
"startColor": "ffe000",
|
||||||
|
"endColor": "34A159"
|
||||||
|
},
|
||||||
|
"point": 6
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"type": "text.exists",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='TEXT']/lines/Item/@value",
|
||||||
|
"value": "흰 꽃 사이 노란 꽃",
|
||||||
|
"point": 5
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Name/@value",
|
||||||
|
"value": "맑은 고딕",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/{style}/@value",
|
||||||
|
"style": "Italic",
|
||||||
|
"value": "True",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Size/@value",
|
||||||
|
"value": "30",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"12": {
|
||||||
|
"type": "text.color",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='TEXT'][contains(draw_type/@value, 'Interior')]/secondary_color/@value",
|
||||||
|
"value": "b46Ef8",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"13": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='TEXT']/outline_peninfo/Width/@value",
|
||||||
|
"value": "7",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"14": {
|
||||||
|
"type": "text.color",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='TEXT'][contains(draw_type/@value, 'Outline')]/primary_color/@value",
|
||||||
|
"value": "ffffff",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"15": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer/MaskOpType/@value",
|
||||||
|
"value": "Clipping",
|
||||||
|
"point": 6,
|
||||||
|
"desc": "클리핑 마스크 항목은 별도 레이어로 추가되고 해당 속성을 추가해놓은 레이어가 있는지 여부 체크 함"
|
||||||
|
},
|
||||||
|
"16": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer/Shapes/Shape/shape_type/@value",
|
||||||
|
"value": "RECTANGLE",
|
||||||
|
"point": 3,
|
||||||
|
"desc": {
|
||||||
|
"사각형": "RECTANGLE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"17": {
|
||||||
|
"type": "clipping.size",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='{option}']//op_points",
|
||||||
|
"option": "RECTANGLE",
|
||||||
|
"value": {
|
||||||
|
"width": 150,
|
||||||
|
"height": 150
|
||||||
|
},
|
||||||
|
"point": 3,
|
||||||
|
"desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점"
|
||||||
|
},
|
||||||
|
"18": {
|
||||||
|
"type": "exists",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='{option}']/outline_peninfo/Width/@value",
|
||||||
|
"option": "RECTANGLE",
|
||||||
|
"value": "7",
|
||||||
|
"point": 3
|
||||||
|
},
|
||||||
|
"19": {
|
||||||
|
"type": "clipping.color",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='{option}' and contains(draw_type/@value, 'Outline')]/primary_color/@value",
|
||||||
|
"option": "RECTANGLE",
|
||||||
|
"value": "e8e88e",
|
||||||
|
"point": 3,
|
||||||
|
"desc": "채우기:secondary_color, 외곽선:primary_color"
|
||||||
|
},
|
||||||
|
"20": {
|
||||||
|
"type": "shadow",
|
||||||
|
"ele": "//Layer//Shape[shape_type/@value='{option}']",
|
||||||
|
"option": "RECTANGLE",
|
||||||
|
"value": {
|
||||||
|
"shadow": true,
|
||||||
|
"width": "3",
|
||||||
|
"distance": "5",
|
||||||
|
"blur": "1",
|
||||||
|
"angle": "320"
|
||||||
|
},
|
||||||
|
"point": 5,
|
||||||
|
"desc": "그림자 속성이 있는 경우 그림자 속성의 너비, 거리, 흐림 정도, 각도를 비교하여 정답 채점"
|
||||||
|
},
|
||||||
|
"21": {
|
||||||
|
"type": "none",
|
||||||
|
"ele": "",
|
||||||
|
"point": 0,
|
||||||
|
"desc": "기본설정"
|
||||||
|
},
|
||||||
|
"22": {
|
||||||
|
"type": "none",
|
||||||
|
"ele": "",
|
||||||
|
"point": 0,
|
||||||
|
"desc": "파일명 확인"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
923
gpdpScoring.js
923
gpdpScoring.js
@@ -192,29 +192,157 @@ function getGpdpScore(gpdpData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// []
|
// []
|
||||||
else if (type === "layer.Exists") {
|
// else if (type === "layer.exists") {
|
||||||
const layerNameList = xpath.select(ele, gpdpXmlDoc);
|
// const layerNameList = xpath.select(ele, gpdpXmlDoc);
|
||||||
const layerNames = layerNameList.map(layer => layer.value);
|
// const layerNames = layerNameList.map(layer => layer.value);
|
||||||
let isMatched = false
|
// let isMatched = false
|
||||||
|
|
||||||
// for (const layerName of layerNames) {
|
// let result = findSimilarString(gpdpXmlDoc, rightAnswer, 0.8);
|
||||||
// if (layerName.trim().toLowerCase() === rightAnswer.trim().toLowerCase()) {
|
// if (result !== null) {
|
||||||
// userAnswer = layerName;
|
// userAnswer = result;
|
||||||
// isMatched = true;
|
// isMatched = true;
|
||||||
// break;
|
// }
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (isMatched) {
|
// if (isMatched) {
|
||||||
// totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
// totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
||||||
// }
|
// type: 'force-correct'
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
let result = findSimilarString(gpdpXmlDoc, rightAnswer, 0.8);
|
// [1-4] 사진1 > 조정
|
||||||
if (result !== null) {
|
else if (type === "layer.Effects") {
|
||||||
userAnswer = result;
|
const effects = xpath.select(ele, gpdpXmlDoc);
|
||||||
isMatched = true;
|
|
||||||
|
let isMatched = false;
|
||||||
|
for (const item of effects) {
|
||||||
|
const name = xpath.select1('Name/@value', item)?.value;
|
||||||
|
const effectData = xpath.select1(`EffectData`, item);
|
||||||
|
|
||||||
|
// 동일한 이펙트 요소만 검사
|
||||||
|
if (rightAnswer['name'] !== name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
userAnswer = {
|
||||||
|
name: name,
|
||||||
|
option: {},
|
||||||
|
}
|
||||||
|
if (name === '흑백') {
|
||||||
|
const Intensity = xpath.select1('Intensity/@value', effectData)?.value;
|
||||||
|
|
||||||
|
const optionKeys = Object.keys(rightAnswer['option']);
|
||||||
|
if (optionKeys.includes('강도')) userAnswer['option']['강도'] = Intensity;
|
||||||
|
}
|
||||||
|
else if (name === '밝기/대비') {
|
||||||
|
const brightness = xpath.select1('brightness/@value', effectData)?.value;
|
||||||
|
const contrast = xpath.select1('contrast/@value', effectData)?.value;
|
||||||
|
|
||||||
|
const optionKeys = Object.keys(rightAnswer['option']);
|
||||||
|
if (optionKeys.includes('밝기')) userAnswer['option']['밝기'] = brightness;
|
||||||
|
if (optionKeys.includes('대비')) userAnswer['option']['대비'] = contrast;
|
||||||
|
}
|
||||||
|
else if (name === '노출') {
|
||||||
|
const ExposureValue = xpath.select1('ExposureValue/@value', effectData)?.value;
|
||||||
|
|
||||||
|
const optionKeys = Object.keys(rightAnswer['option']);
|
||||||
|
if (optionKeys.includes('노출')) userAnswer['option']['노출'] = ExposureValue;
|
||||||
|
}
|
||||||
|
else if (name === '색조/채도') {
|
||||||
|
const hue = xpath.select1('hue/@value', effectData)?.value;
|
||||||
|
const saturation = xpath.select1('saturation/@value', effectData)?.value;
|
||||||
|
const lightness = xpath.select1('lightness/@value', effectData)?.value;
|
||||||
|
|
||||||
|
const optionKeys = Object.keys(rightAnswer['option']);
|
||||||
|
if (optionKeys.includes('색조')) userAnswer['option']['색조'] = hue;
|
||||||
|
if (optionKeys.includes('채도')) userAnswer['option']['채도'] = saturation;
|
||||||
|
if (optionKeys.includes('명도')) userAnswer['option']['명도'] = lightness;
|
||||||
|
}
|
||||||
|
else if (name === '감마') {
|
||||||
|
const lift = xpath.select1('Lift/@value', effectData)?.value;
|
||||||
|
const gamma = xpath.select1('Gamma/@value', effectData)?.value;
|
||||||
|
const gain = xpath.select1('Gain/@value', effectData)?.value;
|
||||||
|
|
||||||
|
const optionKeys = Object.keys(rightAnswer['option']);
|
||||||
|
if (optionKeys.includes('리프트')) userAnswer['option']['리프트'] = lift;
|
||||||
|
if (optionKeys.includes('감마')) userAnswer['option']['감마'] = gamma;
|
||||||
|
if (optionKeys.includes('게인')) userAnswer['option']['게인'] = gain;
|
||||||
|
}
|
||||||
|
else if (name === '세피아') {
|
||||||
|
const u = xpath.select1('U/@value', effectData)?.value;
|
||||||
|
const v = xpath.select1('V/@value', effectData)?.value;
|
||||||
|
|
||||||
|
const optionKeys = Object.keys(rightAnswer['option']).map(key => key.toUpperCase());
|
||||||
|
if (optionKeys.includes('U')) userAnswer['option']['U'] = u;
|
||||||
|
if (optionKeys.includes('V')) userAnswer['option']['V'] = v;
|
||||||
|
}
|
||||||
|
else if (name === '생동감') {
|
||||||
|
const vibranceValue = xpath.select1('VibranceValue/@value', effectData)?.value;
|
||||||
|
// 생동감 옵션값이 프로그램에서 적용한 값에 오차가 발생하는 경우가 있음
|
||||||
|
// 곰픽>XML / 30>29 / 40>39
|
||||||
|
// 설정한 값 그대로 적용되는 경우도 있어서 오차범위 2로 설정
|
||||||
|
const userValue = parseInt(vibranceValue, 10);
|
||||||
|
const rightValue = parseInt(rightAnswer.option['생동감'], 10);
|
||||||
|
|
||||||
|
if (Math.abs(rightValue - userValue) <= 2) {
|
||||||
|
const optionKeys = Object.keys(rightAnswer['option']);
|
||||||
|
if (optionKeys.includes('생동감')) {
|
||||||
|
userAnswer['option']['생동감'] = rightValue.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in rightAnswer.option) {
|
||||||
|
// 속성값이 정답과 다른 경우가 있으면 오답처리
|
||||||
|
if (rightAnswer.option[key] !== userAnswer.option[key]) {
|
||||||
|
isMatched = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isMatched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 속성값이 하나라도 일치하지 않으면 오답
|
||||||
|
if (isMatched === false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// else if (type === "exists") {
|
||||||
|
else if (type.includes("exists")) {
|
||||||
|
const existsValues = xpath.select(ele, gpdpXmlDoc);
|
||||||
|
let isMatched = false;
|
||||||
|
|
||||||
|
for (const v of existsValues) {
|
||||||
|
userAnswer = v.value;
|
||||||
|
|
||||||
|
if (type.includes('layer') || type.includes('text')) {
|
||||||
|
|
||||||
|
// 공백, 대소문자 무시
|
||||||
|
const cleanUserAnswer = userAnswer.replace(/\s+/g, '').toLowerCase();
|
||||||
|
const cleanRightAnswer = rightAnswer.replace(/\s+/g, '').toLowerCase();
|
||||||
|
|
||||||
|
// 하나라도 일치하면 정답
|
||||||
|
if (cleanUserAnswer === cleanRightAnswer) {
|
||||||
|
isMatched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (userAnswer === rightAnswer) {
|
||||||
|
isMatched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (isMatched) {
|
if (isMatched) {
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
||||||
type: 'force-correct'
|
type: 'force-correct'
|
||||||
@@ -223,506 +351,383 @@ function getGpdpScore(gpdpData, scoringJson, index) {
|
|||||||
else {
|
else {
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [1-4] 사진1 > 조정
|
|
||||||
else if (type === "layer.Effects") {
|
|
||||||
const effects = xpath.select(ele, gpdpXmlDoc);
|
|
||||||
|
|
||||||
let isMatched = false;
|
// else if (type === "shape.size") {
|
||||||
for (const item of effects) {
|
else if (type.includes("size")) {
|
||||||
const name = xpath.select1('Name/@value', item)?.value;
|
const items = xpath.select(ele, gpdpXmlDoc);
|
||||||
const effectData = xpath.select1(`EffectData`, item);
|
let isMatched = false;
|
||||||
|
|
||||||
// 동일한 이펙트 요소만 검사
|
// 각 Item 요소별 x,y 좌표 시작점과 끝점의 거리를 계산해 정답과 비교
|
||||||
if (rightAnswer['name'] !== name) {
|
for (const item of items) {
|
||||||
continue;
|
const x1 = Number(xpath.select1('Item[1]/X/@value', item)?.value);
|
||||||
|
const y1 = Number(xpath.select1('Item[1]/Y/@value', item)?.value);
|
||||||
|
|
||||||
|
const x2 = Number(xpath.select1('Item[last()]/X/@value', item)?.value);
|
||||||
|
const y2 = Number(xpath.select1('Item[last()]/Y/@value', item)?.value);
|
||||||
|
|
||||||
|
const width = Math.round(Math.abs(x2 - x1));
|
||||||
|
const height = Math.round(Math.abs(y2 - y1));
|
||||||
|
|
||||||
|
userAnswer = {
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 하나라도 일치하면 정답
|
||||||
|
if (JSON.stringify(userAnswer) == JSON.stringify(rightAnswer)) {
|
||||||
|
isMatched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userAnswer = {
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
name: name,
|
continue;
|
||||||
option: {},
|
}
|
||||||
}
|
|
||||||
if (name === '흑백') {
|
|
||||||
const Intensity = xpath.select1('Intensity/@value', effectData)?.value;
|
|
||||||
|
|
||||||
const optionKeys = Object.keys(rightAnswer['option']);
|
// [1-8]
|
||||||
if (optionKeys.includes('강도')) userAnswer['option']['강도'] = Intensity;
|
else if (type.includes("color")) {
|
||||||
}
|
const items = xpath.select(ele, gpdpXmlDoc);
|
||||||
else if (name === '밝기/대비') {
|
let normalizedAnswer = null;
|
||||||
const brightness = xpath.select1('brightness/@value', effectData)?.value;
|
let isMatched = false;
|
||||||
const contrast = xpath.select1('contrast/@value', effectData)?.value;
|
|
||||||
|
|
||||||
const optionKeys = Object.keys(rightAnswer['option']);
|
for (const item of items) {
|
||||||
if (optionKeys.includes('밝기')) userAnswer['option']['밝기'] = brightness;
|
if (type.includes('gradient')) {
|
||||||
if (optionKeys.includes('대비')) userAnswer['option']['대비'] = contrast;
|
const startColorXpath = scoringData[key].startColor;
|
||||||
}
|
const endColorXpath = scoringData[key].endColor;
|
||||||
else if (name === '노출') {
|
|
||||||
const ExposureValue = xpath.select1('ExposureValue/@value', effectData)?.value;
|
|
||||||
|
|
||||||
const optionKeys = Object.keys(rightAnswer['option']);
|
const startColorRGB = xpath.select1(startColorXpath, item).value;
|
||||||
if (optionKeys.includes('노출')) userAnswer['option']['노출'] = ExposureValue;
|
const endColorRGB = xpath.select1(endColorXpath, item).value;
|
||||||
}
|
|
||||||
else if (name === '색조/채도') {
|
|
||||||
const hue = xpath.select1('hue/@value', effectData)?.value;
|
|
||||||
const saturation = xpath.select1('saturation/@value', effectData)?.value;
|
|
||||||
const lightness = xpath.select1('lightness/@value', effectData)?.value;
|
|
||||||
|
|
||||||
const optionKeys = Object.keys(rightAnswer['option']);
|
const startColor = parseColorToHex(startColorRGB);
|
||||||
if (optionKeys.includes('색조')) userAnswer['option']['색조'] = hue;
|
const endColor = parseColorToHex(endColorRGB);
|
||||||
if (optionKeys.includes('채도')) userAnswer['option']['채도'] = saturation;
|
|
||||||
if (optionKeys.includes('명도')) userAnswer['option']['명도'] = lightness;
|
|
||||||
}
|
|
||||||
else if (name === '감마') {
|
|
||||||
const lift = xpath.select1('Lift/@value', effectData)?.value;
|
|
||||||
const gamma = xpath.select1('Gamma/@value', effectData)?.value;
|
|
||||||
const gain = xpath.select1('Gain/@value', effectData)?.value;
|
|
||||||
|
|
||||||
const optionKeys = Object.keys(rightAnswer['option']);
|
userAnswer = {
|
||||||
if (optionKeys.includes('리프트')) userAnswer['option']['리프트'] = lift;
|
startColor: startColor,
|
||||||
if (optionKeys.includes('감마')) userAnswer['option']['감마'] = gamma;
|
endColor: endColor,
|
||||||
if (optionKeys.includes('게인')) userAnswer['option']['게인'] = gain;
|
}
|
||||||
}
|
|
||||||
else if (name === '세피아') {
|
|
||||||
const u = xpath.select1('U/@value', effectData)?.value;
|
|
||||||
const v = xpath.select1('V/@value', effectData)?.value;
|
|
||||||
|
|
||||||
const optionKeys = Object.keys(rightAnswer['option']).map(key => key.toUpperCase());
|
// JSON파일에서 대문자로 입력된 경우 소문자로 변환
|
||||||
if (optionKeys.includes('U')) userAnswer['option']['U'] = u;
|
normalizedAnswer = {
|
||||||
if (optionKeys.includes('V')) userAnswer['option']['V'] = v;
|
startColor: rightAnswer.startColor.toLowerCase(),
|
||||||
}
|
endColor: rightAnswer.endColor.toLowerCase(),
|
||||||
else if (name === '생동감') {
|
}
|
||||||
const vibranceValue = xpath.select1('VibranceValue/@value', effectData)?.value;
|
|
||||||
// 생동감 옵션값이 프로그램에서 적용한 값에 오차가 발생하는 경우가 있음
|
|
||||||
// 곰픽>XML / 30>29 / 40>39
|
|
||||||
// 설정한 값 그대로 적용되는 경우도 있어서 오차범위 2로 설정
|
|
||||||
const userValue = parseInt(vibranceValue, 10);
|
|
||||||
const rightValue = parseInt(rightAnswer.option['생동감'], 10);
|
|
||||||
|
|
||||||
if (Math.abs(rightValue - userValue) <= 2) {
|
// 하나라도 일치하면 정답
|
||||||
const optionKeys = Object.keys(rightAnswer['option']);
|
if (JSON.stringify(userAnswer) == JSON.stringify(normalizedAnswer)) {
|
||||||
if (optionKeys.includes('생동감')) {
|
isMatched = true;
|
||||||
userAnswer['option']['생동감'] = rightValue.toString();
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// else {
|
||||||
|
else if (type.includes('shape') || type.includes('text') || type.includes('clipping')) {
|
||||||
|
const color = parseColorToHex(item.value);
|
||||||
|
userAnswer = color;
|
||||||
|
normalizedAnswer = rightAnswer.toLowerCase?.();
|
||||||
|
|
||||||
|
// 하나라도 일치하면 정답
|
||||||
|
if (userAnswer === normalizedAnswer) {
|
||||||
|
isMatched = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
totalScore += compareAndScore(userAnswer, normalizedAnswer, point, key, scoringResult);
|
||||||
|
}
|
||||||
|
|
||||||
for (const key in rightAnswer.option) {
|
else if (type === 'layer.blend.opacity') {
|
||||||
// 속성값이 정답과 다른 경우가 있으면 오답처리
|
const layers = xpath.select(ele, gpdpXmlDoc);
|
||||||
if (rightAnswer.option[key] !== userAnswer.option[key]) {
|
let isMatched = false;
|
||||||
isMatched = false;
|
|
||||||
|
for (const layer of layers) {
|
||||||
|
const blendop = xpath.select1('BlendOp/@value', layer).value;
|
||||||
|
const opacity = xpath.select1('Opacity/@value', layer).value;
|
||||||
|
|
||||||
|
userAnswer = {
|
||||||
|
BlendOp: blendop,
|
||||||
|
Opacity: opacity,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 하나라도 일치하면 정답
|
||||||
|
if (JSON.stringify(userAnswer) == JSON.stringify(rightAnswer)) {
|
||||||
|
isMatched = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [5-20]
|
||||||
|
else if (type === 'shadow') {
|
||||||
|
const shapes = xpath.select(ele, gpdpXmlDoc);
|
||||||
|
|
||||||
|
for (const shape of shapes) {
|
||||||
|
// 그림자 설정 여부
|
||||||
|
const shadowExists = xpath.select1('contains(draw_type/@value, "Shadow")', shape);
|
||||||
|
// Shadow 옵션이 있다면
|
||||||
|
if (shadowExists) {
|
||||||
|
// 두께
|
||||||
|
const width = xpath.select1('shadow_width/@value', shape).value;
|
||||||
|
// 거리
|
||||||
|
const distance = xpath.select1('shadow_distance/@value', shape).value;
|
||||||
|
// 분산도
|
||||||
|
const blur = xpath.select1('shadow_blur/@value', shape).value;
|
||||||
|
// 각도
|
||||||
|
const angle = xpath.select1('shadow_angle/@value', shape).value;
|
||||||
|
|
||||||
|
userAnswer = {
|
||||||
|
shadow: shadowExists,
|
||||||
|
width: width,
|
||||||
|
distance: distance,
|
||||||
|
blur: blur,
|
||||||
|
angle: angle,
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
isMatched = true;
|
userAnswer = {
|
||||||
|
shadow: shadowExists,
|
||||||
|
width: null,
|
||||||
|
distance: null,
|
||||||
|
blur: null,
|
||||||
|
angle: null,
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// console.log("🚀 ~ userAnswer:", userAnswer);
|
||||||
// 속성값이 하나라도 일치하지 않으면 오답
|
// console.log("🚀 ~ rightAnswer : ", rightAnswer)
|
||||||
if (isMatched === false) {
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
||||||
break;
|
partial: true
|
||||||
}
|
})
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
else if (type == "boolean") {
|
||||||
else if (type === "exists") {
|
const items = xpath.select(ele, gpdpXmlDoc);
|
||||||
const existsValues = xpath.select(ele, gpdpXmlDoc);
|
|
||||||
let isMatched = false;
|
|
||||||
|
|
||||||
for (const v of existsValues) {
|
// xpath 결과값을 반환하는 요소가 없을 경우
|
||||||
// 하나라도 일치하면 정답
|
if (!items) {
|
||||||
if (v.value === rightAnswer) {
|
scoringResult[key] = 0;
|
||||||
userAnswer = v.value;
|
console.log("❌ 찾는 요소 없음");
|
||||||
isMatched = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
// if (isMatched) {
|
totalScore += point;
|
||||||
|
scoringResult[key] = point;
|
||||||
// }
|
console.log("✅ 찾는 요소 존재함");
|
||||||
// else {
|
|
||||||
|
|
||||||
// }
|
|
||||||
totalScore = compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// else if (type === "shape.size") {
|
|
||||||
else if (type.includes("size")) {
|
|
||||||
const items = xpath.select(ele, gpdpXmlDoc);
|
|
||||||
let isMatched = false;
|
|
||||||
|
|
||||||
// 각 Item 요소별 x,y 좌표 시작점과 끝점의 거리를 계산해 정답과 비교
|
|
||||||
for (const item of items) {
|
|
||||||
const x1 = Number(xpath.select1('Item[1]/X/@value', item)?.value);
|
|
||||||
const y1 = Number(xpath.select1('Item[1]/Y/@value', item)?.value);
|
|
||||||
|
|
||||||
const x2 = Number(xpath.select1('Item[last()]/X/@value', item)?.value);
|
|
||||||
const y2 = Number(xpath.select1('Item[last()]/Y/@value', item)?.value);
|
|
||||||
|
|
||||||
const width = Math.round(Math.abs(x2 - x1));
|
|
||||||
const height = Math.round(Math.abs(y2 - y1));
|
|
||||||
|
|
||||||
userAnswer = {
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 하나라도 일치하면 정답
|
|
||||||
if (JSON.stringify(userAnswer) == JSON.stringify(rightAnswer)) {
|
|
||||||
isMatched = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
totalScore = compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
// 이펙트 효과의 이름과 속성값을 비교
|
||||||
continue;
|
else if (type == "effects") {
|
||||||
}
|
const items = xpath.select(ele, gpdpXmlDoc);
|
||||||
|
let matched = false;
|
||||||
|
|
||||||
// [1-8]
|
// 각 Item 요소별 이름과 속성값을 구하고 정답과 비교
|
||||||
else if (type.includes("color")) {
|
for (const item of items) {
|
||||||
const items = xpath.select(ele, gpdpXmlDoc);
|
const name = xpath.select1('Name/@value', item)?.value;
|
||||||
let normalizedAnswer = null;
|
const attr = xpath.select1(`EffectData/${option?.replace(/"/g, '')}/@value`, item)?.value;
|
||||||
let isMatched = false;
|
|
||||||
|
|
||||||
for (const item of items) {
|
if (name === rightAnswer[0] && attr === rightAnswer[1]) {
|
||||||
if (type.includes('gradient')) {
|
totalScore += point;
|
||||||
const startColorXpath = scoringData[key].startColor;
|
scoringResult[key] = point;
|
||||||
const endColorXpath = scoringData[key].endColor;
|
matched = true;
|
||||||
|
console.log("✅ 정답 일치:", rightAnswer);
|
||||||
const startColorRGB = xpath.select1(startColorXpath, item).value;
|
|
||||||
const endColorRGB = xpath.select1(endColorXpath, item).value;
|
|
||||||
|
|
||||||
const startColor = parseColorToHex(startColorRGB);
|
|
||||||
const endColor = parseColorToHex(endColorRGB);
|
|
||||||
|
|
||||||
userAnswer = {
|
|
||||||
startColor: startColor,
|
|
||||||
endColor: endColor,
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON파일에서 대문자로 입력된 경우 소문자로 변환
|
|
||||||
normalizedAnswer = {
|
|
||||||
startColor: rightAnswer.startColor.toLowerCase(),
|
|
||||||
endColor: rightAnswer.endColor.toLowerCase(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 하나라도 일치하면 정답
|
|
||||||
if (JSON.stringify(userAnswer) == JSON.stringify(normalizedAnswer)) {
|
|
||||||
isMatched = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// else if (type.includes('shape') || type.includes('text') || type.includes('clipping')) {
|
if (!matched) {
|
||||||
else {
|
scoringResult[key] = 0;
|
||||||
const color = parseColorToHex(item.value);
|
console.log("❌ 정답 없음:", rightAnswer);
|
||||||
userAnswer = color;
|
}
|
||||||
normalizedAnswer = rightAnswer.toLowerCase?.();
|
}
|
||||||
|
|
||||||
// 하나라도 일치하면 정답
|
else if (type == "multiValue") {
|
||||||
if (userAnswer === normalizedAnswer) {
|
if (Array.isArray(rightAnswer)) {
|
||||||
isMatched = true;
|
const result = ele ? xpath.select(ele, gpdpXmlDoc) : [];
|
||||||
break;
|
const resultValues = Array.isArray(result) ? result.map(r => (typeof r === 'object' ? r.value : r)) : [result];
|
||||||
|
console.log("🚀 ~ getGpdpScore ~ resultValues:", resultValues)
|
||||||
|
|
||||||
|
const groupSize = rightAnswer.length;
|
||||||
|
const groupedResult = [];
|
||||||
|
for (let i = 0; i < resultValues.length; i += groupSize) {
|
||||||
|
groupedResult.push(resultValues.slice(i, i + groupSize));
|
||||||
|
}
|
||||||
|
console.log("🚀 ~ getGpdpScore ~ groupedResult:", groupedResult)
|
||||||
|
|
||||||
|
// 배열 비교 함수
|
||||||
|
function arraysEqual(arr1, arr2) {
|
||||||
|
if (arr1.length !== arr2.length) return false;
|
||||||
|
return arr1.every((value, index) => value === arr2[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// groupedResult 내부 배열에서 rightAnswer와 일치하는 배열이 있는지 확인
|
||||||
|
const isMatch = groupedResult.some(group => arraysEqual(group, rightAnswer));
|
||||||
|
|
||||||
|
if (isMatch) {
|
||||||
|
totalScore += point;
|
||||||
|
scoringResult[key] = point;
|
||||||
|
console.log("🚀 ~ 정답 포함");
|
||||||
|
} else {
|
||||||
|
scoringResult[key] = 0;
|
||||||
|
console.log("🚀 ~ 오답");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalScore = compareAndScore(userAnswer, normalizedAnswer, point, key, scoringResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (type === 'layer.blend.opacity') {
|
else if (type == "exact") {
|
||||||
const layers = xpath.select(ele, gpdpXmlDoc);
|
let result = xpath.select(ele, gpdpXmlDoc);
|
||||||
let isMatched = false;
|
if (result.length == 0) {
|
||||||
|
scoringResult[key] = 0;
|
||||||
for (const layer of layers) {
|
console.log('ele not found');
|
||||||
const blendop = xpath.select1('BlendOp/@value', layer).value;
|
continue;
|
||||||
const opacity = xpath.select1('Opacity/@value', layer).value;
|
|
||||||
|
|
||||||
userAnswer = {
|
|
||||||
BlendOp: blendop,
|
|
||||||
Opacity: opacity,
|
|
||||||
}
|
}
|
||||||
|
if (result[0].value === rightAnswer) {
|
||||||
// 하나라도 일치하면 정답
|
|
||||||
if (JSON.stringify(userAnswer) == JSON.stringify(rightAnswer)) {
|
|
||||||
isMatched = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalScore = compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [5-20]
|
|
||||||
else if (type === 'shadow') {
|
|
||||||
const shapes = xpath.select(ele, gpdpXmlDoc);
|
|
||||||
|
|
||||||
for (const shape of shapes) {
|
|
||||||
// 그림자 설정 여부
|
|
||||||
const shadowExists = xpath.select1('contains(draw_type/@value, "Shadow")', shape);
|
|
||||||
// Shadow 옵션이 있다면
|
|
||||||
if (shadowExists) {
|
|
||||||
// 두께
|
|
||||||
const width = xpath.select1('shadow_width/@value', shape).value;
|
|
||||||
// 거리
|
|
||||||
const distance = xpath.select1('shadow_distance/@value', shape).value;
|
|
||||||
// 분산도
|
|
||||||
const blur = xpath.select1('shadow_blur/@value', shape).value;
|
|
||||||
// 각도
|
|
||||||
const angle = xpath.select1('shadow_angle/@value', shape).value;
|
|
||||||
|
|
||||||
userAnswer = {
|
|
||||||
shadow: shadowExists,
|
|
||||||
width: width,
|
|
||||||
distance: distance,
|
|
||||||
blur: blur,
|
|
||||||
angle: angle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
userAnswer = {
|
|
||||||
shadow: shadowExists,
|
|
||||||
width: null,
|
|
||||||
distance: null,
|
|
||||||
blur: null,
|
|
||||||
angle: null,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log("🚀 ~ userAnswer:", userAnswer);
|
|
||||||
console.log("🚀 ~ rightAnswer : ", rightAnswer)
|
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
|
||||||
partial: true
|
|
||||||
})
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (type == "boolean") {
|
|
||||||
const items = xpath.select(ele, gpdpXmlDoc);
|
|
||||||
|
|
||||||
// xpath 결과값을 반환하는 요소가 없을 경우
|
|
||||||
if (!items) {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
console.log("❌ 찾는 요소 없음");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
totalScore += point;
|
|
||||||
scoringResult[key] = point;
|
|
||||||
console.log("✅ 찾는 요소 존재함");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 이펙트 효과의 이름과 속성값을 비교
|
|
||||||
else if (type == "effects") {
|
|
||||||
const items = xpath.select(ele, gpdpXmlDoc);
|
|
||||||
let matched = false;
|
|
||||||
|
|
||||||
// 각 Item 요소별 이름과 속성값을 구하고 정답과 비교
|
|
||||||
for (const item of items) {
|
|
||||||
const name = xpath.select1('Name/@value', item)?.value;
|
|
||||||
const attr = xpath.select1(`EffectData/${option?.replace(/"/g, '')}/@value`, item)?.value;
|
|
||||||
|
|
||||||
if (name === rightAnswer[0] && attr === rightAnswer[1]) {
|
|
||||||
totalScore += point;
|
totalScore += point;
|
||||||
scoringResult[key] = point;
|
scoringResult[key] = point;
|
||||||
matched = true;
|
|
||||||
console.log("✅ 정답 일치:", rightAnswer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!matched) {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
console.log("❌ 정답 없음:", rightAnswer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (type == "multiValue") {
|
|
||||||
if (Array.isArray(rightAnswer)) {
|
|
||||||
const result = ele ? xpath.select(ele, gpdpXmlDoc) : [];
|
|
||||||
const resultValues = Array.isArray(result) ? result.map(r => (typeof r === 'object' ? r.value : r)) : [result];
|
|
||||||
console.log("🚀 ~ getGpdpScore ~ resultValues:", resultValues)
|
|
||||||
|
|
||||||
const groupSize = rightAnswer.length;
|
|
||||||
const groupedResult = [];
|
|
||||||
for (let i = 0; i < resultValues.length; i += groupSize) {
|
|
||||||
groupedResult.push(resultValues.slice(i, i + groupSize));
|
|
||||||
}
|
|
||||||
console.log("🚀 ~ getGpdpScore ~ groupedResult:", groupedResult)
|
|
||||||
|
|
||||||
// 배열 비교 함수
|
|
||||||
function arraysEqual(arr1, arr2) {
|
|
||||||
if (arr1.length !== arr2.length) return false;
|
|
||||||
return arr1.every((value, index) => value === arr2[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// groupedResult 내부 배열에서 rightAnswer와 일치하는 배열이 있는지 확인
|
|
||||||
const isMatch = groupedResult.some(group => arraysEqual(group, rightAnswer));
|
|
||||||
|
|
||||||
if (isMatch) {
|
|
||||||
totalScore += point;
|
|
||||||
scoringResult[key] = point;
|
|
||||||
console.log("🚀 ~ 정답 포함");
|
|
||||||
} else {
|
} else {
|
||||||
scoringResult[key] = 0;
|
scoringResult[key] = 0;
|
||||||
console.log("🚀 ~ 오답");
|
console.log('ele not matched, ' + result[0].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else if (type == "exact") {
|
|
||||||
let result = xpath.select(ele, gpdpXmlDoc);
|
else if (type == "multi") {
|
||||||
if (result.length == 0) {
|
try {
|
||||||
scoringResult[key] = 0;
|
const result = xpath.select(ele, gpdpXmlDoc);
|
||||||
console.log('ele not found');
|
let isSame = true;
|
||||||
continue;
|
// console.log(`ele: ${ele}, value: ${value} result: ${result}`);
|
||||||
|
|
||||||
|
if (result.length == 0) {
|
||||||
|
console.log('result length 0');
|
||||||
|
scoringResult[key] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.forEach((v, i) => {
|
||||||
|
// value[i] 값이 정수형인 경우에는 float로 변환하여 비교
|
||||||
|
// 정수형 v값을 float 형으로 변환하고 소수점 3자리까지 버림
|
||||||
|
let temp = v.value;
|
||||||
|
let answer = rightAnswer[i];
|
||||||
|
|
||||||
|
if (Number.isFinite(rightAnswer[i]) && !Number.isInteger(rightAnswer[i])) {
|
||||||
|
temp = parseFloat(v.value);
|
||||||
|
answer = parseFloat(rightAnswer[i]);
|
||||||
|
// 소수점 3자리까지 버림
|
||||||
|
temp = Math.floor(temp * 1000) / 1000;
|
||||||
|
}
|
||||||
|
// answer 문자열 중 : 가 포함되어 있다면 각각 분리하고 그 값의 차이를 구함
|
||||||
|
if (typeof answer == "string" && answer.indexOf(':') > -1) {
|
||||||
|
const [answerStart, answerEnd] = answer.split(':').map(Number);
|
||||||
|
const [tempStart, tempEnd] = temp.split(':').map(Number);
|
||||||
|
answer = answerEnd - answerStart;
|
||||||
|
temp = tempEnd - tempStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`temp: ${temp} answer: ${answer}`);
|
||||||
|
if (answer !== temp) {
|
||||||
|
console.log(`answer !== temp`);
|
||||||
|
isSame = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
totalScore += isSame ? point : 0;
|
||||||
|
scoringResult[key] = isSame ? point : 0;
|
||||||
|
} catch (e) {
|
||||||
|
console.log('err :', e);
|
||||||
|
scoringResult[key] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (result[0].value === rightAnswer) {
|
else if (type == "gradient") {
|
||||||
totalScore += point;
|
const items = xpath.select(ele, gpdpXmlDoc);
|
||||||
scoringResult[key] = point;
|
const startColorXpath = scoringData[key].startColor;
|
||||||
} else {
|
const endColorXpath = scoringData[key].endColor;
|
||||||
scoringResult[key] = 0;
|
let matched = false;
|
||||||
console.log('ele not matched, ' + result[0].value);
|
|
||||||
|
for (const item of items) {
|
||||||
|
const startColor = parseColorToHex(xpath.select1(startColorXpath, item)?.value);
|
||||||
|
const endColor = parseColorToHex(xpath.select1(endColorXpath, item)?.value);
|
||||||
|
|
||||||
|
console.log(startColor + ":" + rightAnswer["startColor"], endColor + ":" + rightAnswer["endColor"]);
|
||||||
|
|
||||||
|
if (startColor === rightAnswer["startColor"] && endColor === rightAnswer["endColor"]) {
|
||||||
|
totalScore += point;
|
||||||
|
scoringResult[key] = point;
|
||||||
|
matched = true;
|
||||||
|
console.log("✅ 정답 일치:", rightAnswer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!matched) {
|
||||||
|
scoringResult[key] = 0;
|
||||||
|
console.log("❌ 정답 없음:", rightAnswer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// 그림자 속성이 있는지 여부 파악해서 그림자 속성 별로 점수 1 점씩 부여
|
||||||
|
else if (type == "shadow") {
|
||||||
|
|
||||||
|
const result = xpath.select(ele["shadow"], gpdpXmlDoc);
|
||||||
|
let shadowScore = 0;
|
||||||
|
if (result.length == 0) {
|
||||||
|
scoringResult[key] = 0;
|
||||||
|
console.log('shadow not found');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
else if (type == "multi") {
|
shadowScore += 1;
|
||||||
try {
|
const width = xpath.select(ele["width"], gpdpXmlDoc);
|
||||||
|
const distance = xpath.select(ele["distance"], gpdpXmlDoc);
|
||||||
|
const blur = xpath.select(ele["blur"], gpdpXmlDoc);
|
||||||
|
const angle = xpath.select(ele["angle"], gpdpXmlDoc);
|
||||||
|
|
||||||
|
if (width.length !== 0 && width[0].value == rightAnswer["width"]) {
|
||||||
|
shadowScore += 1;
|
||||||
|
console.log('width matched');
|
||||||
|
}
|
||||||
|
if (distance.length !== 0 && distance[0].value == rightAnswer["distance"]) {
|
||||||
|
shadowScore += 1;
|
||||||
|
console.log('distance matched');
|
||||||
|
}
|
||||||
|
if (blur.length !== 0 && blur[0].value == rightAnswer["blur"]) {
|
||||||
|
shadowScore += 1;
|
||||||
|
console.log('blur matched');
|
||||||
|
}
|
||||||
|
if (angle.length !== 0 && angle[0].value == rightAnswer["angle"]) {
|
||||||
|
shadowScore += 1;
|
||||||
|
console.log('angle matched');
|
||||||
|
}
|
||||||
|
totalScore += shadowScore;
|
||||||
|
scoringResult[key] = shadowScore;
|
||||||
|
}
|
||||||
|
else {
|
||||||
const result = xpath.select(ele, gpdpXmlDoc);
|
const result = xpath.select(ele, gpdpXmlDoc);
|
||||||
let isSame = true;
|
const result2 = null;
|
||||||
// console.log(`ele: ${ele}, value: ${value} result: ${result}`);
|
let isCheck = false;
|
||||||
|
|
||||||
if (result.length == 0) {
|
if (result.length == 0) {
|
||||||
console.log('result length 0');
|
isCheck = true;
|
||||||
scoringResult[key] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
if (isCheck && ele2) {
|
||||||
|
result2 = xpath.select(ele2, gpdpXmlDoc);
|
||||||
|
|
||||||
result.forEach((v, i) => {
|
if (result2.length == 0) {
|
||||||
// value[i] 값이 정수형인 경우에는 float로 변환하여 비교
|
scoringResult[key] = 0;
|
||||||
// 정수형 v값을 float 형으로 변환하고 소수점 3자리까지 버림
|
continue;
|
||||||
let temp = v.value;
|
|
||||||
let answer = rightAnswer[i];
|
|
||||||
|
|
||||||
if (Number.isFinite(rightAnswer[i]) && !Number.isInteger(rightAnswer[i])) {
|
|
||||||
temp = parseFloat(v.value);
|
|
||||||
answer = parseFloat(rightAnswer[i]);
|
|
||||||
// 소수점 3자리까지 버림
|
|
||||||
temp = Math.floor(temp * 1000) / 1000;
|
|
||||||
}
|
}
|
||||||
// answer 문자열 중 : 가 포함되어 있다면 각각 분리하고 그 값의 차이를 구함
|
result = result2;
|
||||||
if (typeof answer == "string" && answer.indexOf(':') > -1) {
|
// console.log(`1st isChecked: ${isCheck}, result: ${result}`)
|
||||||
const [answerStart, answerEnd] = answer.split(':').map(Number);
|
|
||||||
const [tempStart, tempEnd] = temp.split(':').map(Number);
|
|
||||||
answer = answerEnd - answerStart;
|
|
||||||
temp = tempEnd - tempStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`temp: ${temp} answer: ${answer}`);
|
|
||||||
if (answer !== temp) {
|
|
||||||
console.log(`answer !== temp`);
|
|
||||||
isSame = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
totalScore += isSame ? point : 0;
|
|
||||||
scoringResult[key] = isSame ? point : 0;
|
|
||||||
} catch (e) {
|
|
||||||
console.log('err :', e);
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == "gradient") {
|
|
||||||
const items = xpath.select(ele, gpdpXmlDoc);
|
|
||||||
const startColorXpath = scoringData[key].startColor;
|
|
||||||
const endColorXpath = scoringData[key].endColor;
|
|
||||||
let matched = false;
|
|
||||||
|
|
||||||
for (const item of items) {
|
|
||||||
const startColor = parseColorToHex(xpath.select1(startColorXpath, item)?.value);
|
|
||||||
const endColor = parseColorToHex(xpath.select1(endColorXpath, item)?.value);
|
|
||||||
|
|
||||||
console.log(startColor + ":" + rightAnswer["startColor"], endColor + ":" + rightAnswer["endColor"]);
|
|
||||||
|
|
||||||
if (startColor === rightAnswer["startColor"] && endColor === rightAnswer["endColor"]) {
|
|
||||||
totalScore += point;
|
|
||||||
scoringResult[key] = point;
|
|
||||||
matched = true;
|
|
||||||
console.log("✅ 정답 일치:", rightAnswer);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
// value와 result[0].value를 비교하여 같으면 점수 point 부여
|
||||||
if (!matched) {
|
// console.log(`${(value === result[0].value)}, ${result.length > 0 && value === result[0].value} `)
|
||||||
scoringResult[key] = 0;
|
// console.log(`2nd isChecked: ${isCheck}, result: ${result}`)
|
||||||
console.log("❌ 정답 없음:", rightAnswer);
|
totalScore += result.length > 0 ? point : 0;
|
||||||
|
scoringResult[key] = result.length > 0 ? point : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 그림자 속성이 있는지 여부 파악해서 그림자 속성 별로 점수 1 점씩 부여
|
scoringResult['총점'] = totalScore;
|
||||||
else if (type == "shadow") {
|
return scoringResult;
|
||||||
|
|
||||||
const result = xpath.select(ele["shadow"], gpdpXmlDoc);
|
|
||||||
let shadowScore = 0;
|
|
||||||
if (result.length == 0) {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
console.log('shadow not found');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
shadowScore += 1;
|
|
||||||
const width = xpath.select(ele["width"], gpdpXmlDoc);
|
|
||||||
const distance = xpath.select(ele["distance"], gpdpXmlDoc);
|
|
||||||
const blur = xpath.select(ele["blur"], gpdpXmlDoc);
|
|
||||||
const angle = xpath.select(ele["angle"], gpdpXmlDoc);
|
|
||||||
|
|
||||||
if (width.length !== 0 && width[0].value == rightAnswer["width"]) {
|
|
||||||
shadowScore += 1;
|
|
||||||
console.log('width matched');
|
|
||||||
}
|
|
||||||
if (distance.length !== 0 && distance[0].value == rightAnswer["distance"]) {
|
|
||||||
shadowScore += 1;
|
|
||||||
console.log('distance matched');
|
|
||||||
}
|
|
||||||
if (blur.length !== 0 && blur[0].value == rightAnswer["blur"]) {
|
|
||||||
shadowScore += 1;
|
|
||||||
console.log('blur matched');
|
|
||||||
}
|
|
||||||
if (angle.length !== 0 && angle[0].value == rightAnswer["angle"]) {
|
|
||||||
shadowScore += 1;
|
|
||||||
console.log('angle matched');
|
|
||||||
}
|
|
||||||
totalScore += shadowScore;
|
|
||||||
scoringResult[key] = shadowScore;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const result = xpath.select(ele, gpdpXmlDoc);
|
|
||||||
const result2 = null;
|
|
||||||
let isCheck = false;
|
|
||||||
|
|
||||||
if (result.length == 0) {
|
|
||||||
isCheck = true;
|
|
||||||
}
|
|
||||||
if (isCheck && ele2) {
|
|
||||||
result2 = xpath.select(ele2, gpdpXmlDoc);
|
|
||||||
|
|
||||||
if (result2.length == 0) {
|
|
||||||
scoringResult[key] = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result = result2;
|
|
||||||
// console.log(`1st isChecked: ${isCheck}, result: ${result}`)
|
|
||||||
}
|
|
||||||
// value와 result[0].value를 비교하여 같으면 점수 point 부여
|
|
||||||
// console.log(`${(value === result[0].value)}, ${result.length > 0 && value === result[0].value} `)
|
|
||||||
// console.log(`2nd isChecked: ${isCheck}, result: ${result}`)
|
|
||||||
totalScore += result.length > 0 ? point : 0;
|
|
||||||
scoringResult[key] = result.length > 0 ? point : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scoringResult['총점'] = totalScore;
|
|
||||||
return scoringResult;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ const examTypes = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// testMode가 true일 경우 TEST 폴더에 있는 답안 파일을 읽어옴
|
// testMode가 true일 경우 TEST 폴더에 있는 답안 파일을 읽어옴
|
||||||
const testMode = false;
|
// const testMode = false;
|
||||||
// const testMode = true;
|
const testMode = true;
|
||||||
|
|
||||||
const outputExcelFiles = [];
|
const outputExcelFiles = [];
|
||||||
|
|
||||||
@@ -459,7 +459,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
// 만약 CRClip 요소가 motion clip인 경우 CRCUnitArr의 Path를 찾기
|
// 만약 CRClip 요소가 motion clip인 경우 CRCUnitArr의 Path를 찾기
|
||||||
if (mediaPath == null) {
|
if (mediaPath == null) {
|
||||||
const motionClipPath = xpath.select1(`//CRClipArr/CRClip[${CRClipIndex}]/CRCUnitArr/@Path`, gmepXmlDoc);
|
const motionClipPath = xpath.select1(`//CRClipArr/CRClip[${CRClipIndex}]/CRCUnitArr/@Path`, gmepXmlDoc);
|
||||||
if (motionClipPath !== null) {
|
if (motionClipPath != null) {
|
||||||
const fileName = path.basename(motionClipPath.value);
|
const fileName = path.basename(motionClipPath.value);
|
||||||
mediaOrderList.push(fileName);
|
mediaOrderList.push(fileName);
|
||||||
}
|
}
|
||||||
@@ -616,7 +616,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
else {
|
else {
|
||||||
const xpathExpr = ele?.replace(/{CRClipIndex}/g, crclipIndex);
|
const xpathExpr = ele?.replace(/{CRClipIndex}/g, crclipIndex);
|
||||||
const muteStatus = xpath.select1(xpathExpr, gmepXmlDoc);
|
const muteStatus = xpath.select1(xpathExpr, gmepXmlDoc);
|
||||||
userAnswer = muteStatus.value;
|
userAnswer = muteStatus?.value;
|
||||||
}
|
}
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
}
|
}
|
||||||
@@ -649,7 +649,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
if (!crTrackClip) {
|
if (!crTrackClip) {
|
||||||
userAnswer = null;
|
userAnswer = null;
|
||||||
} else {
|
} else {
|
||||||
const length = parseInt(crTrackClip.getAttribute('Length'), 10);
|
const length = crTrackClip.getAttribute('Length');
|
||||||
userAnswer = length;
|
userAnswer = length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user