<!DOCTYPE html> <meta charset="utf-8"> <style> .polygon { fill: none; stroke: #000; } </style> <body> <script src="https://d3js.org/d3.v3.min.js"></script> <script src='https://npmcdn.com/babel-core@5.8.34/browser.min.js'></script> <script src="obj_parse.js"></script> <script lang='babel' type='text/babel'> const width = 960; const height = 500; const margin = 20; const squareLength = d3.min([width, height]) - 2 * margin; const xScale = d3.scale.linear() .range([width / 2 - squareLength / 2, width / 2 + squareLength / 2]); const yScale = d3.scale.linear() .range([height / 2 + squareLength / 2, height / 2 - squareLength / 2]); const zScale = d3.scale.linear() .range([0, 1]); const camera = { inclination: Math.PI / 2, azimuth: 0, center: { x: 0, y: 0, z: 0 } }; let panMode = false; let surfaces; let obj; const zoom = d3.behavior.zoom() .scaleExtent([1, 10]) .on('zoom', zoomed); // eslint-disable-line const svg = d3.select('body').append('svg') .attr('width', width) .attr('height', height) .call(zoom); const container = svg.append('g'); function translatePT(pt, center) { return { x: pt.x - center.x, y: pt.y - center.y, z: pt.z - center.z }; } function rotatePT(pt, camera) { // eslint-disable-line // first rotate around y-axis to the azimuth angle const xp2 = pt.x * Math.cos(camera.azimuth) - pt.z * Math.sin(camera.azimuth); const zp2 = pt.x * Math.sin(camera.azimuth) + pt.z * Math.cos(camera.azimuth); // then around the x axis to pi/2 minus the inclination angle const a = Math.PI / 2 - camera.inclination; const zp3 = zp2 * Math.cos(a) - pt.y * Math.sin(a); const yp3 = zp2 * Math.sin(a) + pt.y * Math.cos(a); return { x: xp2, y: yp3, z: zp3 }; } function project_orthographic(surfaces, camera) { // eslint-disable-line surfaces.forEach(points => { points.forEach(point => { const pointT = translatePT(point, camera.center); const pointR = rotatePT(pointT, camera); point.px = pointR.x; point.py = pointR.y; point.pz = pointR.z; }); }); return surfaces; } function draw(surfaces) { // eslint-disable-line const polygons = container.selectAll('.polygon') .data(surfaces); polygons.enter().append('path') .attr('class', 'polygon'); polygons .attr('d', datum => { const d = datum.map(point => [xScale(point.px), yScale(point.py)]); return `M${d.join('L')}Z`; }) .attr('opacity', datum => { const d = datum.map(point => point.pz); return zScale(d3.max(d)); }); } function update(surfaces, camera) { // eslint-disable-line surfaces = project_orthographic(surfaces, camera); draw(surfaces); } let mousePanX = 0; let mousePanY = 0; let mouseRotX = 0; let mouseRotY = 0; let prevMouseX = 0; let prevMouseY = 0; let prevScale = 1; function zoomed() { const deltaX = d3.event.translate[0] - prevMouseX; const deltaY = d3.event.translate[1] - prevMouseY; prevMouseX = d3.event.translate[0]; prevMouseY = d3.event.translate[1]; if (d3.event.scale === prevScale) { if (panMode) { mousePanX += deltaX; mousePanY += deltaY; container.attr('transform', `'translate(${mousePanX}, ${mousePanY})`); } else { mouseRotX += deltaX; mouseRotY += deltaY; camera.inclination = Math.PI / 2 + mouseRotY / 500; camera.azimuth = -1 * mouseRotX / 500; } } else { xScale .range([width / 2 - d3.event.scale * squareLength / 2, width / 2 + d3.event.scale * squareLength / 2]); yScale .range([height / 2 + d3.event.scale * squareLength / 2, height / 2 - d3.event.scale * squareLength / 2]); prevScale = d3.event.scale; } // console.log('camera', camera); // console.log('xScale.range()', xScale.range()); // console.log('yScale.range()', yScale.range()); update(surfaces, camera); } function checkKeyDown(e) { const event = window.event ? window.event : e; if (event.keyCode === 32) { panMode = true; } } function checkKeyUp(e) { const event = window.event ? window.event : e; if (event.keyCode === 32) { panMode = false; } } document.onkeydown = checkKeyDown; document.onkeyup = checkKeyUp; // let surfaces; // let obj; d3.text('cessna.obj', (error, objFileText) => { if (error) throw error; obj = parse_obj_text(objFileText); // eslint-disable-line surfaces = obj.surfaces; const extreme = d3.max([Math.abs(obj.extents[0]), Math.abs(obj.extents[1])]); // set a custom starting position // by setting the properties of the camera object camera.center = { x: 1.0351724999999998, y: 0, z: 0 }; camera.azimuth = -1.046; camera.inclination = 1.9627963267948965; xScale.domain([-extreme, extreme]); yScale.domain([-extreme, extreme]); zScale.domain([-extreme, extreme]); // manually set the range of the // xScale and yScale as well xScale.range([25.05443972783297, 934.9455602721671]); yScale.range([704.9455602721671, -204.94556027216703]); update(surfaces, camera); }); </script>