3D Cubes

basil.js, 3D, form, advanced, Law of Gestaltwechsel
Fabian Morón Zirfas

A basic 3D scene mapped from 2D

// @includepath "~/Documents/;%USERPROFILE%Documents"; // eslint-disable-line
// @include "basiljs/bundle/basil.js"; // eslint-disable-line
// based on this flash tutorial
//  Scripting 3D in Flash
//  by senocular
// https://www.kirupa.com/developer/actionscript/3dindex.htm
//
//  TODO: expolore the tutorial even more (e.g. camera)
//
var pw = 200; // for easier handling
var ph = 200; // for easier handling
// see https://en.wikipedia.org/wiki/Focal_length
var focalLength = 300;
var camera = {
  x: -100,
  y: -150,
  z: -400,
  rotation: 0
};
/**
 * creates a 3D point
 * @param  {Number} x the x location
 * @param  {Number} y the y location
 * @param  {Number} z the z location
 * @return {Object}   an Object with {x:Nmber, y:Number, z:Number}
 */
var point = function(x, y, z) {
  var p = {};
  p.x = x;
  p.y = y;
  p.z = z;
  return p;
};
/**
 * Converts a 3D point Object to screen coordiantes
 * @param  {Object} pointIn3D an Object created by the point function
 * @return {Object} an Object with {x:Number, y:Number}
 */
var toScreen = function(pointIn3D) {
  var pointIn2D = {};
  pointIn3D.x -= camera.x;
  pointIn3D.y -= camera.y;
  pointIn3D.z -= camera.z;
  var angle = Math.atan2(pointIn3D.z, pointIn3D.x);
  var radius = Math.sqrt(pointIn3D.x * pointIn3D.x + pointIn3D.z * pointIn3D.z);
  pointIn3D.x = Math.cos(angle + camera.rotation) * radius;
  pointIn3D.z = Math.sin(angle + camera.rotation) * radius;
  var scaleRatio = focalLength / (focalLength + pointIn3D.z);
  pointIn2D.x = pointIn3D.x * scaleRatio;
  pointIn2D.y = pointIn3D.y * scaleRatio;
  return pointIn2D;
};

function cube(x, y, z, w, h, d) {
  points3D = [
    point((-w / 2) + x, (-h / 2) + y, (-d) + z),
    point((w / 2) + x, (-h / 2) + y, (-d) + z),
    point((w / 2) + x, (-h / 2) + y, (d) + z),
    point((-w / 2) + x, (-h / 2) + y, (d) + z),
    point((-w / 2) + x, (h / 2) + y, (-d) + z),
    point((w / 2) + x, (h / 2) + y, (-d) + z),
    point((w / 2) + x, (h / 2) + y, (d) + z),
    point((-w / 2) + x, (h / 2) + y, (d) + z)
  ];
  var points2D = []; // will hold the 2D points
  // convert them from 3D to 2D
  for (var i = 0; i < points3D.length; i++) {
    var p = points3D[i];
    points2D[i] = toScreen(p);
  }
  var items = [];
  // top shape
  b.beginShape(b.CLOSE);
  b.vertex(points2D[0].x, points2D[0].y + (Math.random() * 10) - 10);
  // b.text('0',points2D[0].x, points2D[0].y,20,20);
  b.vertex(points2D[1].x, points2D[1].y + (Math.random() * 10) - 10);
  // b.text('1',points2D[1].x, points2D[1].y,20,20);
  b.vertex(points2D[2].x, points2D[2].y + (Math.random() * 10) - 10);
  // b.text('2',points2D[2].x, points2D[2].y,20,20);
  b.vertex(points2D[3].x, points2D[3].y + (Math.random() * 10) - 10);
  // b.text('3',points2D[3].x, points2D[3].y,20,20);
  var top = b.endShape();
  // draw the bottom plane
  b.beginShape(b.CLOSE);
  b.vertex(points2D[4].x, points2D[4].y);
  // b.text('4',points2D[4].x, points2D[4].y,20,20);
  b.vertex(points2D[5].x, points2D[5].y);
  // b.text('5',points2D[5].x, points2D[5].y,20,20);
  b.vertex(points2D[6].x, points2D[6].y);
  // b.text('6',points2D[6].x, points2D[6].y,20,20);
  b.vertex(points2D[7].x, points2D[7].y);
  // b.text('7',points2D[7].x, points2D[7].y,20,20);
  var bottom = b.endShape(); //
  // // front
  b.beginShape(b.CLOSE);
  b.vertex(points2D[0].x, points2D[0].y);
  b.vertex(points2D[1].x, points2D[1].y);
  b.vertex(points2D[5].x, points2D[5].y);
  b.vertex(points2D[4].x, points2D[4].y);
  var front = b.endShape(); //
  // // back
  b.beginShape(b.CLOSE);
  b.vertex(points2D[3].x, points2D[3].y);
  b.vertex(points2D[2].x, points2D[2].y);
  b.vertex(points2D[6].x, points2D[6].y);
  b.vertex(points2D[7].x, points2D[7].y);
  var back = b.endShape(); //
  // left
  b.beginShape(b.CLOSE);
  b.vertex(points2D[0].x, points2D[0].y);
  b.vertex(points2D[3].x, points2D[3].y);
  b.vertex(points2D[7].x, points2D[7].y);
  b.vertex(points2D[4].x, points2D[4].y);
  var left = b.endShape(); //
  // right
  b.beginShape(b.CLOSE);
  b.vertex(points2D[1].x, points2D[1].y);
  b.vertex(points2D[2].x, points2D[2].y);
  b.vertex(points2D[6].x, points2D[6].y);
  b.vertex(points2D[5].x, points2D[5].y);
  var right = b.endShape(); //
  front.bringToFront();
  top.sendToBack();
  bottom.sendToBack();
  left.sendToBack();
  right.sendToBack();
  back.sendToBack();
  return [top, bottom, front, back, left, right];
}

