Commit 106f9d68 authored by Kento HASEGAWA's avatar Kento HASEGAWA

Merge branch 'comm' into 'master'

Merge comm

See merge request adc2018/adc2018-system!11
parents ca2e8c1b c84029f6
...@@ -60,18 +60,18 @@ def load_questions(): ...@@ -60,18 +60,18 @@ def load_questions():
"board_size": board_size, "board_size": board_size,
"line_num": line_num, "line_num": line_num,
"last_req": None, "last_req": None,
"answers": [], "answers": OrderedDict(),
} }
update_answer_list(_name) update_answer_list(_name)
# 既に回答されているものを読み込む # 既に回答されているものを読み込む
answer_path = os.path.abspath(app_args["out"]) answer_path = os.path.abspath(app_args["out"])
answer_list = glob.glob("{}/T03_A*.txt".format(answer_path)) answer_list = glob.glob("{}/submit/T01_A*.txt".format(answer_path))
for v in answer_list: for v in answer_list:
_ans_name = os.path.basename(v) _ans_name = os.path.basename(v)
m = re.search(r"T03_A([0-9A-Za-z]+)\.txt", _ans_name) m = re.search(r"T01_A([0-9A-Za-z]+)\.txt", _ans_name)
if m: if m:
_name = "NL_Q{}.txt".format(m.group(1)) _name = "NL_Q{}.txt".format(m.group(1))
with open(v, "r") as fp: with open(v, "r") as fp:
...@@ -87,7 +87,7 @@ def update_answer_list(qname): ...@@ -87,7 +87,7 @@ def update_answer_list(qname):
global app_args global app_args
global questions global questions
questions[qname]['answers'] = [] questions[qname]['answers'] = OrderedDict()
_folder_name = os.path.splitext(qname)[0] _folder_name = os.path.splitext(qname)[0]
_answers_path = "{}/{}".format(app_args['out'], _folder_name) _answers_path = "{}/{}".format(app_args['out'], _folder_name)
...@@ -97,9 +97,13 @@ def update_answer_list(qname): ...@@ -97,9 +97,13 @@ def update_answer_list(qname):
answer_log_file.reverse() answer_log_file.reverse()
for v2 in answer_log_file: for v2 in answer_log_file:
json_name = os.path.basename(v2)
with open(v2, "r") as fp: with open(v2, "r") as fp:
answer_log = json.load(fp) answer_log = json.load(fp)
questions[qname]['answers'].append(answer_log) questions[qname]['answers'][json_name] = answer_log
if questions[qname]['answer'] == answer_log['answer']:
questions[qname]['best_json'] = json_name
@app.before_request @app.before_request
def before_request(): def before_request():
...@@ -161,7 +165,7 @@ def post(): ...@@ -161,7 +165,7 @@ def post():
if not os.path.isdir(save_path): if not os.path.isdir(save_path):
os.makedirs(save_path) os.makedirs(save_path)
file_name = "{}-{}.json".format(receive_time_str, _client.replace(":", ".")) file_name = "{}-{}.json".format(receive_time_str, _solver.replace(":", "."))
save_file_path = "{}/{}".format(save_path, file_name) save_file_path = "{}/{}".format(save_path, file_name)
with open(save_file_path, "w") as fp: with open(save_file_path, "w") as fp:
json.dump(dat, fp, indent=4) json.dump(dat, fp, indent=4)
...@@ -282,6 +286,148 @@ def get_status(): ...@@ -282,6 +286,148 @@ def get_status():
return json.dumps(res) return json.dumps(res)
@app.route("/save", methods=["POST"])
def save_best_solution():
"""
それぞれの問題に対し,解き終わった答えの中で最も品質の高い解を
submitフォルダに出力する.
"""
global questions
global app_args
qname = request.form["qname"]
_best_score = -1
_best_json = ""
for k, v in questions[qname]['answers'].items():
if v['nlcheck'] > _best_score:
_best_socer = v['nlcheck']
_best_json = k
if _best_json != "":
out_path = "{}/{}".format(app_args['out'], "submit")
if not os.path.isdir(out_path):
os.makedirs(out_path)
qnumber = qname.replace("NL_Q", "").replace(".txt", "")
out_file_path = "{}/T01_A{}.txt".format(out_path, qnumber)
with open(out_file_path, 'w') as fp:
fp.write(questions[qname]['answers'][_best_json]['answer'])
questions[qname]['best_json'] = _best_json
res = {"status": "OK"}
else:
res = {"status": "No answer is found"}
return json.dumps(res)
@app.route("/board-data", methods=["POST"])
def get_board_data():
global questions
qname = request.form['qname']
json_name = request.form['jname']
lines = questions[qname]['answers'][json_name]['answer'].split("\n")
quality = questions[qname]['answers'][json_name]['nlcheck']
# board_size = [int(v) for v in lines[1].rstrip().split()[1].split("X")]
board_size = [int(v) for v in questions[qname]['board_size'].split("X")]
raw_data = [[[0 for x in range(board_size[0])] for y in range(board_size[1])] for z in range(board_size[2])]
data = []
max_line_num = 0
for l in lines[1:]:
if l.rstrip() == "":
continue
elif l.startswith("LAYER"):
z = int(l.rstrip().split()[1])-1
y = 0
continue
else:
ldat = l.rstrip().split(",")
for x, v in enumerate(ldat):
raw_data[z][y][x] = int(v)
max_line_num = max(max_line_num, int(v))
y += 1
terminals = [[] for v in range(max_line_num+1)]
for z in range(board_size[2]):
for y in range(board_size[1]):
for x in range(board_size[0]):
line_num = raw_data[z][y][x]
if line_num == 0:
continue
adj_cnt = 0
if((0 <= x-1 < board_size[0]) and (raw_data[z][y][x-1] == line_num)):
adj_cnt += 1
if((0 <= x+1 < board_size[0]) and (raw_data[z][y][x+1] == line_num)):
adj_cnt += 1
if((0 <= y-1 < board_size[1]) and (raw_data[z][y-1][x] == line_num)):
adj_cnt += 1
if((0 <= y+1 < board_size[1]) and (raw_data[z][y+1][x] == line_num)):
adj_cnt += 1
if((0 <= z-1 < board_size[2]) and (raw_data[z-1][y][x] == line_num)):
adj_cnt += 1
if((0 <= z+1 < board_size[2]) and (raw_data[z+1][y][x] == line_num)):
adj_cnt += 1
if adj_cnt == 1:
terminals[line_num].append((x, y, z))
lines = {}
for i in range(1, max_line_num+1):
if len(terminals[i]) != 2:
continue
start = terminals[i][0]
goal = terminals[i][1]
lines[i] = []
lines[i].append(start)
lines[i].append(start)
now = start
_next = (0, 0, 0)
while now != goal:
x, y, z = now
adj_cnt = 0
if((0 <= x-1 < board_size[0]) and (raw_data[z][y][x-1] == i) and (lines[i][-2] != (x-1, y, z))):
_next = (x-1, y, z)
elif((0 <= x+1 < board_size[0]) and (raw_data[z][y][x+1] == i) and (lines[i][-2] != (x+1, y, z))):
_next = (x+1, y, z)
elif((0 <= y-1 < board_size[1]) and (raw_data[z][y-1][x] == i) and (lines[i][-2] != (x, y-1, z))):
_next = (x, y-1, z)
elif((0 <= y+1 < board_size[1]) and (raw_data[z][y+1][x] == i) and (lines[i][-2] != (x, y+1, z))):
_next = (x, y+1, z)
elif((0 <= z-1 < board_size[2]) and (raw_data[z-1][y][x] == i) and (lines[i][-2] != (x, y, z-1))):
_next = (x, y, z-1)
elif((0 <= z+1 < board_size[2]) and (raw_data[z+1][y][x] == i) and (lines[i][-2] != (x, y, z+1))):
_next = (x, y, z+1)
else:
print("Error: Not found an adjacent node")
_next = goal
lines[i].append(_next)
now = _next
res = {
'line': lines,
'board': board_size,
'quality': quality,
}
return json.dumps(res)
@app.route("/get_clients") @app.route("/get_clients")
def get_clients(): def get_clients():
global clients global clients
...@@ -294,6 +440,11 @@ def get_clients(): ...@@ -294,6 +440,11 @@ def get_clients():
return json.dumps(res) return json.dumps(res)
@app.route("/board-viewer", methods=["GET"])
def show_board_viewer():
return render_template("board-viewer.html")
@app.route("/get_question_table") @app.route("/get_question_table")
def question_table(): def question_table():
......
...@@ -40,6 +40,9 @@ body{ ...@@ -40,6 +40,9 @@ body{
#question-table-wrapper tr.question-row.q-selected{ #question-table-wrapper tr.question-row.q-selected{
background-color: rgba(200, 100, 100, .3); background-color: rgba(200, 100, 100, .3);
} }
#question-table-wrapper tr.question-row:hover{
background-color: rgba(200, 100, 100, .15);
}
#client-control-pane{ #client-control-pane{
height: 330px; height: 330px;
...@@ -58,3 +61,17 @@ body{ ...@@ -58,3 +61,17 @@ body{
#question-control-pane h3{ #question-control-pane h3{
display: inline-block; display: inline-block;
} }
#client-control-pane tr.answer-detail-row,
#client-control-pane tr.answer-detail-row td{
cursor: pointer;
}
#client-control-pane tr.answer-detail-row:hover{
background-color: rgba(200, 100, 100, .15);
}
#client-control-pane tr.answer-detail-row.submit-answer{
background-color: rgba(100, 200, 100, .3);
}
/**
* @author qiao / https://github.com/qiao
* @author mrdoob / http://mrdoob.com
* @author alteredq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
* @author erich666 / http://erichaines.com
*/
// This set of controls performs orbiting, dollying (zooming), and panning.
// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
//
// Orbit - left mouse / touch: one-finger move
// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
// Pan - right mouse, or left mouse + ctrl/metaKey, or arrow keys / touch: two-finger move
THREE.OrbitControls = function ( object, domElement ) {
this.object = object;
this.domElement = ( domElement !== undefined ) ? domElement : document;
// Set to false to disable this control
this.enabled = true;
// "target" sets the location of focus, where the object orbits around
this.target = new THREE.Vector3();
// How far you can dolly in and out ( PerspectiveCamera only )
this.minDistance = 0;
this.maxDistance = Infinity;
// How far you can zoom in and out ( OrthographicCamera only )
this.minZoom = 0;
this.maxZoom = Infinity;
// How far you can orbit vertically, upper and lower limits.
// Range is 0 to Math.PI radians.
this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians
// How far you can orbit horizontally, upper and lower limits.
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
this.minAzimuthAngle = - Infinity; // radians
this.maxAzimuthAngle = Infinity; // radians
// Set to true to enable damping (inertia)
// If damping is enabled, you must call controls.update() in your animation loop
this.enableDamping = false;
this.dampingFactor = 0.25;
// This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
// Set to false to disable zooming
this.enableZoom = true;
this.zoomSpeed = 1.0;
// Set to false to disable rotating
this.enableRotate = true;
this.rotateSpeed = 1.0;
// Set to false to disable panning
this.enablePan = true;
this.panSpeed = 1.0;
this.screenSpacePanning = false; // if true, pan in screen-space
this.keyPanSpeed = 7.0; // pixels moved per arrow key push
// Set to true to automatically rotate around the target
// If auto-rotate is enabled, you must call controls.update() in your animation loop
this.autoRotate = false;
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
// Set to false to disable use of the keys
this.enableKeys = true;
// The four arrow keys
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
// Mouse buttons
this.mouseButtons = { LEFT: THREE.MOUSE.LEFT, MIDDLE: THREE.MOUSE.MIDDLE, RIGHT: THREE.MOUSE.RIGHT };
// for reset
this.target0 = this.target.clone();
this.position0 = this.object.position.clone();
this.zoom0 = this.object.zoom;
//
// public methods
//
this.getPolarAngle = function () {
return spherical.phi;
};
this.getAzimuthalAngle = function () {
return spherical.theta;
};
this.saveState = function () {
scope.target0.copy( scope.target );
scope.position0.copy( scope.object.position );
scope.zoom0 = scope.object.zoom;
};
this.reset = function () {
scope.target.copy( scope.target0 );
scope.object.position.copy( scope.position0 );
scope.object.zoom = scope.zoom0;
scope.object.updateProjectionMatrix();
scope.dispatchEvent( changeEvent );
scope.update();
state = STATE.NONE;
};
// this method is exposed, but perhaps it would be better if we can make it private...
this.update = function () {
var offset = new THREE.Vector3();
// so camera.up is the orbit axis
var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
var quatInverse = quat.clone().inverse();
var lastPosition = new THREE.Vector3();
var lastQuaternion = new THREE.Quaternion();
return function update() {
var position = scope.object.position;
offset.copy( position ).sub( scope.target );
// rotate offset to "y-axis-is-up" space
offset.applyQuaternion( quat );
// angle from z-axis around y-axis
spherical.setFromVector3( offset );
if ( scope.autoRotate && state === STATE.NONE ) {
rotateLeft( getAutoRotationAngle() );
}
spherical.theta += sphericalDelta.theta;
spherical.phi += sphericalDelta.phi;
// restrict theta to be between desired limits
spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) );
// restrict phi to be between desired limits
spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
spherical.makeSafe();
spherical.radius *= scale;
// restrict radius to be between desired limits
spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );
// move target to panned location
scope.target.add( panOffset );
offset.setFromSpherical( spherical );
// rotate offset back to "camera-up-vector-is-up" space
offset.applyQuaternion( quatInverse );
position.copy( scope.target ).add( offset );
scope.object.lookAt( scope.target );
if ( scope.enableDamping === true ) {
sphericalDelta.theta *= ( 1 - scope.dampingFactor );
sphericalDelta.phi *= ( 1 - scope.dampingFactor );
panOffset.multiplyScalar( 1 - scope.dampingFactor );
} else {
sphericalDelta.set( 0, 0, 0 );
panOffset.set( 0, 0, 0 );
}
scale = 1;
// update condition is:
// min(camera displacement, camera rotation in radians)^2 > EPS
// using small-angle approximation cos(x/2) = 1 - x^2 / 8
if ( zoomChanged ||
lastPosition.distanceToSquared( scope.object.position ) > EPS ||
8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
scope.dispatchEvent( changeEvent );
lastPosition.copy( scope.object.position );
lastQuaternion.copy( scope.object.quaternion );
zoomChanged = false;
return true;
}
return false;
};
}();
this.dispose = function () {
scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
scope.domElement.removeEventListener( 'wheel', onMouseWheel, false );
scope.domElement.removeEventListener( 'touchstart', onTouchStart, false );
scope.domElement.removeEventListener( 'touchend', onTouchEnd, false );
scope.domElement.removeEventListener( 'touchmove', onTouchMove, false );
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
window.removeEventListener( 'keydown', onKeyDown, false );
//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
};
//
// internals
//
var scope = this;
var changeEvent = { type: 'change' };
var startEvent = { type: 'start' };
var endEvent = { type: 'end' };
var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY_PAN: 4 };
var state = STATE.NONE;
var EPS = 0.000001;
// current position in spherical coordinates
var spherical = new THREE.Spherical();
var sphericalDelta = new THREE.Spherical();
var scale = 1;
var panOffset = new THREE.Vector3();
var zoomChanged = false;
var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var panStart = new THREE.Vector2();
var panEnd = new THREE.Vector2();
var panDelta = new THREE.Vector2();
var dollyStart = new THREE.Vector2();
var dollyEnd = new THREE.Vector2();
var dollyDelta = new THREE.Vector2();
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow( 0.95, scope.zoomSpeed );
}
function rotateLeft( angle ) {
sphericalDelta.theta -= angle;
}
function rotateUp( angle ) {
sphericalDelta.phi -= angle;
}
var panLeft = function () {
var v = new THREE.Vector3();
return function panLeft( distance, objectMatrix ) {
v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
v.multiplyScalar( - distance );
panOffset.add( v );
};
}();
var panUp = function () {
var v = new THREE.Vector3();
return function panUp( distance, objectMatrix ) {
if ( scope.screenSpacePanning === true ) {
v.setFromMatrixColumn( objectMatrix, 1 );
} else {
v.setFromMatrixColumn( objectMatrix, 0 );
v.crossVectors( scope.object.up, v );
}
v.multiplyScalar( distance );
panOffset.add( v );
};
}();
// deltaX and deltaY are in pixels; right and down are positive
var pan = function () {
var offset = new THREE.Vector3();
return function pan( deltaX, deltaY ) {
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
if ( scope.object.isPerspectiveCamera ) {
// perspective
var position = scope.object.position;
offset.copy( position ).sub( scope.target );
var targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
// we use only clientHeight here so aspect ratio does not distort speed
panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
} else if ( scope.object.isOrthographicCamera ) {
// orthographic
panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
} else {
// camera neither orthographic nor perspective
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
scope.enablePan = false;
}
};
}();
function dollyIn( dollyScale ) {
if ( scope.object.isPerspectiveCamera ) {
scale /= dollyScale;
} else if ( scope.object.isOrthographicCamera ) {
scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
scope.object.updateProjectionMatrix();
zoomChanged = true;
} else {
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
scope.enableZoom = false;
}
}
function dollyOut( dollyScale ) {
if ( scope.object.isPerspectiveCamera ) {
scale *= dollyScale;
} else if ( scope.object.isOrthographicCamera ) {
scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
scope.object.updateProjectionMatrix();
zoomChanged = true;
} else {
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
scope.enableZoom = false;
}
}
//
// event callbacks - update the object state
//
function handleMouseDownRotate( event ) {
//console.log( 'handleMouseDownRotate' );
rotateStart.set( event.clientX, event.clientY );
}
function handleMouseDownDolly( event ) {
//console.log( 'handleMouseDownDolly' );
dollyStart.set( event.clientX, event.clientY );
}
function handleMouseDownPan( event ) {
//console.log( 'handleMouseDownPan' );
panStart.set( event.clientX, event.clientY );
}
function handleMouseMoveRotate( event ) {
//console.log( 'handleMouseMoveRotate' );
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
rotateStart.copy( rotateEnd );
scope.update();
}
function handleMouseMoveDolly( event ) {
//console.log( 'handleMouseMoveDolly' );
dollyEnd.set( event.clientX, event.clientY );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
dollyIn( getZoomScale() );
} else if ( dollyDelta.y < 0 ) {
dollyOut( getZoomScale() );
}
dollyStart.copy( dollyEnd );
scope.update();
}
function handleMouseMovePan( event ) {
//console.log( 'handleMouseMovePan' );
panEnd.set( event.clientX, event.clientY );
panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
pan( panDelta.x, panDelta.y );
panStart.copy( panEnd );
scope.update();
}
function handleMouseUp( event ) {
// console.log( 'handleMouseUp' );
}
function handleMouseWheel( event ) {
// console.log( 'handleMouseWheel' );
if ( event.deltaY < 0 ) {
dollyOut( getZoomScale() );
} else if ( event.deltaY > 0 ) {
dollyIn( getZoomScale() );
}
scope.update();
}
function handleKeyDown( event ) {
//console.log( 'handleKeyDown' );
switch ( event.keyCode ) {
case scope.keys.UP:
pan( 0, scope.keyPanSpeed );
scope.update();
break;
case scope.keys.BOTTOM:
pan( 0, - scope.keyPanSpeed );
scope.update();
break;
case scope.keys.LEFT:
pan( scope.keyPanSpeed, 0 );
scope.update();
break;
case scope.keys.RIGHT:
pan( - scope.keyPanSpeed, 0 );
scope.update();
break;
}
}
function handleTouchStartRotate( event ) {
//console.log( 'handleTouchStartRotate' );
rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
}
function handleTouchStartDollyPan( event ) {
//console.log( 'handleTouchStartDollyPan' );
if ( scope.enableZoom ) {
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyStart.set( 0, distance );
}
if ( scope.enablePan ) {
var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
panStart.set( x, y );
}
}
function handleTouchMoveRotate( event ) {
//console.log( 'handleTouchMoveRotate' );
rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
rotateStart.copy( rotateEnd );
scope.update();
}
function handleTouchMoveDollyPan( event ) {
//console.log( 'handleTouchMoveDollyPan' );
if ( scope.enableZoom ) {
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyEnd.set( 0, distance );
dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );
dollyIn( dollyDelta.y );
dollyStart.copy( dollyEnd );
}
if ( scope.enablePan ) {
var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
panEnd.set( x, y );
panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
pan( panDelta.x, panDelta.y );
panStart.copy( panEnd );
}
scope.update();
}
function handleTouchEnd( event ) {
//console.log( 'handleTouchEnd' );
}
//
// event handlers - FSM: listen for events and reset state
//
function onMouseDown( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
switch ( event.button ) {
case scope.mouseButtons.LEFT:
if ( event.ctrlKey || event.metaKey ) {
if ( scope.enablePan === false ) return;
handleMouseDownPan( event );
state = STATE.PAN;
} else {
if ( scope.enableRotate === false ) return;
handleMouseDownRotate( event );
state = STATE.ROTATE;
}
break;
case scope.mouseButtons.MIDDLE:
if ( scope.enableZoom === false ) return;
handleMouseDownDolly( event );
state = STATE.DOLLY;
break;
case scope.mouseButtons.RIGHT:
if ( scope.enablePan === false ) return;
handleMouseDownPan( event );
state = STATE.PAN;
break;
}
if ( state !== STATE.NONE ) {
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mouseup', onMouseUp, false );
scope.dispatchEvent( startEvent );
}
}
function onMouseMove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
switch ( state ) {
case STATE.ROTATE:
if ( scope.enableRotate === false ) return;
handleMouseMoveRotate( event );
break;
case STATE.DOLLY:
if ( scope.enableZoom === false ) return;
handleMouseMoveDolly( event );
break;
case STATE.PAN:
if ( scope.enablePan === false ) return;
handleMouseMovePan( event );
break;
}
}
function onMouseUp( event ) {
if ( scope.enabled === false ) return;
handleMouseUp( event );
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
scope.dispatchEvent( endEvent );
state = STATE.NONE;
}
function onMouseWheel( event ) {
if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;
event.preventDefault();
event.stopPropagation();
scope.dispatchEvent( startEvent );
handleMouseWheel( event );
scope.dispatchEvent( endEvent );
}
function onKeyDown( event ) {
if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
handleKeyDown( event );
}
function onTouchStart( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.enableRotate === false ) return;
handleTouchStartRotate( event );
state = STATE.TOUCH_ROTATE;
break;
case 2: // two-fingered touch: dolly-pan
if ( scope.enableZoom === false && scope.enablePan === false ) return;
handleTouchStartDollyPan( event );
state = STATE.TOUCH_DOLLY_PAN;
break;
default:
state = STATE.NONE;
}
if ( state !== STATE.NONE ) {
scope.dispatchEvent( startEvent );
}
}
function onTouchMove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
event.stopPropagation();
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.enableRotate === false ) return;
if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?
handleTouchMoveRotate( event );
break;
case 2: // two-fingered touch: dolly-pan
if ( scope.enableZoom === false && scope.enablePan === false ) return;
if ( state !== STATE.TOUCH_DOLLY_PAN ) return; // is this needed?
handleTouchMoveDollyPan( event );
break;
default:
state = STATE.NONE;
}
}
function onTouchEnd( event ) {
if ( scope.enabled === false ) return;
handleTouchEnd( event );
scope.dispatchEvent( endEvent );
state = STATE.NONE;
}
function onContextMenu( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
}
//
scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );
scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
scope.domElement.addEventListener( 'wheel', onMouseWheel, false );
scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
window.addEventListener( 'keydown', onKeyDown, false );
// force an update at start
this.update();
};
THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
Object.defineProperties( THREE.OrbitControls.prototype, {
center: {
get: function () {
console.warn( 'THREE.OrbitControls: .center has been renamed to .target' );
return this.target;
}
},
// backward compatibility
noZoom: {
get: function () {
console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
return ! this.enableZoom;
},
set: function ( value ) {
console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
this.enableZoom = ! value;
}
},
noRotate: {
get: function () {
console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
return ! this.enableRotate;
},
set: function ( value ) {
console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
this.enableRotate = ! value;
}
},
noPan: {
get: function () {
console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
return ! this.enablePan;
},
set: function ( value ) {
console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
this.enablePan = ! value;
}
},
noKeys: {
get: function () {
console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
return ! this.enableKeys;
},
set: function ( value ) {
console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
this.enableKeys = ! value;
}
},
staticMoving: {
get: function () {
console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
return ! this.enableDamping;
},
set: function ( value ) {
console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
this.enableDamping = ! value;
}
},
dynamicDampingFactor: {
get: function () {
console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
return this.dampingFactor;
},
set: function ( value ) {
console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
this.dampingFactor = value;
}
}
} );
...@@ -166,6 +166,24 @@ $(function(){ ...@@ -166,6 +166,24 @@ $(function(){
$("#client-control-pane").find(".stop-button").eq(0).click(function(){ $("#client-control-pane").find(".stop-button").eq(0).click(function(){
pm.sendStop(); pm.sendStop();
}); });
$("#client-control-pane").find(".save-button").eq(0).click(function(){
var qname = $(this).data("qname");
$.ajax({
type: "POST",
dataType: "json",
url: "/save",
data: {qname: qname}
}).done((data) => {
alert(data['status']);
});
});
$(".answer-detail-row td").click(function(){
var json_name = $(this).parent("tr").data("json");
var qname = $(this).parent("tr").data("qname");
var viewer_url = "/board-viewer#" + qname + "," + json_name
window.open(viewer_url, "_blank");
})
}); });
} }
......
This source diff could not be displayed because it is too large. You can view the blob instead.
<!DOCTYPE html>
<html>
<head>
<title>PYNQ Router Control Panel for ADC2018</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/pynq-manager.css">
<script src="/static/js/three.min.js"></script>
<script src="/static/js/OrbitControls.js"></script>
<script src="/static/js/jquery.min.js"></script>
<script src="/static/js/bootstrap.bundle.min.js"></script>
<!-- <script src="/static/js/pynq-manager.js"></script> -->
<script>
$(function(){
// サイズを指定
const _width = $("#view_area_wrapper").width();
const _height = $(window).height();
const colors = [0x0000FF, 0x00FF00, 0xFF0000, 0x00FFFF, 0xFF00FF, 0xFFFF00];
const _linewidth = 1;
const _linespace = 3;
const _linemargin = 1;
// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#viewer_area')
});
renderer.setClearColor(new THREE.Color(0xEEEEEE));
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(_width, _height);
// シーンを作成
const scene = new THREE.Scene();
// カメラを作成
// const camera = new THREE.PerspectiveCamera(45, width / height);
const camera = new THREE.PerspectiveCamera(45, _width / _height);
const controls = new THREE.OrbitControls(camera, document.querySelector('#viewer_area'));
var draw_answer = function (qname, jname) {
$.ajax({
url: "./board-data",
type: "POST",
data: {
qname: qname,
jname: jname
},
dataType: "json"
}).done((data) => {
scene.remove.apply(scene, scene.children);
var board_x = data['board'][0];
var board_y = data['board'][1];
var board_z = data['board'][2];
camera.position.set(_linespace * board_y / 2, _linespace * board_x / 2, +500);
controls.target.set(_linespace * board_y / 2, _linespace * board_x / 2, _linespace * board_z / 2);
for (var i = 0; i <= board_x; i++) {
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0, _linespace * i, _linespace * board_z));
geometry.vertices.push(new THREE.Vector3(0, _linespace * i, 0));
geometry.vertices.push(new THREE.Vector3(_linespace * board_y, _linespace * i, 0));
var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0x888888, transparent: true, opacity: 0.5 }));
scene.add(line);
}
for (var i = 0; i <= board_y; i++) {
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(_linespace * i, 0, _linespace * board_z));
geometry.vertices.push(new THREE.Vector3(_linespace * i, 0, 0));
geometry.vertices.push(new THREE.Vector3(_linespace * i, _linespace * board_x, 0));
var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0x888888, transparent: true, opacity: 0.5 }));
scene.add(line);
}
for (var i = 0; i <= board_z; i++) {
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0, _linespace * board_x, _linespace * i));
geometry.vertices.push(new THREE.Vector3(0, 0, _linespace * i));
geometry.vertices.push(new THREE.Vector3(_linespace * board_y, 0, _linespace * i));
var line = new THREE.Line(geometry, new THREE.LineBasicMaterial({ color: 0x888888, transparent: true, opacity: 0.5 }));
scene.add(line);
}
var line_data = data["line"];
var max_line_length = 0;
for (var i = 0; i < Object.keys(line_data).length; i++) {
var line_num = Number(Object.keys(line_data)[i]);
if (line_num == 0) continue;
max_line_length = Math.max(max_line_length, line_data[line_num].length);
const _color = colors[line_num % colors.length];
var _material = new THREE.LineBasicMaterial({ linewidth: _linewidth, color: _color, transparent: true, opacity: 0.5 });
var _geometry = new THREE.Geometry();
var _box_material = new THREE.MeshBasicMaterial({ color: _color, transparent: true, opacity: 0.5 });
var _box_geometry = new THREE.BoxGeometry(_linewidth, _linewidth, _linewidth);
for (var j = 1; j < line_data[line_num].length; j++) {
var _x = line_data[line_num][j][0];
var _y = line_data[line_num][j][1];
var _z = line_data[line_num][j][2];
_geometry.vertices.push(new THREE.Vector3(_linespace * _y + _linemargin, _linespace * _x + _linemargin, _linespace * _z + _linemargin));
var _cube = new THREE.Mesh(_box_geometry, _box_material);
_cube.position.x = _linespace * _y + _linemargin + _linewidth / 2
_cube.position.y = _linespace * _x + _linemargin + _linewidth / 2
_cube.position.z = _linespace * _z + _linemargin + _linewidth / 2
scene.add(_cube);
if (j >= 2) {
var _prev_x = line_data[line_num][j - 1][0];
var _prev_y = line_data[line_num][j - 1][1];
var _prev_z = line_data[line_num][j - 1][2];
var _padbox_material = new THREE.MeshBasicMaterial({ color: _color, transparent: true, opacity: 0.5 });
if (_x - _prev_x == -1) {
var _padbox_geometry = new THREE.BoxGeometry(_linewidth, 2 * _linemargin, _linewidth);
var _pad_cube = new THREE.Mesh(_padbox_geometry, _padbox_material);
_pad_cube.position.x = _linespace * _y + _linemargin + _linewidth / 2
_pad_cube.position.y = _linespace * (_x + 1) - _linemargin / 2 + _linewidth / 2
_pad_cube.position.z = _linespace * _z + _linemargin + _linewidth / 2
scene.add(_pad_cube);
}
if (_x - _prev_x == 1) {
var _padbox_geometry = new THREE.BoxGeometry(_linewidth, 2 * _linemargin, _linewidth);
var _pad_cube = new THREE.Mesh(_padbox_geometry, _padbox_material);
_pad_cube.position.x = _linespace * _y + _linemargin + _linewidth / 2
_pad_cube.position.y = _linespace * _x - _linemargin / 2 + _linewidth / 2
_pad_cube.position.z = _linespace * _z + _linemargin + _linewidth / 2
scene.add(_pad_cube);
}
if (_y - _prev_y == -1) {
var _padbox_geometry = new THREE.BoxGeometry(2 * _linemargin, _linewidth, _linewidth);
var _pad_cube = new THREE.Mesh(_padbox_geometry, _padbox_material);
_pad_cube.position.x = _linespace * (_y + 1) - _linemargin / 2 + _linewidth / 2
_pad_cube.position.y = _linespace * _x + _linemargin + _linewidth / 2
_pad_cube.position.z = _linespace * _z + _linemargin + _linewidth / 2
scene.add(_pad_cube);
}
if (_y - _prev_y == 1) {
var _padbox_geometry = new THREE.BoxGeometry(2 * _linemargin, _linewidth, _linewidth);
var _pad_cube = new THREE.Mesh(_padbox_geometry, _padbox_material);
_pad_cube.position.x = _linespace * _y - _linemargin / 2 + _linewidth / 2
_pad_cube.position.y = _linespace * _x + _linemargin + _linewidth / 2
_pad_cube.position.z = _linespace * _z + _linemargin + _linewidth / 2
scene.add(_pad_cube);
}
if (_z - _prev_z == -1) {
var _padbox_geometry = new THREE.BoxGeometry(_linewidth, _linewidth, 2 * _linemargin);
var _pad_cube = new THREE.Mesh(_padbox_geometry, _padbox_material);
_pad_cube.position.x = _linespace * _y + _linemargin + _linewidth / 2
_pad_cube.position.y = _linespace * _x + _linemargin + _linewidth / 2
_pad_cube.position.z = _linespace * (_z + 1) - _linemargin / 2 + _linewidth / 2
scene.add(_pad_cube);
}
if (_z - _prev_z == 1) {
var _padbox_geometry = new THREE.BoxGeometry(_linewidth, _linewidth, 2 * _linemargin);
var _pad_cube = new THREE.Mesh(_padbox_geometry, _padbox_material);
_pad_cube.position.x = _linespace * _y + _linemargin + _linewidth / 2
_pad_cube.position.y = _linespace * _x + _linemargin + _linewidth / 2
_pad_cube.position.z = _linespace * _z - _linemargin / 2 + _linewidth / 2
scene.add(_pad_cube);
}
}
}
scene.add(new THREE.Line(_geometry, _material));
}
var board_info = "" + board_x + " x " + board_y + " x " + board_z + " ";
$("#board_info_size").text(board_info);
$("#board_info_linenum").text("" + Object.keys(line_data).length);
$("#board_info_maxlength").text("" + max_line_length);
$("#board_info_quality").text("" + data['quality']);
$("#viewer_status").text("Complete.");
});
}
$(window).on('hashchange', function () {
var hash = location.hash.replace("#", "");
if (hash == "") {
$("#viewer_status").text("Please input the board name in the hash of URL.");
} else {
$("#viewer_status").text("Drawing...");
$("#board_info_size").text("...");
$("#board_info_linenum").text("...");
$("#board_info_maxlength").text("...");
$("#board_info_quality").text("...");
controls.reset();
var _data = hash.split(",")
$("#board_info_qname").text("" + _data[0]);
draw_answer(_data[0], _data[1]);
}
}).trigger('hashchange');
$(window).on('resize', function () {
var width = $("#view_area_wrapper").width();
var height = $(window).height();
renderer.setSize(width, height);
camera.aspect = width / height;
});
tick();
// 毎フレーム時に実行されるループイベントです
function tick() {
// レンダリング
renderer.render(scene, camera);
requestAnimationFrame(tick);
}
});
</script>
<style>
html,
body {
height: 100%;
}
body {
overflow: hidden;
padding: 0;
}
#wrapper {
width: 100%;
height: 100vh;
}
#view_board_info {
position: fixed;
top: 0;
left: 0;
overflow-y: auto;
padding: 5px;
background-color: rgba(255, 255, 255, 0.5);
line-height: 1.2em;
}
#view_area_wrapper {
width: 100%;
height: 100vh;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="view_board_info">
<dt>Status</dt>
<dd><span id="viewer_status">Ready to start.</span></dd>
<dt>Question name</dt>
<dd><span id="board_info_qname"></span></dd>
<dt>Board size</dt>
<dd><span id="board_info_size"></span></dd>
<dt># of lines</dt>
<dd><span id="board_info_linenum"></span></dd>
<dt>Max line length</dt>
<dd><span id="board_info_maxlength"></span></dd>
<dt>Quality</dt>
<dd><span id="board_info_quality"></span></dd>
</div>
<div id="view_area_wrapper">
<canvas id="viewer_area"></canvas>
</div>
</div>
</body>
</html>
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
<h3> 【{{qname}}】</h3> <h3> 【{{qname}}】</h3>
<p> <p>
<button class="btn btn-primary btn-lg start-button" type="button" data-qname="{{qname}}">Start</button> <button class="btn btn-primary btn-lg start-button" type="button" data-qname="{{qname}}">Start</button>
<button class="btn btn-danger btn-lg stop-button" type="button" data-qname="all">Stop</button> <button class="btn btn-danger btn-lg stop-button" type="button" data-qname="all">Stop</button><br />
<button class="btn btn-info btn-lg save-button" type="button" data-qname="{{qname}}">Save</button>
</p> </p>
</div> </div>
<div class="col-8"> <div class="col-8">
...@@ -39,8 +40,12 @@ ...@@ -39,8 +40,12 @@
<th>Client</th> <th>Client</th>
<th>Score</th> <th>Score</th>
</tr> </tr>
{% for v in qdata.answers %} {% for k, v in qdata.answers.items() %}
<tr> {% if qdata.best_json == k %}
<tr class="answer-detail-row submit-answer" data-json="{{k}}" data-qname="{{qname}}">
{% else %}
<tr class="answer-detail-row" data-json="{{k}}" data-qname="{{qname}}">
{% endif %}
<td>{{v.timestamp}}</td> <td>{{v.timestamp}}</td>
<td>{{v.solver}}</td> <td>{{v.solver}}</td>
<td>{{v.nlcheck}}</td> <td>{{v.nlcheck}}</td>
......
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