function axis() {
  var xplus3D = [point(0, 0, 0), point(200, 0, 0)];
  var xminus3D = [point(0, 0, 0), point(-200, 0, 0)];
  var yplus3D = [point(0, 0, 0), point(0, 200, 0)];
  var yminus3D = [point(0, 0, 0), point(0, -200, 0)];
  var zplus3D = [point(0, 0, 0), point(0, 0, 200)];
  var zminus3D = [point(0, 0, 0), point(0, 0, -200)];
  var convertToScreen = function(p3d) {
    var p2d = []; // will hold the 2D points
      // convert them from 3D to 2D
    for (var i = 0; i < p3d.length; i++) {
      var p = p3d[i];
      p2d[i] = toScreen(p);
    } // end loop
    return p2d;
  }; // end convert
  var xplus2D = convertToScreen(xplus3D);
  var xminus2D = convertToScreen(xminus3D);
  var yplus2D = convertToScreen(yplus3D);
  var yminus2D = convertToScreen(yminus3D);
  var zplus2D = convertToScreen(zplus3D);
  var zminus2D = convertToScreen(zminus3D);
  var line1 = b.line(xplus2D[0].x, xplus2D[0].y, xplus2D[1].x, xplus2D[1].y);
  var txt1 = b.text('+x', xplus2D[1].x, xplus2D[1].y, 20, 20);
  var line2 = b.line(xminus2D[0].x, xminus2D[0].y, xminus2D[1].x, xminus2D[1].y);
  var txt2 = b.text('-x', xminus2D[1].x, xminus2D[1].y, 20, 20);
  var line3 = b.line(yplus2D[0].x, yplus2D[0].y, yplus2D[1].x, yplus2D[1].y);
  var txt3 = b.text('+y', yplus2D[1].x, yplus2D[1].y, 20, 20);
  var line4 = b.line(yminus2D[0].x, yminus2D[0].y, yminus2D[1].x, yminus2D[1].y);
  var txt4 = b.text('-y', yminus2D[1].x, yminus2D[1].y, 20, 20);
  var line5 = b.line(zplus2D[0].x, zplus2D[0].y, zplus2D[1].x, zplus2D[1].y);
  var txt5 = b.text('+z', zplus2D[1].x, zplus2D[1].y, 20, 20);
  var line6 = b.line(zminus2D[0].x, zminus2D[0].y, zminus2D[1].x, zminus2D[1].y);
  var txt6 = b.text('-z', zminus2D[1].x, zminus2D[1].y, 20, 20);
  return [line1, line2, line3, line4, line5, line6, txt1, txt2, txt3, txt4, txt5, txt6];
}

function draw() {
  b.clear(b.doc()); // clear the current document
  b.units(b.MM); // we want to print. use MM instead of default pixels
  var doc = b.doc(); // a reference to the current document
  // set some preferneces of the document for better handling
  doc.documentPreferences.properties = {
    pageWidth: pw,
    pageHeight: ph
  }; // set the page size
  doc.viewPreferences.rulerOrigin = RulerOrigin.SPREAD_ORIGIN; // upper left corner
  // ----------
  // main code goes here
  // define some 3D points
  b.noFill();
  // var makeACube = function (x,y,z,w,h,d){
  // b.pushMatrix(); // push the matrix
  // b.translate(x, y); // to the center of the screen
  // var c = cube(x,y,z,w,h,d);
  // draw the top plane. Could also be a polygon
  // b.popMatrix();// reset the matrix
  // return c;
  // }
  // ~   b.pushMatrix(); // push the matrix
  // ~   b.translate(b.width/2, b.height/2); // to the center of the screen
  // ~   var planes = cube(50,100,100);
  // draw the top plane. Could also be a polygon
  // ~   b.popMatrix();// reset the matrix
  doc.pages[0].groups.add(cube(b.width / 2, b.height / 2, -200, 50, 50, 50));
  doc.pages[0].groups.add(cube(b.width / 2, -(b.height / 2), -200, 50, 50, 50));
  // doc.pages[0].groups.add(makeACube (b.width/4,b.height/2, 50,50,50));
  // doc.pages[0].groups.add(makeACube ((b.width/4)*3,b.height/2, 50,50,100));
  // b.pushMatrix();
  // b.translate(b.width/2,b.height/2);
  b.fill(0);
  doc.pages[0].groups.add(axis());
  // b.popMatrix();
  // ----------
  var fname = File($.fileName).parent.fsName + '/' + ($.fileName.split('/')[$.fileName.split('/').length - 1]).split('.')[0] + '.indd';
  // b.println(fname);
  doc.save(fname, false, 'basil', true);
  b.savePNG('out.png');
}
b.go();