Adaptation of code from Fran Armstrong's submisison in 2019.
-
-
Save dribnet/b0a6a211702c53ad9b371f820cac377b to your computer and use it in GitHub Desktop.
license: mit |
/* | |
* FaceMap class - holds all informaiton about one mapped | |
* face and is able to draw itself. | |
*/ | |
// other variables can be in here too | |
// these control the colors used | |
//COLOURS | |
const white = [225, 225, 225]; | |
const black = [0, 0, 0]; | |
const lightBlack = [40, 40, 40]; | |
//FACE COLOURS | |
const face1Main = "#ded1ca"; | |
const face1Detail = "#c7b2a7"; | |
const face2Main = "#c7ad9d"; | |
const face2Detail = "#9c8373"; | |
const face3Main = "#ab8a72"; | |
const face3Detail = "#8a6d5b"; | |
const face4Main = "#856a59"; | |
const face4Detail = "#594336"; | |
const face5Main = "#594844"; | |
const face5Detail = "#4a342c"; | |
//EAR COLOURS | |
const earGrey = "#abaaa9"; | |
const earLightBlonde = "#eddfc7"; | |
const earDarkBlonde = "#d1ab7d"; | |
const earRed = "#963917"; | |
const earLightBrown = "#9c785a"; | |
const earDarkBrown = "#572e1a"; | |
const earBlack = "#210c02"; | |
//EYES | |
const eyeDBrown = "#38220a"; | |
const eyeLBrown = "#b58c6e"; | |
const eyeGreen = "#739c60"; | |
const eyeBlue = "#6591b5"; | |
function Face() { | |
// these are state variables for a face | |
// (your variables may be different) | |
this.tilt_value = 0; // range is -30 to 30 | |
this.face_width = 0; | |
this.face_colour = 1; // range 1-5 | |
this.hair_style = 1; // hair length in middle of ear | |
this.ear_colour = 1; // 1= grey, 2 = lightBlonde, 3 = darkBlonde, 4 = red, 5 = lightBrown, 6= darkBrown, 7 = black; | |
this.eye_colour = 1; // 1= dark brown, 2 = light brown, 3 = green, 4 = blue | |
this.blush_value = 1; // 1 = true, 2 = false; | |
/* | |
* Draw a face with position lists that include: | |
* chin, right_eye, left_eye, right_eyebrow, left_eyebrow | |
* bottom_lip, top_lip, nose_tip, nose_bridge, | |
*/ | |
this.draw = function(positions) { | |
// SETUP | |
rectMode(CENTER); | |
ellipseMode(CENTER); | |
noStroke(); | |
rotate(this.tilt_value); | |
//******** POSITIONS ********/ | |
let left_eyebrow1 = positions.left_eyebrow[0]; | |
let right_eyebrow5 = positions.right_eyebrow[4]; | |
let left_eye = positions.left_eye[5]; | |
let right_eye = positions.right_eye[5]; | |
let bottom_lip = positions.bottom_lip[9]; | |
let top_lip1 = positions.top_lip[0]; | |
let top_lip2 = positions.top_lip[1]; | |
let top_lip3 = positions.top_lip[2]; | |
let top_lip4 = positions.top_lip[3]; | |
let top_lip5 = positions.top_lip[4]; | |
let top_lip6 = positions.top_lip[5]; | |
let top_lip7 = positions.top_lip[6]; | |
let top_lip8 = positions.top_lip[7]; | |
let top_lip9 = positions.top_lip[8]; | |
let top_lip10 = positions.top_lip[9]; | |
let top_lip11 = positions.top_lip[10]; | |
let top_lip12 = positions.top_lip[11]; | |
let nose_bridge4 = positions.nose_bridge[3]; | |
//***** HEAD ******/ | |
//Colours | |
let faceColour = face1Main; | |
let detailColour = face1Detail; | |
let hairColour = earBlack; | |
//Facial Colouring | |
if(this.face_colour == 1){ | |
faceColour = face1Main; | |
detailColour = face1Detail; | |
} | |
else if(this.face_colour == 2){ | |
faceColour = face2Main; | |
detailColour = face2Detail; | |
} | |
else if(this.face_colour == 3){ | |
faceColour = face3Main; | |
detailColour = face3Detail; | |
} | |
else if(this.face_colour == 4){ | |
faceColour = face4Main; | |
detailColour = face4Detail; | |
} | |
else if(this.face_colour == 5){ | |
faceColour = face5Main; | |
detailColour = face5Detail; | |
} | |
//Ear/Hair Colouring | |
if(this.ear_colour == 1){ | |
hairColour = earGrey; | |
} | |
else if(this.ear_colour == 2){ | |
hairColour = earLightBlonde; | |
} | |
else if(this.ear_colour == 3){ | |
hairColour = earDarkBlonde; | |
} | |
else if(this.ear_colour == 4){ | |
hairColour = earRed; | |
} | |
else if(this.ear_colour == 5){ | |
hairColour = earLightBrown; | |
} | |
else if(this.ear_colour == 6){ | |
hairColour = earDarkBrown; | |
} | |
else if(this.ear_colour == 7){ | |
hairColour = earBlack; | |
} | |
//Ears | |
this.drawEars(detailColour, hairColour, left_eyebrow1[0], right_eyebrow5[0], left_eyebrow1[1], right_eyebrow5[1]); | |
//Hair in the Middle | |
this.drawHair(hairColour, this.hair_style); | |
//Face | |
fill(faceColour); | |
rect(0,0,this.face_width,4, 20); | |
//******** EYES - LEFT EYE, RIGHT EYE ******/ | |
if(this.eye_colour == 1){ | |
this.drawEyes(detailColour, eyeDBrown, left_eye[0], left_eye[1], right_eye[0], right_eye[1]); | |
} | |
else if(this.eye_colour == 2){ | |
this.drawEyes(detailColour, eyeLBrown, left_eye[0], left_eye[1], right_eye[0], right_eye[1]); | |
} | |
else if(this.eye_colour == 3){ | |
this.drawEyes(detailColour, eyeGreen, left_eye[0], left_eye[1], right_eye[0], right_eye[1]); | |
} | |
else if(this.eye_colour == 4){ | |
this.drawEyes(detailColour, eyeBlue, left_eye[0], left_eye[1], right_eye[0], right_eye[1]); | |
} | |
//******** MOUTH - BOTTOM LIP, TOP LIP & NOSE - NOSE TIP, NOSE BRIDGE*********/ | |
//OuterMouth | |
fill(detailColour); | |
ellipse(top_lip4[0], top_lip4[1]+0.2, 2.3, 2); | |
//BottomLip | |
fill("#ad8e8e"); | |
beginShape(); | |
curveVertex(top_lip2[0], top_lip2[1]); | |
curveVertex(top_lip4[0], top_lip4[1]); | |
curveVertex(top_lip6[0], top_lip6[1]); | |
curveVertex(bottom_lip[0] + 0.4, bottom_lip[1]); | |
curveVertex(bottom_lip[0], bottom_lip[1]); | |
curveVertex(bottom_lip[0] - 0.4, bottom_lip[1]); | |
endShape(CLOSE); | |
stroke(black); | |
strokeCap(SQUARE); | |
strokeWeight(0.08); | |
noFill(); | |
beginShape(); | |
curveVertex(top_lip2[0], top_lip2[1] + 0.05); | |
curveVertex(top_lip2[0], top_lip2[1]+ 0.05); | |
curveVertex(bottom_lip[0] - 0.4, bottom_lip[1]-0.05); | |
curveVertex(bottom_lip[0], bottom_lip[1]); | |
curveVertex(bottom_lip[0] + 0.4, bottom_lip[1]-0.05); | |
curveVertex(top_lip6[0], top_lip6[1]+0.05); | |
curveVertex(top_lip6[0], top_lip6[1]+0.05); | |
endShape(); | |
noStroke(); | |
//TopLip | |
fill(black); | |
beginShape(); | |
curveVertex(top_lip1[0], top_lip1[1]); | |
curveVertex(top_lip2[0], top_lip2[1]); | |
curveVertex(top_lip3[0], top_lip3[1]); | |
curveVertex(top_lip4[0], top_lip4[1]); | |
curveVertex(top_lip5[0], top_lip5[1]); | |
curveVertex(top_lip6[0], top_lip6[1]); | |
curveVertex(top_lip7[0], top_lip7[1]); | |
curveVertex(top_lip8[0], top_lip8[1]); | |
curveVertex(top_lip9[0], top_lip9[1]); | |
curveVertex(top_lip10[0], top_lip10[1]); | |
curveVertex(top_lip11[0], top_lip11[1]); | |
curveVertex(top_lip12[0], top_lip12[1]); | |
curveVertex(top_lip1[0], top_lip1[1]); | |
curveVertex(top_lip2[0], top_lip2[1]); | |
endShape(); | |
//Blush | |
if(this.blush_value == 1){ | |
fill(255, 48, 93, 75); | |
ellipse(top_lip1[0]-0.25, top_lip1[1], 0.75); | |
ellipse(top_lip7[0] + 0.25, top_lip7[1], 0.75); | |
} | |
//Nose | |
stroke(black); | |
strokeWeight(0.15); | |
strokeCap(SQUARE); | |
noFill(); | |
line(nose_bridge4[0], nose_bridge4[1], top_lip4[0], top_lip4[1]); | |
noStroke(); | |
fill(black); | |
ellipse(nose_bridge4[0], nose_bridge4[1], 0.6, 0.4); | |
fill(30); | |
ellipse(nose_bridge4[0], nose_bridge4[1], 0.3, 0.2); | |
fill(175); | |
ellipse(nose_bridge4[0]+0.125, nose_bridge4[1]-0.1, 0.075, 0.05); | |
} | |
//****** OBJECTS FUNCTIONS FOR FACIAL FEATURES ****/ | |
//Ears | |
this.drawEars = function(detail, hair, lx, rx, ly, ry){ | |
fill(detail); | |
ellipse(lx+0.25, ly, 2, 2); | |
ellipse(rx-0.25, ry, 2, 2); | |
//left_ear floofs | |
beginShape(); | |
vertex(lx, ly); | |
vertex(lx, ly-0.7); | |
vertex(lx-1, ly-0.6); | |
endShape(CLOSE); | |
beginShape(); | |
vertex(lx, ry-0.3); | |
vertex(lx , ry-0.9); | |
vertex(lx-1, ry-0.9); | |
endShape(CLOSE); | |
//right_ear floofs | |
beginShape(); | |
vertex(rx, ry); | |
vertex(rx, ry-0.7); | |
vertex(rx+1, ry-0.6); | |
endShape(CLOSE) | |
beginShape(); | |
vertex(rx, ry-0.3); | |
vertex(rx , ry-0.95); | |
vertex(rx+0.75, ry-0.9); | |
endShape(CLOSE); | |
fill(hair); | |
ellipse(lx+0.25, ly, 1.5, 1.5); | |
ellipse(rx-0.25, ry, 1.5, 1.5); | |
} | |
//Eyes | |
this.drawEyes = function(detail, eye, lx, ly, rx, ry){ | |
//EYE PATCHES | |
//LeftEyePatch | |
fill(detail); | |
beginShape(); | |
curveVertex(lx + 0.65, ly); | |
curveVertex(lx + 0.65, ly + 0.3); | |
curveVertex(lx - 0.2, ly + 0.8); | |
curveVertex(lx - 0.7, ly + 0.3); | |
curveVertex(lx - 0.3, ly - 0.5); | |
curveVertex(lx + 0.5, ly - 0.5); | |
endShape(CLOSE); | |
//RightEyePatch | |
beginShape(); | |
curveVertex(rx - 0.65, ry); | |
curveVertex(rx - 0.65, ry + 0.3); | |
curveVertex(rx + 0.2, ry + 0.8); | |
curveVertex(rx + 0.7, ry + 0.3); | |
curveVertex(rx + 0.3, ry - 0.5); | |
curveVertex(rx - 0.5, ry - 0.5); | |
endShape(CLOSE); | |
//EyeBalls | |
fill(eye); | |
ellipse(lx, ly, 0.55, 0.55); | |
ellipse(rx, ry, 0.55, 0.55); | |
fill(100); | |
ellipse(lx, ly, 0.48, 0.48); | |
ellipse(rx, ry, 0.48, 0.48); | |
fill(black); | |
ellipse(lx, ly, 0.4, 0.4); | |
ellipse(rx, ry, 0.4, 0.4); | |
fill(175); | |
ellipse(lx +0.075, ly-0.075, 0.08, 0.05); | |
ellipse(rx +0.075, ry-0.075, 0.08, 0.05); | |
} | |
//Hair | |
this.drawHair = function(hair, length){ | |
fill(hair); | |
beginShape(); | |
vertex(-0.25, -1.5); | |
vertex(0.25, -1.5); | |
vertex(0, -2*length); | |
endShape(CLOSE); | |
beginShape(); | |
vertex(-0.22, -1.5); | |
vertex(0.22, -1.5); | |
vertex(-0.25 - (0.1*length), -1.85*length); | |
endShape(CLOSE); | |
beginShape(); | |
vertex(-0.2, -1.5); | |
vertex(0.2, -1.5); | |
vertex(0.25 + (0.1*length), -1.8*length); | |
endShape(CLOSE); | |
} | |
/* set internal properties based on list numbers 0-100 */ | |
this.setProperties = function(settings) { | |
//this.eye_value = int(map(settings[0], 0, 100, 2, 3)); | |
//TiltValue | |
this.tilt_value = map(settings[0], 0, 100, -30, 30); | |
//FACE SHAPE | |
this.face_width = map(settings[1], 0, 100, 3.6, 4); | |
//FACE COLOUR | |
this.face_colour = int(map(settings[2], 0, 100, 1, 5)); | |
//EARS | |
this.hair_style = map(settings[3], 0, 100, 1, 1.2); | |
//EAR COLOUR | |
this.ear_colour = int(map(settings[4], 0, 100, 1, 7)); | |
//EYE COLOUR - brown, light brown, green, blue | |
this.eye_colour = int(map(settings[5], 0, 100, 1, 4)); | |
// BLUSH | |
this.blush_value = int(map(settings[6], 0, 100, 1, 2)); | |
} | |
/* get internal properties as list of numbers 0-100 */ | |
this.getProperties = function() { | |
let settings = new Array(7); | |
settings[0] = map(this.tilt_value, -30, 30, 0, 100); | |
settings[1] = map(this.face_width, 3.6, 4, 0, 100); | |
settings[2] = map(this.face_colour, 1, 5, 0, 100); | |
settings[3] = map(this.hair_style, 1, 1.2, 0, 100); | |
settings[4] = map(this.ear_colour, 1, 7, 0, 100); | |
settings[5] = map(this.eye_colour, 1, 4, 0, 100); | |
settings[6] = map(this.blush_value, 1, 2, 0, 100); | |
return settings; | |
} | |
} | |
//given an array of [x,y] points, return the average | |
function average_point(list){ | |
var sum_x = 0; | |
var sum_y = 0; | |
var num_points = 0; | |
for(var i = 0; i<list.length; i++){ | |
sum_x += list[i][0]; | |
sum_y += list[i][1]; | |
num_points +- 1; | |
} | |
return [sum_x / num_points, sum_y /num_points]; | |
} | |
<head> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.3/seedrandom.min.js"></script> | |
<script src="https://d3js.org/d3-random.v1.min.js"></script> | |
<script src="z_clmtrackr.js"></script> | |
<script src="z_model_pca_20_svm.js"></script> | |
<script language="javascript" type="text/javascript" src="z_purview_helper.js"></script> | |
<script language="javascript" type="text/javascript" src="z_focused_random.js"></script> | |
<script language="javascript" type="text/javascript" src="z_face_system.js"></script> | |
<script language="javascript" type="text/javascript" src="z_kdTree.js"></script> | |
<script language="javascript" type="text/javascript" src="z_face-api.js"></script> | |
<script language="javascript" type="text/javascript" src="z_training_images.js"></script> | |
<script language="javascript" type="text/javascript" src="z_testing_images.js"></script> | |
<script language="javascript" type="text/javascript" src="face.js"></script> | |
<script language="javascript" type="text/javascript" src="system_runner.js"></script> | |
<style> | |
body { padding: 0; margin: 0; } | |
.inner { position: absolute; } | |
#controls { | |
font: 300 12px "Helvetica Neue"; | |
padding: 5; | |
margin: 5; | |
background: #f0f0f0; | |
opacity: 0.0; | |
-webkit-transition: opacity 0.2s ease; | |
-moz-transition: opacity 0.2s ease; | |
-o-transition: opacity 0.2s ease; | |
-ms-transition: opacity 0.2s ease; | |
} | |
#controls:hover { opacity: 0.9; } | |
</style> | |
</head> | |
<body style="background-color:white"> | |
<div class="outer"> | |
<div class="inner" id="controls" height="500"> | |
<table> | |
<tr> | |
<td>setting 1</td> | |
<td id="slider1Container"></td> | |
</tr> | |
<tr> | |
<td>setting 2</td> | |
<td id="slider2Container"></td> | |
</tr> | |
<tr> | |
<td>setting 3</td> | |
<td id="slider3Container"></td> | |
</tr> | |
<tr> | |
<td>setting 4</td> | |
<td id="slider4Container"></td> | |
</tr> | |
<tr> | |
<td>setting 5</td> | |
<td id="slider5Container"></td> | |
</tr> | |
<tr> | |
<td>setting 6</td> | |
<td id="slider6Container"></td> | |
</tr> | |
<tr> | |
<td>setting 7</td> | |
<td id="slider7Container"></td> | |
</tr> | |
<tr> | |
<td>setting 8</td> | |
<td id="slider8Container"></td> | |
</tr> | |
<tr> | |
<td>setting 9</td> | |
<td id="slider9Container"></td> | |
</tr> | |
<tr> | |
<td>setting 10</td> | |
<td id="slider10Container"></td> | |
</tr> | |
<tr> | |
<td>setting 11</td> | |
<td id="slider11Container"></td> | |
</tr> | |
<tr> | |
<td>setting 12</td> | |
<td id="slider12Container"></td> | |
</tr> | |
<tr> | |
</tr> | |
<tr> | |
<td>show target</td> | |
<td id="sliderTintContainer"></td> | |
</tr> | |
<tr> | |
<td>Draw function</td> | |
<td id="selector1Container"></td> | |
</tr> | |
<tr> | |
<td>Face Draw</td> | |
<td id="checkbox1Container"></td> | |
</tr> | |
<tr> | |
<td>Face Targets</td> | |
<td id="checkbox2Container"></td> | |
</tr> | |
<tr> | |
<td>Face Points</td> | |
<td id="checkbox3Container"></td> | |
</tr> | |
<tr> | |
<td></td> | |
<td id="button1Container"></td> | |
</tr> | |
<tr> | |
<td></td> | |
<td id="button2Container"></td> | |
</tr> | |
<tr> | |
<td></td> | |
<td id="button3Container"></td> | |
</tr> | |
<tr> | |
<td></td> | |
<td id="button4Container"></td> | |
</tr> | |
</table> | |
</div> | |
<div> | |
<div id="canvasContainer"></div> | |
<a href="face.js">face code</a><br> | |
<a href="sketch.html">sketches</a> | |
</div> | |
</div> | |
<pre> | |
<p id="output"> | |
</p> | |
</pre> | |
</body> |
[ | |
"williams.jpg", | |
"oscar_selfie.jpg" | |
] |
<head> | |
<style> body {padding: 0; margin: 0;} </style> | |
</head> | |
<body style="background-color:white"> | |
<img src="same_pose.jpg" width="960" height="500"/><br> | |
Same Pose | |
<hr> | |
<img src="same_subject.jpg" width="960" height="500"/><br> | |
Same Subject | |
<p> | |
<a href="index.html">program</a> | |
</body> |
// recent work from my @VicUniWgtn 3rd year media design students that combines @nulhom's dlib face library with @p5xjs | |
var canvasWidth = 960; | |
var canvasHeight = 500; | |
var button; | |
var curRandomSeed; | |
var mainFace; | |
var faceImages = []; | |
var curFaceIndex = 0; | |
var curTrainIndex = 0; | |
var curValidIndex = 0; | |
var main_canvas; | |
var video_buffer; | |
var faceSelector; | |
var drawFaceCheckbox; | |
var faceGuideCheckbox; | |
var facePointsCheckbox; | |
var sliders = []; | |
var NUM_SLIDERS = 12; | |
var sliderTint; | |
var trainDataKeys = [] | |
var trainValues = {} | |
var validDataKeys = [] | |
var faceMapping = null; | |
let model_loaded = false; | |
let faces_processing = false; | |
let faces_processed = false; | |
var sample_images; | |
var selfieData = [] | |
var video_capture = null; | |
async function preload () { | |
sample_images = loadJSON('sample_images.json') | |
trainValues = loadJSON('training_values.json'); | |
await faceapi.loadSsdMobilenetv1Model("./"); | |
await faceapi.loadFaceLandmarkModel("./"); | |
await faceapi.loadFaceRecognitionModel("./"); | |
model_loaded = true; | |
} | |
var allEmbeddingsTree; | |
var allEmbeddings = []; | |
var embeddingDimensions; | |
var curNeighbors = []; | |
function squaredDistance(a, b) { | |
var sum = 0; | |
var length = 128; | |
for(var i=0; i<128; i++) { | |
var diff = a[i] - b[i]; | |
sum += diff * diff; | |
} | |
// print(a.length,diff); | |
// print(sum, a==b); | |
return sum; | |
} | |
var haveStarted = false; | |
function setup () { | |
let keys = Object.keys(sample_images); | |
for (let i=0; i<keys.length; i++) { | |
let obj = {}; | |
obj.url = sample_images[keys[i]]; | |
selfieData.push(obj); | |
} | |
// create the drawing canvas, save the canvas element | |
main_canvas = createCanvas(canvasWidth, canvasHeight); | |
main_canvas.parent('canvasContainer'); | |
curRandomSeed = int(focusedRandom(0, 100)); | |
mainFace = new Face(); | |
littleFace = new Face(); | |
for(var i=0; i<selfieData.length; i++) { | |
var data = selfieData[i]; | |
data.image = loadImage(data.url); | |
} | |
trainDataKeys = Object.keys(trainData); | |
for(var i=0; i<trainDataKeys.length; i++) { | |
var curKey = trainDataKeys[i]; | |
var data = trainData[curKey]; | |
var curEmbedding = data.embedding[0]; | |
if(curEmbedding.length == 128) { | |
curEmbedding.push(curKey); | |
allEmbeddings.push(curEmbedding); | |
} | |
else { | |
print("rejected embedding ", curEmbedding.length, curEmbedding); | |
} | |
data.image = loadImage(data.url); | |
} | |
validDataKeys = Object.keys(validData); | |
for(var i=0; i<validDataKeys.length; i++) { | |
var curKey = validDataKeys[i]; | |
var data = validData[curKey]; | |
data.image = loadImage(data.url); | |
} | |
// print("Length: ", allEmbeddings.length); | |
// setup k-d tree | |
var N = allEmbeddings[0].length - 1; | |
embeddingDimensions = Array.apply(null, {length: N}).map(Number.call, Number); | |
// print(embeddingDimensions) | |
allEmbeddingsTree = new kdTree(allEmbeddings, squaredDistance, embeddingDimensions); | |
// print(allEmbeddingsTree) | |
faceSelector = createSelect(); | |
faceSelector.option('Faces'); | |
faceSelector.option('Train'); | |
faceSelector.option('NearestNeighbors'); | |
faceSelector.option('TrainingQuiz'); | |
faceSelector.option('InterpolationQuiz'); | |
faceSelector.option('Video'); | |
faceSelector.value('Faces'); | |
faceSelector.parent('selector1Container'); | |
/* create the sliders */ | |
for(i=1; i<=NUM_SLIDERS; i++) { | |
var slider = createSlider(0, 100, 50); | |
var parentStr = 'slider' + i + 'Container'; | |
slider.parent(parentStr); | |
sliders.push(slider); | |
} | |
drawFaceCheckbox = createCheckbox('', true); | |
drawFaceCheckbox.parent('checkbox1Container'); | |
faceGuideCheckbox = createCheckbox('', false); | |
faceGuideCheckbox.parent('checkbox2Container'); | |
facePointsCheckbox = createCheckbox('', false); | |
facePointsCheckbox.parent('checkbox3Container'); | |
sliderTint = createSlider(0, 100, 10); | |
sliderTint.parent("sliderTintContainer"); | |
/* and the buttons */ | |
var loadButton = createButton('load'); | |
loadButton.mousePressed(loadCurrentSettings); | |
loadButton.parent('button1Container'); | |
var interpButton = createButton('interpolate'); | |
interpButton.mousePressed(interpolateCurrent); | |
interpButton.parent('button1Container'); | |
var saveButton = createButton('save'); | |
saveButton.mousePressed(saveCurrentSettings); | |
saveButton.parent('button2Container'); | |
var getValuesButton = createButton('get values'); | |
getValuesButton.mousePressed(getSingleJson); | |
getValuesButton.parent('button3Container'); | |
var randButton = createButton('get all values'); | |
randButton.mousePressed(getAllJson); | |
randButton.parent('button4Container'); | |
updateSlidersForTraining(); | |
// rotation in degrees | |
angleMode(DEGREES); | |
background(255); | |
fill(0); | |
textSize(50); | |
textAlign(CENTER); | |
text("(waiting for models to load...)", width/2, height/2); | |
haveStarted = true; | |
} | |
function saveCurrentSettings() { | |
var curKey = trainDataKeys[curTrainIndex]; | |
obj = mainFace.getProperties(); | |
trainValues[curKey] = obj; | |
// for(var i=0; i<obj.length; i++) { | |
// trainData[curKey][i] = obj[i]; | |
// } | |
var text = select('#output'); | |
text.html("Storing values for " + curKey); | |
// getAllJson(); | |
} | |
function getSingleJson() { | |
obj = mainFace.getProperties(); | |
var text = select('#output'); | |
var json = JSON.stringify(obj, null, 2); | |
text.html(json) | |
} | |
function getAllJson() { | |
obj = trainValues; | |
var text = select('#output'); | |
var json = JSON.stringify(obj, null, 2); | |
// alert(json); | |
text.html(json) | |
} | |
// global variables for colors | |
var bg_color1 = [50, 50, 50]; | |
var lastSwapTime = 0; | |
var millisPerSwap = 5000; | |
function changeRandomSeed() { | |
curRandomSeed = curRandomSeed + 1; | |
lastSwapTime = millis(); | |
} | |
function mouseClicked() { | |
// changeRandomSeed(); | |
} | |
var quiz_done = true; | |
var guessed_answer = 0; | |
function num_dist(e1, e2) { | |
let dist = 0; | |
for(let i=0; i<e1.length; i++) { | |
print(i, e1[i], e2[i]); | |
dist = dist + Math.abs(e1[i] - e2[i]); | |
} | |
return dist; | |
} | |
var processing_vid_face = false; | |
var lastProcessedVidFace = null; | |
async function draw () { | |
if (!model_loaded) { | |
return; | |
} | |
if (!faces_processing) { | |
faces_processing = true; | |
background(255); | |
fill(0); | |
textSize(50); | |
textAlign(CENTER); | |
text("(processing faces...)", width/2, height/2); | |
for(var i=0; i<selfieData.length; i++) { | |
var data = selfieData[i]; | |
let fullFaceDescriptions = await faceapi.detectAllFaces(data.image.canvas).withFaceLandmarks().withFaceDescriptors(); | |
data.landmarks = get_landmarks(fullFaceDescriptions); | |
data.embedding = get_latents(fullFaceDescriptions); | |
} | |
// print("Some distances") | |
// var data = selfieData[0]; | |
// for(var i=0; i<data.landmarks.length; i++) { | |
// for(var j=0; j<data.landmarks.length; j++) { | |
// print("dist ", i, "old to ", j, " new -> ", num_dist(data.embedding[i], data.latents[j])); | |
// } | |
// } | |
faces_processed = true; | |
return; | |
} | |
if(!faces_processed) { | |
return; | |
} | |
var mode = faceSelector.value(); | |
if(millis() > lastSwapTime + millisPerSwap) { | |
lastSwapTime = millis(); | |
// changeRandomSeed(); | |
} | |
resetFocusedRandom(curRandomSeed); | |
noStroke(); | |
var textDisplay = "unknown"; | |
var params = []; | |
for(var i=0; i<NUM_SLIDERS; i++) { | |
params.push(sliders[i].value()); | |
} | |
if (mode == 'Faces' || mode == 'FacePair' || mode == 'Train' || mode == 'Video') { | |
var do_train = (mode == 'Train'); | |
var is_face = (mode == 'Faces'); | |
var is_video = (mode == 'Video'); | |
var show_face_guide = faceGuideCheckbox.checked(); | |
var show_face_points = facePointsCheckbox.checked(); | |
var do_draw_face = drawFaceCheckbox.checked(); | |
if(do_train) { | |
// var keys = Object.keys(trainData); | |
var curKey = trainDataKeys[curTrainIndex]; | |
var data = trainData[curKey]; | |
} | |
else { | |
var data = selfieData[curFaceIndex]; | |
} | |
const v_w = 640; | |
const v_h = 480; | |
const v_w_p = v_w / this._pixelDensity; | |
const v_h_p = v_h / this._pixelDensity; | |
// setup "video image" if in video mode | |
if (is_video) { | |
if (video_capture == null) { | |
video_capture = createCapture(VIDEO); | |
video_capture.size(canvasWidth, canvasHeight); | |
video_buffer = createGraphics(v_w, v_h); | |
return; | |
} | |
// print(processing_vid_face); | |
if(processing_vid_face == false) { | |
video_buffer.image(video_capture, 0, 0, v_w_p, v_h_p); | |
// print("grabbing video"); | |
processing_vid_face = true; | |
lastProcessedVidFace = await faceapi.detectAllFaces(video_buffer.canvas).withFaceLandmarks().withFaceDescriptors(); | |
processing_vid_face = false; | |
// print("grabbed video"); | |
return; | |
} | |
if (lastProcessedVidFace == null) { | |
background(255); | |
fill(0); | |
textSize(50); | |
textAlign(CENTER); | |
text("(setting up camera...)", width/2, height/2); | |
return | |
} | |
data = {}; | |
data["image"] = video_buffer; | |
data["landmarks"] = get_landmarks(lastProcessedVidFace); | |
data["embedding"] = get_latents(lastProcessedVidFace); | |
// print("Found faces: ", data.landmarks.length) | |
} | |
// we are not bailing, draw background | |
background(bg_color1); | |
// Displays the image at its actual size at point (0,0) | |
var img = data.image | |
if (is_face) { | |
x2 = 0; | |
y1 = 0; | |
x1 = 0; | |
var im_w = canvasWidth; | |
var im_h = canvasHeight; | |
var rect_w = canvasWidth; | |
var rect_h = canvasHeight; | |
image(img, x2, y1, im_w, im_h); | |
} | |
else if(is_video) { | |
// let vw = video_capture.elt.videoWidth; | |
// let vh = video_capture.elt.videoHeight; | |
// x2 = 0; | |
// y1 = 0; | |
// x1 = 0; | |
x1 = (canvasWidth - v_w) / 2.0; | |
x2 = x1; | |
y1 = (canvasHeight - v_h) / 2.0; | |
var im_w = v_w; | |
var im_h = v_h; | |
var rect_w = v_w; | |
var rect_h = v_h; | |
// print(im_w, im_h); | |
image(img, x2, y1, im_w, im_h, 0, 0, v_w_p, v_h_p); | |
} | |
else { | |
var x1 = (width/4-400/2); | |
var x2 = (3*width/4-400/2); | |
var y1 = (height/2-400/2); | |
var rect_w = 400; | |
var rect_h = 400; | |
var im_w = 400; | |
var im_h = 400; | |
image(img, x1, y1, 400, 400); | |
} | |
if(do_train) { | |
if (curKey in trainValues) { | |
fill(0, 200, 0); | |
} | |
else { | |
fill(200, 0, 0); | |
} | |
ellipse(x1+400/2, y1+400+15, 10, 10); | |
} | |
noStroke(); | |
var curSliderTintValue = sliderTint.value(); | |
var overlayAlpha = map(curSliderTintValue, 0, 100, 255, 0); | |
fill(bg_color1[0], bg_color1[1], bg_color1[2], overlayAlpha); | |
rect(x2, y1, rect_w, rect_h); | |
stroke(0); | |
fill(255); | |
for(var i=0; i<data.landmarks.length; i++) { | |
// get array of face marker positions [x, y] format | |
var positions = data.landmarks[i]; | |
var shifted_positions = JSON.parse(JSON.stringify(positions)) | |
var data_mean = [0.0, 0.0]; | |
var data_scale = 1.0; | |
var data_angle = 0.0; | |
if ('transform' in positions) { | |
data_mean = positions.transform.center; | |
data_scale = positions.transform.scale; | |
data_angle = positions.transform.angle; | |
delete shifted_positions.transform | |
} | |
var scale_x = im_w / img.width; | |
var scale_y = im_h / img.height; | |
push(); | |
translate(x1, y1) | |
translate(scale_x*data_mean[0], scale_y*data_mean[1]); | |
scale(scale_x*data_scale, scale_y*data_scale); | |
rotate(degrees(data_angle)); | |
stroke(0); | |
fill(255); | |
strokeWeight(1/data_scale); | |
Object.keys(positions).forEach(function(key) { | |
if (key=='transform') { | |
return; | |
} | |
var curSection = positions[key]; | |
var shiftedSection = shifted_positions[key]; | |
for (var i=0; i<curSection.length; i++) { | |
var cur_x = curSection[i][0]; | |
var cur_y = curSection[i][1]; | |
if (show_face_points) { | |
ellipse(cur_x, cur_y, 5/data_scale, 5/data_scale); | |
} | |
// get ready for drawing the face | |
shiftedSection[i][0] = cur_x; | |
shiftedSection[i][1] = cur_y; | |
} | |
}); | |
noFill(); | |
if(show_face_guide) { | |
stroke(0, 0, 255); | |
ellipse(0, 0, 4, 4); | |
line(0, -2, 0, 2); | |
line(-2, 0, 2, 0); | |
} | |
// ellipse(x1+data_mean[0], y1+data_mean[1], 4*data_scale, 4*data_scale); | |
// line(x1+data_mean[0], y1+data_mean[1]-2*data_scale, x1+data_mean[0], y1+data_mean[1]+2*data_scale); | |
pop(); | |
var settings = params; | |
if (Object.keys(trainValues).length > 0) { | |
// NOT NOW | |
if ((typeof data.embedding !== 'undefined') && | |
(data.embedding != null) && | |
(data.embedding.length > i) && | |
(data.embedding[i] != null) && | |
(typeof data.embedding[i].length !== 'undefined') && | |
(data.embedding[i].length == 128)) { | |
// print("Using embedding ", i) | |
var curEmbedding = data.embedding[i]; | |
results = getAverageSettingsFrom(curEmbedding); | |
settings = results[0]; | |
} | |
} | |
push(); | |
translate(x2, y1) | |
translate(scale_x*data_mean[0], scale_y*data_mean[1]); | |
scale(scale_x*data_scale, scale_y*data_scale); | |
rotate(degrees(data_angle)); | |
strokeWeight(1/data_scale); | |
mainFace.setProperties(settings); | |
if (do_draw_face) { | |
mainFace.draw(shifted_positions); | |
} | |
pop(); | |
} | |
if(do_train) { | |
textDisplay = "Train: " + curKey; | |
} | |
else { | |
textDisplay = ""; | |
} | |
} | |
else if (mode == 'NearestNeighbors') { | |
background(bg_color1); | |
// var keys = Object.keys(trainData); | |
var curKey = trainDataKeys[curTrainIndex]; | |
var data = trainData[curKey]; | |
// Displays the image at its actual size at point (0,0) | |
var img = data.image | |
var x1 = (width/4-250/2); | |
var y1 = (height/3-250/2); | |
image(img, x1, y1, 250, 250); | |
if (curKey in trainValues) { | |
fill(0, 200, 0); | |
} | |
else { | |
fill(200, 0, 0); | |
} | |
ellipse(x1+250/2, y1+250+15, 10, 10); | |
var y2 = (3*height/4-80/2); | |
for(var i=0; i<4; i++) { | |
// var keys = Object.keys(trainData); | |
var curKey = curNeighbors[i]; | |
var nearData = trainData[curKey]; | |
// Displays the image at its actual size at point (0,0) | |
var img = nearData.image | |
var x2 = (width/4 - 200 + i*100); | |
image(img, x2, y2, 80, 80); | |
} | |
for(var i=0; i<1; i++) { | |
// get array of face marker positions [x, y] format | |
var positions = data.landmarks[i]; | |
var shifted_positions = JSON.parse(JSON.stringify(positions)) | |
var data_mean = [0.0, 0.0]; | |
var data_scale = 1.0; | |
var data_angle = 0.0; | |
if ('transform' in positions) { | |
data_mean = positions.transform.center; | |
data_scale = positions.transform.scale; | |
data_angle = positions.transform.angle; | |
delete shifted_positions.transform | |
} | |
var scale_x = 400.0 / img.width; | |
var scale_y = 400.0 / img.height; | |
Object.keys(positions).forEach(function(key) { | |
if (key=='transform') { | |
return; | |
} | |
var curSection = positions[key]; | |
var shiftedSection = shifted_positions[key]; | |
for (var i=0; i<curSection.length; i++) { | |
var cur_x = curSection[i][0]; | |
var cur_y = curSection[i][1]; | |
// get ready for drawing the face | |
shiftedSection[i][0] = cur_x; | |
shiftedSection[i][1] = cur_y; | |
} | |
}); | |
var scale_x = 250.0 / img.width; | |
var scale_y = 250.0 / img.height; | |
var x2 = (3*width/4-250/2); | |
push(); | |
translate(x2, y1); | |
translate(scale_x*data_mean[0], scale_y*data_mean[1]); | |
scale(scale_x*data_scale, scale_y*data_scale); | |
rotate(degrees(data_angle)); | |
strokeWeight(1/data_scale); | |
mainFace.setProperties(params); | |
mainFace.draw(shifted_positions); | |
pop(); | |
var scale_x = 80.0 / img.width; | |
var scale_y = 80.0 / img.height; | |
for(var j=0; j<4; j++) { | |
// var keys = Object.keys(trainData); | |
var curKey = curNeighbors[j]; | |
var x2 = (3*width/4 - 200 + j*100); | |
push(); | |
translate(x2, y2); | |
if (curKey in trainValues) { | |
var settings = trainValues[curKey] | |
translate(scale_x*data_mean[0], scale_y*data_mean[1]); | |
scale(scale_x*data_scale, scale_y*data_scale); | |
rotate(degrees(data_angle)); | |
strokeWeight(1/data_scale); | |
littleFace.setProperties(settings); | |
littleFace.draw(shifted_positions); | |
} | |
else { | |
noFill(); | |
stroke(100); | |
rect(10, 10, 70, 70); | |
} | |
pop(); | |
} | |
} | |
textDisplay = "Neighbors: " + trainDataKeys[curTrainIndex]; | |
} | |
else if (mode == 'TrainingQuiz' || mode == 'InterpolationQuiz') { | |
background(bg_color1); | |
var curKey = trainDataKeys[curTrainIndex]; | |
var data = trainData[curKey]; | |
var valid_mode = false; | |
if (mode == 'InterpolationQuiz') { | |
valid_mode = true; | |
curKey = validDataKeys[curValidIndex]; | |
data = validData[curKey]; | |
} | |
// Displays the image at its actual size at point (0,0) | |
var img = data.image | |
var x1 = (width/2-200/2); | |
var y1 = (height/3-300/2); | |
image(img, x1, y1, 200, 200); | |
if(valid_mode) { | |
fill(0, 0, 200); | |
} | |
else if (curKey in trainValues) { | |
fill(0, 200, 0); | |
} | |
else { | |
fill(200, 0, 0); | |
} | |
ellipse(x1+200/2, y1+200+15, 10, 10); | |
var y2 = (3*height/5-80/2); | |
var y3 = (4*height/5-80/2); | |
/* | |
for(var i=0; i<4; i++) { | |
// var keys = Object.keys(trainData); | |
var curKey = curNeighbors[i]; | |
var nearData = trainData[curKey]; | |
// Displays the image at its actual size at point (0,0) | |
var img = nearData.image | |
var x2 = (width/4 - 200 + i*100); | |
image(img, x2, y2, 80, 80); | |
} | |
*/ | |
for(var i=0; i<1; i++) { | |
// get array of face marker positions [x, y] format | |
var positions = data.landmarks[i]; | |
var shifted_positions = JSON.parse(JSON.stringify(positions)) | |
var data_mean = [0.0, 0.0]; | |
var data_scale = 1.0; | |
var data_angle = 0.0; | |
if ('transform' in positions) { | |
data_mean = positions.transform.center; | |
data_scale = positions.transform.scale; | |
data_angle = positions.transform.angle; | |
delete shifted_positions.transform | |
} | |
var scale_x = 400.0 / img.width; | |
var scale_y = 400.0 / img.height; | |
Object.keys(positions).forEach(function(key) { | |
if (key=='transform') { | |
return; | |
} | |
var curSection = positions[key]; | |
var shiftedSection = shifted_positions[key]; | |
for (var i=0; i<curSection.length; i++) { | |
var cur_x = curSection[i][0]; | |
var cur_y = curSection[i][1]; | |
// get ready for drawing the face | |
shiftedSection[i][0] = cur_x; | |
shiftedSection[i][1] = cur_y; | |
} | |
}); | |
/* | |
var scale_x = 250.0 / img.width; | |
var scale_y = 250.0 / img.height; | |
var x2 = (3*width/4-250/2); | |
push(); | |
translate(x2, y1); | |
translate(scale_x*data_mean[0], scale_y*data_mean[1]); | |
scale(scale_x*data_scale, scale_y*data_scale); | |
rotate(degrees(data_angle)); | |
strokeWeight(1/data_scale); | |
mainFace.setProperties(params); | |
mainFace.draw(shifted_positions); | |
pop(); | |
*/ | |
var scale_x = 80.0 / img.width; | |
var scale_y = 80.0 / img.height; | |
var otherKeys = Object.keys(trainValues); | |
var index = otherKeys.indexOf(trainDataKeys[curTrainIndex]); | |
if(index >= 0) { | |
otherKeys.splice(index, 1); | |
} | |
var answerSlot = int(focusedRandom(0, 4)); | |
var answerKeys = Array(4); | |
for(var j=0; j<4; j++) { | |
if(j == answerSlot) { | |
curKey = trainDataKeys[curTrainIndex]; | |
} | |
else { | |
var guess = int(focusedRandom(0, otherKeys.length)); | |
// if(otherKeys.length > j+2) { | |
// while(answerKeys.indexOf(guess) == -1) { | |
// guess = int(focusedRandom(0, otherKeys.length)); | |
// } | |
// } | |
curKey = otherKeys[guess]; | |
} | |
answerKeys[j] = curKey; | |
// print("Answer", j, " is ", curKey); | |
var x2 = (width/2 - 200 + j*100); | |
var settings = params; | |
if (valid_mode && j == answerSlot) { | |
var curEmbedding = data.embedding[0]; | |
results = getAverageSettingsFrom(curEmbedding); | |
settings = results[0]; | |
var validTrainKeys = results[1]; | |
} | |
else if (curKey in trainValues) { | |
settings = trainValues[curKey]; | |
} | |
push(); | |
translate(x2, y2); | |
translate(scale_x*data_mean[0], scale_y*data_mean[1]); | |
scale(scale_x*data_scale, scale_y*data_scale); | |
rotate(degrees(data_angle)); | |
strokeWeight(1/data_scale); | |
if (typeof settings !== 'undefined') { | |
littleFace.setProperties(settings); | |
} | |
littleFace.draw(shifted_positions); | |
pop(); | |
if(quiz_done && guessed_answer == (j+1)) { | |
push(); | |
translate(x2, y2); | |
noFill(); | |
strokeWeight(4); | |
if(guessed_answer == (answerSlot+1)) { | |
stroke(0, 100, 0); | |
} | |
else { | |
stroke(100, 0, 0); | |
} | |
rect(-10, -10, 100, 100); | |
pop(); | |
} | |
} | |
if(quiz_done) { | |
for(var j=0; j<4; j++) { | |
if (valid_mode && (answerSlot+1) == (j+1)) { | |
for(var k=0; k<4; k++) { | |
var curKey = validTrainKeys[k]; | |
var nearData = trainData[curKey]; | |
// Displays the image at its actual size at point (0,0) | |
var img = nearData.image | |
var x2 = (width/2 - 200 + j*100 + (k%2)*40); | |
var y4 = y3 + (int(k/2))*40; | |
image(img, x2, y4, 40, 40); | |
} | |
} | |
else { | |
var curKey = answerKeys[j]; | |
var nearData = trainData[curKey]; | |
// Displays the image at its actual size at point (0,0) | |
if (typeof nearData !== 'undefined') { | |
var img = nearData.image | |
var x2 = (width/2 - 200 + j*100); | |
image(img, x2, y3, 80, 80); | |
} | |
} | |
} | |
} | |
} | |
if(valid_mode) { | |
if(quiz_done) { | |
textDisplay = "InterpolationQuiz: hit a number to continue"; | |
} | |
else { | |
textDisplay = "InterpolationQuiz: hit 1, 2, 3, or 4 to guess"; | |
} | |
} | |
else { | |
if(quiz_done) { | |
textDisplay = "TrainingQuiz: hit a number to continue"; | |
} | |
else { | |
textDisplay = "TrainingQuiz: hit 1, 2, 3, or 4 to guess"; | |
} | |
} | |
} | |
fill(255); | |
textSize(32); | |
textAlign(CENTER); | |
text(textDisplay, width/2, height-12); | |
} | |
async function keyTyped() { | |
if(!haveStarted) { | |
return; | |
} | |
var mode = faceSelector.value(); | |
if (key == 'q' && mode != 'Faces') { | |
faceSelector.value('Faces'); | |
} | |
else if (key == 'w' && mode != 'Train') { | |
faceSelector.value('Train'); | |
} | |
else if (key == 'e' && mode != 'NearestNeighbors') { | |
faceSelector.value('NearestNeighbors'); | |
} | |
else if (key == 'r' && mode != 'TrainingQuiz') { | |
faceSelector.value('TrainingQuiz'); | |
} | |
else if (key == 't' && mode != 'InterpolationQuiz') { | |
faceSelector.value('InterpolationQuiz'); | |
} | |
else if (key == 'y' && mode != 'Video') { | |
faceSelector.value('Video'); | |
} | |
if (key >= '0' && key <= '9' && | |
(mode == 'TrainingQuiz' || mode == 'InterpolationQuiz') && quiz_done) { | |
quiz_done = false; | |
if(mode == 'TrainingQuiz') { | |
curTrainIndex = (curTrainIndex + 1) % trainDataKeys.length; | |
} | |
else { | |
curValidIndex = (curValidIndex + 1) % validDataKeys.length; | |
} | |
changeRandomSeed(); | |
} | |
else if ((mode == 'TrainingQuiz' || mode == 'InterpolationQuiz') && quiz_done == false) { | |
if(key >= '1' && key <= '4') { | |
guessed_answer = key - '0'; | |
quiz_done = true; | |
} | |
} | |
if (key == 's') { | |
saveCurrentSettings(); | |
} | |
else if (key == 'i') { | |
interpolateCurrent(); | |
} | |
else if (key == 'l') { | |
loadCurrentSettings(); | |
} | |
if (key == '!') { | |
saveBlocksImages(); | |
} | |
else if (key == '@') { | |
saveBlocksImages(true); | |
} | |
/* THIS CODE IS USED TO UPDATE TRAINING_IMAGES.JS and TESTING_IMAGES.JS | |
if (key == '/') { | |
print("loading new train[0]"); | |
for(let i=0; i<trainDataKeys.length; i++) { | |
var curKey = trainDataKeys[i]; | |
var data = trainData[curKey]; | |
let fullFaceDescriptions = await faceapi.detectAllFaces(data.image.canvas).withFaceLandmarks().withFaceDescriptors(); | |
data.landmarks = get_landmarks(fullFaceDescriptions); | |
data.embedding = get_latents(fullFaceDescriptions); | |
} | |
print("loaded new trains"); | |
return; | |
} | |
if (key == '?') { | |
print("running diagnostic on training"); | |
let obj = {}; | |
for(let i=0; i<trainDataKeys.length; i++) { | |
var curKey = trainDataKeys[i]; | |
var data = trainData[curKey]; | |
let fullFaceDescriptions = await faceapi.detectAllFaces(data.image.canvas).withFaceLandmarks().withFaceDescriptors(); | |
let found_embed = get_latents(fullFaceDescriptions); | |
let found_landmarks = get_landmarks(fullFaceDescriptions); | |
// print(data.embedding[0], found_embed[0]); | |
// print("dist old to new -> ", num_dist(found_embed[0], data.embedding[0])); | |
let lst = []; | |
for(let i=0; i<128; i++) { | |
lst[i] = found_embed[0][i]; | |
} | |
obj[curKey] = {"url": data.url, "embedding": [lst], "landmarks": found_landmarks}; | |
} | |
// print(obj); | |
// obj = found_embed; | |
var text = select('#output'); | |
var json = JSON.stringify(obj, null); | |
// alert(json); | |
text.html(json) | |
return; | |
} | |
if (key == ':') { | |
print("running diagnostic on validation"); | |
let obj = {}; | |
for(let i=0; i<validDataKeys.length; i++) { | |
var curKey = validDataKeys[i]; | |
var data = validData[curKey]; | |
let fullFaceDescriptions = await faceapi.detectAllFaces(data.image.canvas).withFaceLandmarks().withFaceDescriptors(); | |
let found_embed = get_latents(fullFaceDescriptions); | |
let found_landmarks = get_landmarks(fullFaceDescriptions); | |
// print(data.embedding[0], found_embed[0]); | |
// print("dist old to new -> ", num_dist(found_embed[0], data.embedding[0])); | |
let lst = []; | |
for(let i=0; i<128; i++) { | |
lst[i] = found_embed[0][i]; | |
} | |
obj[curKey] = {"url": data.url, "embedding": [lst], "landmarks": found_landmarks}; | |
} | |
// print(obj); | |
// obj = found_embed; | |
var text = select('#output'); | |
var json = JSON.stringify(obj, null); | |
// alert(json); | |
text.html(json) | |
return; | |
} | |
*/ | |
} | |
function interpolateCurrent() { | |
var curNeighborSettings = []; | |
for(var i=0; i<4; i++) { | |
neighborKey = curNeighbors[i] | |
if(neighborKey in trainValues) { | |
curNeighborSettings.push(trainValues[neighborKey]); | |
} | |
} | |
for(var i=0; i<NUM_SLIDERS; i++) { | |
sliders[i].value(50); | |
} | |
if(curNeighborSettings.length > 0) { | |
settings = curNeighborSettings[0]; | |
for(var i=0; i<settings.length; i++) { | |
var sum = 0; | |
for(j=0; j<curNeighborSettings.length; j++) { | |
sum += curNeighborSettings[j][i]; | |
} | |
var avg = int(sum / curNeighborSettings.length) | |
sliders[i].value(avg); | |
} | |
} | |
} | |
function loadCurrentSettings() { | |
var curKey = trainDataKeys[curTrainIndex]; | |
for(var i=0; i<NUM_SLIDERS; i++) { | |
sliders[i].value(50); | |
} | |
if (curKey in trainValues) { | |
var settings = trainValues[curKey] | |
for(var i=0; i<settings.length; i++) { | |
sliders[i].value(settings[i]); | |
} | |
} | |
} | |
function updateSlidersForTraining() { | |
var mode = faceSelector.value(); | |
var curKey = trainDataKeys[curTrainIndex]; | |
// first find the closest neighbors | |
var nearest = allEmbeddingsTree.nearest(trainData[curKey].embedding[0], 5); | |
curNeighbors = []; | |
curNeighborSettings = []; | |
for(var i=0; i<5; i++) { | |
if(nearest[i][0][128] != curKey) { | |
var neighborKey = nearest[i][0][128]; | |
curNeighbors.push(neighborKey); | |
if(neighborKey in trainValues) { | |
curNeighborSettings.push(trainValues[neighborKey]); | |
} | |
} | |
} | |
loadCurrentSettings(); | |
// if(mode == 'NearestNeighbors') { | |
// interpolateCurrent(); | |
// } | |
// else { | |
// loadCurrentSettings(); | |
// } | |
} | |
function getAverageSettingsFrom(e) { | |
// first find the closest neighbors | |
var nearest = allEmbeddingsTree.nearest(e, 4); | |
curNeighbors = []; | |
curNeighborSettings = []; | |
for(var i=0; i<4; i++) { | |
var neighborKey = nearest[i][0][128]; | |
curNeighbors.push(neighborKey); | |
if(neighborKey in trainValues) { | |
curNeighborSettings.push(trainValues[neighborKey]); | |
} | |
} | |
for(var i=0; i<4; i++) { | |
neighborKey = curNeighbors[i] | |
if(neighborKey in trainValues) { | |
curNeighborSettings.push(trainValues[neighborKey]); | |
} | |
} | |
var trainValueKeys = Object.keys(trainValues); | |
var props = trainValues[trainValueKeys[0]]; | |
if(curNeighborSettings.length > 0) { | |
settings = curNeighborSettings[0]; | |
for(var i=0; i<settings.length; i++) { | |
var sum = 0; | |
for(j=0; j<curNeighborSettings.length; j++) { | |
sum += curNeighborSettings[j][i]; | |
} | |
var avg = int(sum / curNeighborSettings.length) | |
props[i] = avg; | |
} | |
} | |
return [props, curNeighbors]; | |
} | |
function keyPressed() { | |
if(!haveStarted) { | |
return; | |
} | |
var mode = faceSelector.value(); | |
if (mode == 'Faces') { | |
if (keyCode == LEFT_ARROW || keyCode == UP_ARROW) { | |
curFaceIndex = (curFaceIndex + selfieData.length - 1) % selfieData.length; | |
} else if (keyCode === RIGHT_ARROW || keyCode == DOWN_ARROW) { | |
curFaceIndex = (curFaceIndex + 1) % selfieData.length; | |
} | |
} | |
else if (mode == 'Train' || mode == 'NearestNeighbors') { | |
if (keyCode == LEFT_ARROW || keyCode == UP_ARROW) { | |
curTrainIndex = (curTrainIndex + trainDataKeys.length - 1) % trainDataKeys.length; | |
updateSlidersForTraining(); | |
} else if (keyCode == RIGHT_ARROW || keyCode == DOWN_ARROW) { | |
curTrainIndex = (curTrainIndex + 1) % trainDataKeys.length; | |
updateSlidersForTraining(); | |
} | |
} | |
} |
{ | |
"000001": [ | |
50, | |
24.00000000000003, | |
25, | |
100, | |
33.33333333333333, | |
0, | |
0 | |
], | |
"000002": [ | |
50, | |
49.99999999999994, | |
0, | |
100, | |
50, | |
0, | |
0 | |
], | |
"000005": [ | |
50, | |
42.00000000000005, | |
25, | |
36.000000000000036, | |
33.33333333333333, | |
100, | |
0 | |
], | |
"000006": [ | |
50, | |
42.00000000000005, | |
75, | |
100, | |
66.66666666666666, | |
0, | |
0 | |
], | |
"000007": [ | |
42, | |
53.00000000000006, | |
50, | |
16.000000000000018, | |
100, | |
0, | |
100 | |
], | |
"000009": [ | |
60, | |
14.000000000000016, | |
25, | |
100, | |
83.33333333333334, | |
0, | |
0 | |
], | |
"000010": [ | |
50, | |
10.000000000000012, | |
25, | |
100, | |
33.33333333333333, | |
100, | |
0 | |
], | |
"000013": [ | |
50, | |
82.99999999999999, | |
25, | |
45.00000000000005, | |
16.666666666666664, | |
100, | |
100 | |
], | |
"000014": [ | |
56.00000000000001, | |
4.000000000000004, | |
75, | |
42.00000000000005, | |
100, | |
0, | |
0 | |
], | |
"000015": [ | |
45, | |
57.99999999999995, | |
25, | |
46.00000000000005, | |
83.33333333333334, | |
100, | |
100 | |
], | |
"000016": [ | |
50, | |
29.000000000000032, | |
50, | |
43.00000000000005, | |
83.33333333333334, | |
0, | |
100 | |
], | |
"000018": [ | |
50, | |
39.00000000000004, | |
25, | |
100, | |
33.33333333333333, | |
100, | |
0 | |
], | |
"000020": [ | |
50, | |
61.99999999999996, | |
25, | |
90.99999999999999, | |
83.33333333333334, | |
0, | |
100 | |
], | |
"000023": [ | |
53, | |
55.00000000000006, | |
25, | |
41.00000000000005, | |
100, | |
100, | |
100 | |
], | |
"000025": [ | |
50, | |
55.99999999999995, | |
25, | |
18.000000000000018, | |
66.66666666666666, | |
0, | |
100 | |
], | |
"000028": [ | |
47, | |
42.00000000000005, | |
50, | |
100, | |
66.66666666666666, | |
0, | |
0 | |
], | |
"000029": [ | |
50, | |
25.00000000000003, | |
25, | |
100, | |
16.666666666666664, | |
100, | |
0 | |
], | |
"000030": [ | |
56.99999999999999, | |
37.000000000000036, | |
25, | |
52.99999999999995, | |
16.666666666666664, | |
0, | |
100 | |
], | |
"000031": [ | |
50, | |
30.000000000000032, | |
25, | |
67.99999999999996, | |
66.66666666666666, | |
100, | |
0 | |
], | |
"000032": [ | |
50, | |
37.000000000000036, | |
25, | |
43.00000000000005, | |
66.66666666666666, | |
0, | |
100 | |
], | |
"000035": [ | |
50, | |
44.00000000000005, | |
0, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000037": [ | |
50, | |
55.99999999999995, | |
75, | |
26.00000000000003, | |
100, | |
0, | |
100 | |
], | |
"000038": [ | |
50, | |
43.00000000000005, | |
25, | |
50.00000000000006, | |
83.33333333333334, | |
100, | |
100 | |
], | |
"000040": [ | |
50, | |
39.00000000000004, | |
25, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000041": [ | |
38, | |
49.99999999999994, | |
50, | |
63.99999999999996, | |
100, | |
0, | |
100 | |
], | |
"000042": [ | |
50, | |
28.000000000000032, | |
0, | |
77.99999999999999, | |
66.66666666666666, | |
100, | |
0 | |
], | |
"000043": [ | |
50, | |
49.99999999999994, | |
25, | |
100, | |
83.33333333333334, | |
0, | |
0 | |
], | |
"000044": [ | |
50, | |
35.000000000000036, | |
75, | |
93, | |
100, | |
0, | |
0 | |
], | |
"000045": [ | |
50, | |
23.000000000000025, | |
50, | |
83.99999999999999, | |
50, | |
0, | |
0 | |
], | |
"000047": [ | |
46, | |
49.99999999999994, | |
50, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000048": [ | |
50, | |
49.99999999999994, | |
0, | |
31.000000000000032, | |
100, | |
66.66666666666666, | |
100 | |
], | |
"000050": [ | |
50, | |
34.000000000000036, | |
25, | |
27.00000000000003, | |
100, | |
0, | |
100 | |
], | |
"000051": [ | |
50, | |
49.99999999999994, | |
50, | |
0, | |
0, | |
0, | |
100 | |
], | |
"000052": [ | |
50, | |
23.000000000000025, | |
25, | |
20.000000000000025, | |
83.33333333333334, | |
0, | |
100 | |
], | |
"000054": [ | |
50, | |
31.000000000000032, | |
25, | |
100, | |
16.666666666666664, | |
100, | |
0 | |
], | |
"000055": [ | |
50, | |
49.99999999999994, | |
25, | |
22.000000000000025, | |
100, | |
0, | |
100 | |
], | |
"000056": [ | |
50, | |
36.000000000000036, | |
0, | |
62.99999999999996, | |
100, | |
100, | |
100 | |
], | |
"000058": [ | |
50, | |
39.00000000000004, | |
0, | |
100, | |
100, | |
100, | |
0 | |
], | |
"000060": [ | |
50, | |
49.99999999999994, | |
75, | |
20.000000000000025, | |
100, | |
0, | |
100 | |
], | |
"000064": [ | |
50, | |
32.000000000000036, | |
25, | |
29.000000000000032, | |
83.33333333333334, | |
100, | |
100 | |
], | |
"000065": [ | |
50, | |
37.000000000000036, | |
25, | |
39.00000000000004, | |
100, | |
0, | |
100 | |
], | |
"000068": [ | |
52, | |
31.000000000000032, | |
50, | |
58.99999999999995, | |
0, | |
33.33333333333333, | |
100 | |
], | |
"000069": [ | |
50, | |
43.00000000000005, | |
25, | |
13.000000000000014, | |
100, | |
0, | |
100 | |
], | |
"000071": [ | |
50, | |
28.000000000000032, | |
25, | |
68.99999999999996, | |
33.33333333333333, | |
33.33333333333333, | |
0 | |
], | |
"000073": [ | |
50, | |
35.000000000000036, | |
25, | |
100, | |
83.33333333333334, | |
0, | |
0 | |
], | |
"000076": [ | |
50, | |
29.000000000000032, | |
25, | |
80.99999999999999, | |
100, | |
0, | |
100 | |
], | |
"000077": [ | |
50, | |
37.000000000000036, | |
25, | |
97, | |
100, | |
0, | |
0 | |
], | |
"000078": [ | |
50, | |
49.99999999999994, | |
50, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000079": [ | |
50, | |
12.000000000000014, | |
50, | |
0, | |
83.33333333333334, | |
0, | |
100 | |
], | |
"000080": [ | |
50, | |
36.000000000000036, | |
25, | |
29.000000000000032, | |
100, | |
0, | |
100 | |
], | |
"000081": [ | |
50, | |
35.000000000000036, | |
50, | |
16.000000000000018, | |
100, | |
0, | |
100 | |
], | |
"000083": [ | |
50, | |
49.99999999999994, | |
25, | |
68.99999999999996, | |
50, | |
66.66666666666666, | |
0 | |
], | |
"000085": [ | |
50, | |
32.000000000000036, | |
25, | |
94, | |
50, | |
66.66666666666666, | |
0 | |
], | |
"000086": [ | |
50, | |
34.000000000000036, | |
25, | |
73.99999999999997, | |
66.66666666666666, | |
33.33333333333333, | |
0 | |
], | |
"000088": [ | |
50, | |
49.99999999999994, | |
25, | |
100, | |
50, | |
0, | |
0 | |
], | |
"000091": [ | |
50, | |
68.99999999999996, | |
25, | |
27.00000000000003, | |
100, | |
0, | |
100 | |
], | |
"000092": [ | |
50, | |
40.00000000000005, | |
25, | |
71.99999999999996, | |
33.33333333333333, | |
66.66666666666666, | |
0 | |
], | |
"000096": [ | |
50, | |
58.99999999999995, | |
25, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000097": [ | |
50, | |
39.00000000000004, | |
25, | |
100, | |
66.66666666666666, | |
100, | |
0 | |
], | |
"000099": [ | |
50, | |
42.00000000000005, | |
25, | |
100, | |
66.66666666666666, | |
100, | |
0 | |
], | |
"000100": [ | |
50, | |
49.99999999999994, | |
0, | |
29.000000000000032, | |
33.33333333333333, | |
0, | |
0 | |
], | |
"000103": [ | |
50, | |
49.99999999999994, | |
25, | |
84.99999999999999, | |
100, | |
66.66666666666666, | |
0 | |
], | |
"000104": [ | |
50, | |
49.99999999999994, | |
0, | |
38.00000000000004, | |
33.33333333333333, | |
100, | |
100 | |
], | |
"000106": [ | |
50, | |
31.000000000000032, | |
25, | |
70.99999999999996, | |
66.66666666666666, | |
0, | |
0 | |
], | |
"000108": [ | |
50, | |
49.99999999999994, | |
25, | |
56.000000000000064, | |
16.666666666666664, | |
100, | |
0 | |
], | |
"000109": [ | |
50, | |
19.00000000000002, | |
25, | |
26.00000000000003, | |
33.33333333333333, | |
100, | |
100 | |
], | |
"000110": [ | |
50, | |
49.99999999999994, | |
0, | |
59.99999999999995, | |
66.66666666666666, | |
100, | |
0 | |
], | |
"000111": [ | |
50, | |
49.99999999999994, | |
75, | |
30.000000000000032, | |
66.66666666666666, | |
0, | |
0 | |
], | |
"000114": [ | |
50, | |
41.00000000000005, | |
25, | |
36.000000000000036, | |
100, | |
0, | |
100 | |
], | |
"000115": [ | |
50, | |
49.99999999999994, | |
0, | |
0, | |
16.666666666666664, | |
66.66666666666666, | |
100 | |
], | |
"000116": [ | |
50, | |
49.99999999999994, | |
25, | |
58.99999999999995, | |
83.33333333333334, | |
0, | |
100 | |
], | |
"000117": [ | |
50, | |
24.00000000000003, | |
100, | |
83.99999999999999, | |
100, | |
0, | |
0 | |
], | |
"000118": [ | |
50, | |
18.000000000000018, | |
50, | |
24.00000000000003, | |
100, | |
0, | |
0 | |
], | |
"000121": [ | |
50, | |
49.99999999999994, | |
50, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000122": [ | |
50, | |
32.000000000000036, | |
0, | |
0, | |
16.666666666666664, | |
0, | |
0 | |
], | |
"000125": [ | |
50, | |
26.00000000000003, | |
25, | |
0, | |
0, | |
100, | |
100 | |
], | |
"000126": [ | |
50, | |
49.99999999999994, | |
25, | |
100, | |
16.666666666666664, | |
100, | |
0 | |
], | |
"000129": [ | |
50, | |
18.000000000000018, | |
25, | |
32.000000000000036, | |
100, | |
100, | |
100 | |
], | |
"000131": [ | |
50, | |
43.00000000000005, | |
50, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000132": [ | |
50, | |
51.00000000000006, | |
50, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000133": [ | |
50, | |
49.99999999999994, | |
25, | |
24.00000000000003, | |
66.66666666666666, | |
100, | |
0 | |
], | |
"000134": [ | |
50, | |
49.99999999999994, | |
100, | |
0, | |
100, | |
0, | |
100 | |
], | |
"000135": [ | |
50, | |
23.000000000000025, | |
50, | |
12.000000000000014, | |
100, | |
0, | |
100 | |
], | |
"000137": [ | |
50, | |
71.99999999999996, | |
25, | |
32.000000000000036, | |
83.33333333333334, | |
100, | |
100 | |
], | |
"000140": [ | |
50, | |
35.000000000000036, | |
25, | |
100, | |
16.666666666666664, | |
100, | |
0 | |
], | |
"000142": [ | |
50, | |
16.000000000000018, | |
25, | |
100, | |
83.33333333333334, | |
100, | |
0 | |
], | |
"000143": [ | |
50, | |
33.000000000000036, | |
25, | |
22.000000000000025, | |
66.66666666666666, | |
100, | |
100 | |
], | |
"000145": [ | |
50, | |
49.99999999999994, | |
25, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000146": [ | |
50, | |
49.99999999999994, | |
50, | |
100, | |
50, | |
0, | |
0 | |
], | |
"000147": [ | |
50, | |
38.00000000000004, | |
25, | |
100, | |
33.33333333333333, | |
100, | |
0 | |
], | |
"000148": [ | |
50, | |
38.00000000000004, | |
0, | |
97, | |
100, | |
100, | |
0 | |
], | |
"000150": [ | |
50, | |
19.00000000000002, | |
0, | |
52.00000000000006, | |
50, | |
100, | |
100 | |
], | |
"000151": [ | |
50, | |
31.000000000000032, | |
25, | |
100, | |
100, | |
0, | |
0 | |
], | |
"000152": [ | |
50, | |
49.99999999999994, | |
25, | |
23.000000000000025, | |
66.66666666666666, | |
66.66666666666666, | |
100 | |
], | |
"000153": [ | |
50, | |
23.000000000000025, | |
25, | |
20.000000000000025, | |
83.33333333333334, | |
33.33333333333333, | |
100 | |
], | |
"000155": [ | |
46, | |
22.000000000000025, | |
25, | |
100, | |
50, | |
0, | |
0 | |
], | |
"000156": [ | |
50, | |
30.000000000000032, | |
25, | |
10.000000000000012, | |
33.33333333333333, | |
100, | |
0 | |
], | |
"000157": [ | |
50, | |
32.000000000000036, | |
25, | |
100, | |
16.666666666666664, | |
100, | |
0 | |
], | |
"000160": [ | |
50, | |
36.000000000000036, | |
25, | |
24.00000000000003, | |
100, | |
0, | |
100 | |
], | |
"000161": [ | |
50, | |
27.00000000000003, | |
0, | |
100, | |
100, | |
100, | |
0 | |
] | |
} | |
const bg_color = [225, 206, 187]; | |
const fg_color = [151, 102, 52]; | |
const stroke_color = [95, 52, 8]; | |
function Face() { | |
// these are state variables for a face | |
// (your variables may be different) | |
/* | |
* Draw a face with position lists that include: | |
* chin, right_eye, left_eye, right_eyebrow, left_eyebrow | |
* bottom_lip, top_lip, nose_tip, nose_bridge, | |
*/ | |
this.draw = function(positions) { | |
let eyeChange = this.eyesSHape; | |
//position for land marks | |
let rightePx = positions.right_eye[0][0]; //0.48 | |
let rightePy = positions.right_eye[0][1] | |
let leftePx = positions.left_eye[3][0]; //0.48 | |
let leftePy = positions.left_eye[3][1]; | |
let skinco = this.skinC; | |
let Gender = this.Genders; | |
let smooth; | |
let sk1 = '#F2C6AE'; | |
let sk2 = '#dbb58c'; | |
let sk3 = '#F5E5C9'; | |
let sk4 = '#c48d52'; | |
let sk5 = '#36210d'; | |
let teethP= this.teethPos; | |
let decoration = this.dec; | |
let eyecolor = this.ecolor; | |
let rightEyebrow = this.rightbrow; | |
let leftEyebrow = this.leftbrow; | |
fill(255 - this.mouth_value, 200) | |
beginShape(); | |
if(skinco == 1){ | |
fill(sk1); | |
}else if(skinco ==2){ | |
fill(sk2) | |
}else if(skinco == 3){ | |
fill(sk3) | |
}else if(skinco ==4){ | |
fill(sk4) | |
}else if(skinco ==5){ | |
fill(sk5) | |
} | |
//face | |
for(let i=0; i<positions.chin.length;i += Gender) { | |
vertex(positions.chin[i][0], positions.chin[i][1]); | |
} | |
for(let i=positions.right_eyebrow.length-2; i>=0;i-=2) { | |
vertex(positions.right_eyebrow[i][0], positions.right_eyebrow[i][1]-1.2); | |
} | |
for(let i=positions.left_eyebrow.length-2; i>=0;i-=2) { | |
vertex(positions.left_eyebrow[i][0], positions.left_eyebrow[i][1]-1.2); | |
} | |
endShape(CLOSE); | |
push(); | |
fill(255); | |
beginShape(); | |
noStroke() | |
for(let i = 0; i<positions.nose_tip.length; i++){ | |
vertex(positions.nose_tip[i][0], positions.nose_tip[i][1]); | |
} | |
for(let i=14; i>1; i -= Gender) { | |
vertex(positions.chin[i][0], positions.chin[i][1]); | |
} | |
endShape(CLOSE); | |
pop(); | |
//eye | |
push() | |
let eyeP = this.eyePos; | |
fill(100); | |
ellipse(leftePx-0.52, leftePy-0.3,1,2) | |
ellipse(rightePx+0.52, rightePy-0.3,1,2) | |
translate(0,eyeP) | |
if(eyeChange == 1){ | |
push() | |
strokeWeight(0.04) | |
fill(255) | |
beginShape(); | |
vertex(rightePx+1.12, -1.12); | |
bezierVertex(rightePx+1.04, -0.8, rightePx+0.92, -0.68, rightePx+0.76, -0.6) | |
bezierVertex(rightePx+0.4, -0.6, rightePx+0.24, -0.68, rightePx+0.08, -0.8) | |
vertex(rightePx, -1); | |
endShape(CLOSE); | |
beginShape(); | |
vertex(leftePx-1.12, -1.12); | |
bezierVertex(leftePx-1.04, -0.8, leftePx-0.92, -0.68, leftePx-0.76, -0.6) | |
bezierVertex(leftePx-0.4, -0.6, leftePx-0.24, -0.68, leftePx-0.08, -0.8) | |
vertex(leftePx, -1); | |
endShape(CLOSE); | |
noStroke(); | |
push(); | |
colorMode(HSB); | |
fill(eyecolor,100,71) | |
ellipse(rightePx+0.52, -1.04, 0.6, 0.52) | |
ellipse(leftePx-0.52, -1.04, 0.6, 0.52) | |
pop(); | |
fill(0); | |
ellipse(rightePx+0.52,-1.04, 0.4, 0.32) | |
ellipse(leftePx-0.52,-1.04, 0.4, 0.32) | |
pop(); | |
push(); | |
push(); | |
strokeWeight(0) | |
fill('#FF9D85') | |
beginShape(); | |
vertex(rightePx+1.2, -1.08); | |
vertex(rightePx+0.92, -1.4); | |
vertex(rightePx+0.32, -1.4); | |
vertex(rightePx, -1) | |
endShape(); | |
beginShape(); | |
vertex(leftePx-1.2, -1.08); | |
vertex(leftePx-0.92, -1.4); | |
vertex(leftePx-0.32, -1.4); | |
vertex(leftePx, -1) | |
endShape(); | |
pop(); | |
beginShape(); | |
strokeWeight(0.08); | |
vertex(rightePx, -1); | |
bezierVertex(rightePx+0.24, -1.08, rightePx+1.12, -1.12, rightePx+1.2, -1.08); | |
endShape(); | |
beginShape(); | |
vertex(leftePx, -1); | |
bezierVertex(leftePx-0.24, -1.08, leftePx-1.12, -1.12, leftePx-1.2, -1.08); | |
endShape(); | |
pop(); | |
}else if(eyeChange ==2){ | |
//rightePx = 0.48 | |
//rightePy = 0.2 | |
strokeWeight(0.04); | |
fill(255); | |
beginShape(); | |
vertex(rightePx+1.12, rightePy-0.52); | |
bezierVertex(rightePx+1, rightePy, rightePx+0.72, rightePy, rightePx,rightePy); | |
bezierVertex(rightePx+0.28, rightePy-0.8, rightePx+0.44, rightePy - 0.64, rightePx +0.68, rightePy - 0.68); | |
endShape(); | |
beginShape(); | |
vertex(leftePx-1.12, leftePy-0.52); | |
bezierVertex(leftePx-1, leftePy, leftePx-0.72, leftePy, leftePx,leftePy); | |
bezierVertex(leftePx-0.28, leftePy-0.8, leftePx-0.44, leftePy - 0.64, leftePx -0.68, leftePy - 0.68); | |
endShape(); | |
push(); | |
colorMode(HSB); | |
fill(eyecolor,100,71) | |
ellipse(rightePx+0.52, rightePy-0.3, 0.6, 0.6) | |
pop(); | |
fill(0); | |
ellipse(rightePx+0.52, rightePy-0.3, 0.3, 0.3) | |
beginShape(); | |
vertex(rightePx,rightePy); | |
bezierVertex(rightePx+0.08, rightePy-0.72, rightePx + 0.44, rightePy-0.8, rightePx + 0.68, rightePy-0.78); | |
bezierVertex(rightePx + 0.92, rightePy-0.72, rightePx + 1.12, rightePy-0.52, rightePx + 1.2, rightePy-0.64); | |
bezierVertex(rightePx + 1.12, rightePy-0.52, rightePx + 0.92, rightePy-0.56, rightePx + 0.68, rightePy-0.68); | |
bezierVertex(rightePx + 0.44, rightePy-0.64, rightePx+0.28, rightePy-0.6, rightePx, rightePy-0.2); | |
endShape() | |
push(); | |
colorMode(HSB); | |
fill(eyecolor,100,71) | |
ellipse(leftePx-0.52, leftePy-0.3, 0.6, 0.6) | |
pop(); | |
fill(0); | |
ellipse(leftePx-0.52, leftePy-0.3, 0.3, 0.3) | |
beginShape(); | |
vertex(leftePx,leftePy); | |
bezierVertex(leftePx-0.08, leftePy-0.72, leftePx - 0.44, leftePy-0.8, leftePx - 0.68, leftePy-0.78); | |
bezierVertex(leftePx - 0.92, leftePy-0.72, leftePx - 1.12, leftePy-0.52, leftePx - 1.2, leftePy-0.64); | |
bezierVertex(leftePx - 1.12, leftePy-0.52, leftePx - 0.92, leftePy-0.56, leftePx - 0.68, leftePy-0.68); | |
bezierVertex(leftePx - 0.44, leftePy-0.64, leftePx-0.28, leftePy-0.6, leftePx, leftePy-0.2); | |
endShape(); | |
}else if(eyeChange == 3){ | |
translate(0,-0.8) | |
// scale(0.4) | |
beginShape();//right eye inside | |
fill(250) | |
//rightePx = 0.48 | |
vertex(rightePx, -0.216); | |
bezierVertex(rightePx+0.144, -0.364, rightePx+1.2, -0.676, rightePx+1.08,-0.24) | |
bezierVertex(rightePx+0.96, 0, rightePx+0.916, 0.048, rightePx + 0.72, 0.192); | |
bezierVertex(rightePx, 0.24, rightePx-0.12, 0.12, rightePx, -0.216) | |
endShape(CLOSE); | |
push(); | |
colorMode(HSB); | |
fill(eyecolor,100,71); | |
ellipse(rightePx+0.432, -0.12, 0.648, 0.576); | |
pop(); | |
fill(36, 73, 83) | |
ellipse(rightePx+0.432, -0.12, 0.24, 0.24) | |
push(); | |
noFill(); | |
beginShape(); | |
fill(0) | |
vertex(rightePx, -0.216); | |
bezierVertex(rightePx+0.144, -0.368, rightePx+1.2, -0.676, rightePx+1.08, -0.24) | |
vertex(rightePx+1.2, -0.48); | |
bezierVertex(rightePx + 1.08, -0.6, rightePx+0.72, -0.6, rightePx, -0.24) | |
endShape(CLOSE); | |
pop(); | |
beginShape();//left eye inside | |
fill(250) | |
vertex(leftePx, -0.216); | |
bezierVertex(leftePx-0.144, -0.364, leftePx-1.2, -0.676, leftePx-1.08,-0.24) | |
bezierVertex(leftePx-0.96, 0, leftePx-0.916, 0.048, leftePx - 0.72, 0.192); | |
bezierVertex(leftePx, 0.24, leftePx-0.12, 0.12, leftePx, -0.216) | |
endShape(CLOSE); | |
push(); | |
colorMode(HSB); | |
fill(eyecolor,100,71); | |
ellipse(leftePx-0.432, -0.12, 0.648, 0.576); | |
pop(); | |
fill(36, 73, 83) | |
ellipse(leftePx-0.432, -0.12, 0.24, 0.24) | |
beginShape(); | |
fill(0) | |
vertex(leftePx, -0.216); | |
bezierVertex(leftePx-0.144, -0.368, leftePx-1.2, -0.676, leftePx-1.08, -0.24) | |
vertex(leftePx-1.2, -0.48); | |
bezierVertex(leftePx - 1.08, -0.6, leftePx-0.72, -0.6, leftePx, -0.24) | |
endShape(CLOSE); | |
} | |
pop() | |
push(); | |
scale(0.4) | |
translate(0,-2.5) | |
if(decoration == 1){ | |
//freckle | |
fill("#B57738") | |
noStroke() | |
ellipse(1,0,0.1,0.1); | |
ellipse(0.2,0.5,0.2,0.2) | |
ellipse(-1.1,0.5,0.2,0.15); | |
ellipse(1.4,0.8,0.15,0.15); | |
ellipse(-1.1,0.3,0.15,0.1); | |
ellipse(-1.4,1.3,0.15,0.15); | |
ellipse(-0.8,0.5,0.2,0.15); | |
ellipse(1.1,0.3,0.15,0.15); | |
ellipse(-1,0.9,0.15,0.2); | |
ellipse(-2,1,0.15,0.15); | |
ellipse(2,1,0.2,0.15); | |
ellipse(0, 1, 0.3, 0.15); | |
ellipse(1.5, 1.4, 0.25, 0.25); | |
ellipse(-1.8, 0.8, 0.2, 0.2); | |
ellipse(1.8, 0.8, 0.2, 0.2); | |
}else if(decoration==2){ | |
}else if(decoration==3){ | |
// translate(3,0) | |
fill('#EB4762'); | |
noStroke(); | |
ellipse(3,2,2,2); | |
ellipse(-3,2,2,2); | |
}else if(decoration==4){ | |
//glass | |
noFill(); | |
strokeWeight(0.2) | |
ellipse(2.5,0,3.5,2.5); | |
ellipse(-2.5,0,3.5,2.5); | |
beginShape(); | |
vertex(0.8,0); | |
vertex(0,-0.5) | |
vertex(-0.8,0) | |
endShape(); | |
} | |
pop(); | |
push() | |
beginShape();// botom lip | |
noFill(); | |
vertex(positions.bottom_lip[2][0],positions.bottom_lip[2][1]); | |
bezierVertex(positions.bottom_lip[2][0],positions.bottom_lip[2][1],positions.bottom_lip[3][0],positions.bottom_lip[3][1],positions.bottom_lip[4][0],positions.bottom_lip[4][1]) | |
endShape(); | |
pop(); | |
beginShape();//mouth | |
noFill(); | |
for(let i = 7; i <positions.top_lip.length; i ++){ | |
vertex(positions.top_lip[i][0],positions.top_lip[i][1]); | |
} | |
endShape(); | |
beginShape(); | |
fill('#543B33'); | |
vertex(positions.top_lip[7][0],positions.top_lip[7][1]); | |
vertex(positions.top_lip[8][0],positions.top_lip[8][1]+this.teethPos); | |
vertex(positions.top_lip[9][0],positions.top_lip[9][1]+this.teethPos); | |
vertex(positions.top_lip[10][0],positions.top_lip[10][1]+this.teethPos); | |
vertex(positions.top_lip[11][0],positions.top_lip[11][1]); | |
for(let i = 7; i <positions.bottom_lip.length; i ++){ | |
vertex(positions.bottom_lip[i][0],positions.bottom_lip[i][1]) | |
} | |
endShape(); | |
beginShape(); | |
noStroke(); | |
fill('red'); | |
vertex(positions.top_lip[0][0]-0.6,positions.top_lip[0][1]); | |
for(let i = 1; i <6; i ++){ | |
vertex(positions.top_lip[i][0],positions.top_lip[i][1]); | |
} | |
vertex(positions.top_lip[6][0]+0.6,positions.top_lip[6][1]); | |
for(let i = 7; i <12; i ++){ | |
vertex(positions.top_lip[i][0],positions.top_lip[i][1]); | |
} | |
endShape() | |
beginShape(); | |
vertex(positions.top_lip[6][0]+0.6,positions.top_lip[6][1]); | |
for(let i = 1; i <6; i ++){ | |
vertex(positions.bottom_lip[i][0],positions.bottom_lip[i][1]) | |
} | |
vertex(positions.top_lip[0][0]-0.6,positions.top_lip[0][1]); | |
vertex(positions.bottom_lip[6][0],positions.bottom_lip[6][1]); | |
for(let i = 7; i <12; i ++){ | |
vertex(positions.bottom_lip[i][0],positions.bottom_lip[i][1]) | |
} | |
endShape(); | |
beginShape()//teeth | |
fill(255) | |
vertex(positions.top_lip[7][0],positions.top_lip[7][1]); | |
vertex(positions.top_lip[8][0],positions.top_lip[8][1]+this.teethPos); | |
vertex(positions.top_lip[9][0],positions.top_lip[9][1]+this.teethPos); | |
vertex(positions.top_lip[10][0],positions.top_lip[10][1]+this.teethPos); | |
vertex(positions.top_lip[11][0],positions.top_lip[11][1]); | |
for(let i = 11; i >6 ; i --){ | |
vertex(positions.top_lip[i][0],positions.top_lip[i][1]); | |
} | |
endShape(); | |
push(); | |
stroke(0); | |
fill('red'); | |
ellipse(positions.nose_bridge[3][0], positions.nose_bridge[3][1],1,1) | |
pop(); | |
push(); | |
translate(0,-1) | |
scale(0.4); | |
noStroke(); | |
fill(25); | |
beginShape();//right eye brow | |
vertex(0.72, -2.1+0.2*rightEyebrow); | |
bezierVertex(0.72, -2.16+0.2*rightEyebrow, 2.4, -3.3-0.15*rightEyebrow, 4.2, -2.4-0.15*rightEyebrow); | |
vertex(3.6, -2.46-0.15*rightEyebrow); | |
vertex(2.1, -2.4+0.01*rightEyebrow); | |
endShape(CLOSE); | |
beginShape();//Left eye brow | |
vertex(-0.72, -2.1+0.15*leftEyebrow); | |
bezierVertex(-0.72, -2.16+0.2*leftEyebrow, -2.4, -3.3-0.15*leftEyebrow, -4.2, -2.4-0.15*leftEyebrow); | |
vertex(-3.6, -2.46-0.15*leftEyebrow); | |
vertex(-2.1, -2.4+0.01*leftEyebrow); | |
endShape(CLOSE); | |
pop(); | |
fill(20); | |
// for(let i = 0; i <positions.top_lip.length; i++){ | |
// textSize(0.3); | |
// text(i, positions.top_lip[i][0], positions.top_lip[i][1]); | |
// } //11 10 9 8 7 | |
// for(let i = 0; i <positions.bottom_lip.length; i++){ | |
// textSize(0.2); | |
// text(i, positions.bottom_lip[i][0], positions.bottom_lip[i][1]); | |
// } //7 8 9 10 11 | |
// // // for(let i = 0; i <positions.chin.length; i++){ | |
// // // textSize(0.2); | |
// // // text(i, positions.chin[i][0], positions.chin[i][1]); | |
// // // } | |
// // for(let i = 0; i <positions.nose_tip.length; i++){ | |
// // textSize(0.2); | |
// // text(i, positions.nose_tip[i][0], positions.nose_tip[i][1]); | |
// // } | |
// // for(let i = 0; i <positions.nose_bridge.length; i++){ | |
// // textSize(0.2); | |
// // text(i, positions.nose_bridge[i][0], positions.nose_bridge[i][1]); | |
// // } | |
// fill(0); | |
// for(let i = 0; i <positions.left_eyebrow.length; i++){ | |
// textSize(0.4); | |
// text(i, positions.left_eyebrow[i][0], positions.left_eyebrow[i][1]); | |
// } | |
} | |
/* set internal properties based on list numbers 0-100 */ | |
this.setProperties = function(settings) { | |
this.eyesSHape = int(map(settings[0], 0, 100, 1,3)); | |
this.skinC = int(map(settings[1], 0, 100, 1, 5)); | |
this.Genders = int(map(settings[2], 0, 100, 1, 2)); | |
this.teethPos = map(settings[3], 0, 100,0, 0.5); | |
this.dec = int(map(settings[4], 0, 100,1, 4)); | |
this.ecolor = map(settings[5], 0, 100,0, 360); | |
this.rightbrow = map(settings[6], 0, 100,0, 3); | |
this.leftbrow = map(settings[7], 0, 100,0, 3); | |
this.eyePos = map(settings[8], 0, 100,-0.3,0.3) | |
} | |
/* get internal properties as list of numbers 0-100 */ | |
this.getProperties = function() { | |
let settings = new Array(9); | |
settings[0] = map(this.eyesSHape, 1, 3, 0, 100); | |
settings[1] = map(this.skinC, 1, 5, 0, 100); | |
settings[2] = map(this.Genders, 1, 2, 0, 100); | |
settings[3] = map(this.teethPos, 0, 0.5, 0, 100); | |
settings[4] = map(this.dec, 1, 4, 0, 100); | |
settings[5]= map(this.ecolor,0,360,0,100); | |
settings[6]= map(this.rightbrow,0,3,0,100); | |
settings[7]= map(this.leftbrow,0,3,0,100); | |
settings[8]= map(this.eyePos,-0.3,0.3,0,100); | |
return settings; | |
} | |
} | |
function average_point(list) { | |
var sum_x = 0; | |
var sum_y = 0; | |
var num_points = 0; | |
for(var i=0; i<list.length; i++) { | |
sum_x += list[i][0]; | |
sum_y += list[i][1]; | |
num_points += 1; | |
} | |
return [sum_x / num_points, sum_y / num_points]; | |
} | |
/* | |
* FaceMap class - holds all informaiton about one mapped | |
* face and is able to draw itself. | |
*/ | |
// other variables can be in here too | |
// these control the colors used | |
const bg_color = [225, 206, 187]; | |
const fg_color = [151, 102, 52]; | |
const stroke_color = [95, 52, 8]; | |
function segment_average(segment) { | |
let sum_x = 0; | |
let sum_y = 0; | |
let s_len = segment.length; | |
for (let i=0; i<s_len; i++) { | |
sum_x = sum_x + segment[i][0]; | |
sum_y = sum_y + segment[i][1]; | |
} | |
return [sum_x / s_len , sum_y / s_len ]; | |
} | |
function Face() { | |
// these are state variables for a face | |
// (your variables may be different) | |
this.eye_value = 2; // can be either 2 (eyes) or 3 (no eyes) | |
this.mouth_value = 1; // range is 0.5 to 8 | |
this.tilt_value = 0; // range is -30 to 30 | |
this.draw_segment = function(segment, do_loop) { | |
// print(segment); | |
for(let i=0; i<segment.length; i++) { | |
let px = segment[i][0]; | |
let py = segment[i][1]; | |
ellipse(px, py, 0.1); | |
if(i < segment.length - 1) { | |
let nx = segment[i+1][0]; | |
let ny = segment[i+1][1]; | |
line(px, py, nx, ny); | |
} | |
else if(do_loop) { | |
let nx = segment[0][0]; | |
let ny = segment[0][1]; | |
line(px, py, nx, ny); | |
} | |
} | |
}; | |
/* | |
* Draw a face with position lists that include: | |
* chin, right_eye, left_eye, right_eyebrow, left_eyebrow | |
* bottom_lip, top_lip, nose_tip, nose_bridge, | |
*/ | |
this.draw = function(positions) { | |
rotate(this.tilt_value); | |
// head | |
stroke(stroke_color); | |
fill(fg_color); | |
ellipse(0, 0, 3, 4); | |
noStroke(); | |
// mouth | |
fill(bg_color); | |
ellipse(0, 0.64, 1.36, 0.25 * this.mouth_value); | |
// eyebrows | |
fill(0); | |
stroke(0); | |
strokeWeight(0.08); | |
this.draw_segment(positions.left_eyebrow); | |
this.draw_segment(positions.right_eyebrow); | |
fill(128); | |
stroke(128); | |
this.draw_segment(positions.chin); | |
fill(100, 0, 100); | |
stroke(100, 0, 100); | |
this.draw_segment(positions.nose_bridge); | |
this.draw_segment(positions.nose_tip); | |
strokeWeight(0.03); | |
fill(200, 0, 0); | |
stroke(200, 0, 0); | |
this.draw_segment(positions.top_lip); | |
this.draw_segment(positions.bottom_lip); | |
fill(255); | |
stroke(255); | |
// this.draw_segment(positions.left_eye, true); | |
// this.draw_segment(positions.right_eye, true); | |
// print(Object.keys(positions)) | |
let left_eye_pos = segment_average(positions.left_eye); | |
let right_eye_pos = segment_average(positions.right_eye); | |
// eyes | |
noStroke(); | |
fill(bg_color); | |
ellipse(left_eye_pos[0], left_eye_pos[1], 0.45, 0.27); | |
ellipse(right_eye_pos[0], right_eye_pos[1], 0.45, 0.27); | |
fill(fg_color); | |
ellipse(left_eye_pos[0] - 0.1, left_eye_pos[1], 0.18); | |
ellipse(right_eye_pos[0] - 0.1, right_eye_pos[1], 0.18); | |
} | |
/* set internal properties based on list numbers 0-100 */ | |
this.setProperties = function(settings) { | |
this.eye_value = int(map(settings[0], 0, 100, 2, 3)); | |
this.mouth_value = map(settings[1], 0, 100, 0.5, 8); | |
this.tilt_value = map(settings[2], 0, 100, -30, 30); | |
} | |
/* get internal properties as list of numbers 0-100 */ | |
this.getProperties = function() { | |
let settings = new Array(3); | |
settings[0] = map(this.eye_value, 2, 3, 0, 100); | |
settings[1] = map(this.mouth_value, 0.5, 8, 0, 100); | |
settings[2] = map(this.tilt_value, -30, 30, 0, 100); | |
return settings; | |
} | |
} |
// draw the whole mask in function face() | |
function Face() { | |
this.draw = function(positions) { | |
let hair_setting = this.hair_setting; | |
let face_setting = this.face_setting; | |
let nose_setting = this.nose_setting; | |
let symbol_value = this.symbol_value; | |
let eye_setting = this.eye_setting; | |
let beard_setting = this.beard_setting; | |
let hair_colour = this.hair_colour; | |
//hair colour | |
let hc1 = "#000000"; | |
let hc2 = "#e5ddcc"; | |
let hc3 = "#d9a86c"; | |
let hc4 = "#6a5b4d"; | |
let hc5 = "#f2c46d"; | |
let hc6 = "#8c3730"; | |
let shift_face_x = positions.left_eyebrow[0][0]; | |
let shift_face_y =positions.left_eyebrow[0][1]; | |
angleMode(DEGREES); | |
push(); | |
scale(0.33); | |
stroke(0); | |
strokeWeight(0.15); | |
//draw face shape | |
push() | |
strokeWeight(0.1); | |
scale(3.3); | |
if (face_setting == 0){ | |
fill("#f2c1ae") | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0], positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0], positions.left_eyebrow[0][1]); | |
curveVertex(positions.chin[0][0], positions.chin[0][1]); | |
curveVertex(positions.chin[3][0], positions.chin[3][1]); | |
curveVertex(positions.chin[5][0], positions.chin[5][1]); | |
curveVertex(positions.chin[6][0], positions.chin[6][1]); | |
curveVertex(positions.chin[7][0], positions.chin[7][1]); | |
curveVertex(positions.chin[8][0], positions.chin[8][1]); | |
curveVertex(positions.chin[9][0], positions.chin[9][1]); | |
curveVertex(positions.chin[10][0], positions.chin[10][1]); | |
curveVertex(positions.chin[11][0], positions.chin[11][1]); | |
curveVertex(positions.chin[12][0], positions.chin[12][1]); | |
curveVertex(positions.chin[14][0], positions.chin[14][1]); | |
curveVertex(positions.chin[16][0], positions.chin[16][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
endShape(); | |
}else if (face_setting == 1){ | |
fill("#fff3ec"); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0], positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0], positions.left_eyebrow[0][1]); | |
curveVertex(positions.chin[0][0], positions.chin[0][1]); | |
curveVertex(positions.chin[0][0], positions.chin[0][1]); | |
curveVertex(positions.chin[3][0], positions.chin[3][1]); | |
curveVertex(positions.chin[5][0], positions.chin[5][1]); | |
curveVertex(positions.chin[6][0], positions.chin[6][1]); | |
curveVertex(positions.chin[7][0], positions.chin[7][1]); | |
curveVertex(positions.chin[8][0], positions.chin[8][1]); | |
curveVertex(positions.chin[9][0], positions.chin[9][1]); | |
curveVertex(positions.chin[10][0], positions.chin[10][1]); | |
curveVertex(positions.chin[11][0], positions.chin[11][1]); | |
curveVertex(positions.chin[12][0], positions.chin[12][1]); | |
curveVertex(positions.chin[14][0], positions.chin[14][1]); | |
curveVertex(positions.chin[16][0], positions.chin[16][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
endShape(); | |
}else if (face_setting == 2){ | |
beginShape(); | |
fill("#ffdcbb"); | |
curveVertex(positions.left_eyebrow[0][0], positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0], positions.left_eyebrow[0][1]); | |
curveVertex(positions.chin[0][0], positions.chin[0][1]); | |
curveVertex(positions.chin[3][0], positions.chin[3][1]); | |
curveVertex(positions.chin[5][0], positions.chin[5][1]); | |
curveVertex(positions.chin[6][0], positions.chin[6][1]); | |
curveVertex(positions.chin[7][0], positions.chin[7][1]); | |
curveVertex(positions.chin[8][0], positions.chin[8][1]); | |
curveVertex(positions.chin[9][0], positions.chin[9][1]); | |
curveVertex(positions.chin[10][0], positions.chin[10][1]); | |
curveVertex(positions.chin[11][0], positions.chin[11][1]); | |
curveVertex(positions.chin[12][0], positions.chin[12][1]); | |
curveVertex(positions.chin[14][0], positions.chin[14][1]); | |
curveVertex(positions.chin[16][0], positions.chin[16][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
endShape(CLOSE); | |
}else { | |
fill("#bf8665"); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0], positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0], positions.left_eyebrow[0][1]); | |
curveVertex(positions.chin[0][0], positions.chin[0][1]); | |
curveVertex(positions.chin[3][0], positions.chin[3][1]); | |
curveVertex(positions.chin[5][0], positions.chin[5][1]); | |
curveVertex(positions.chin[6][0], positions.chin[6][1]); | |
curveVertex(positions.chin[7][0], positions.chin[7][1]); | |
curveVertex(positions.chin[8][0], positions.chin[8][1]); | |
curveVertex(positions.chin[9][0], positions.chin[9][1]); | |
curveVertex(positions.chin[10][0], positions.chin[10][1]); | |
curveVertex(positions.chin[11][0], positions.chin[11][1]); | |
curveVertex(positions.chin[12][0], positions.chin[12][1]); | |
curveVertex(positions.chin[14][0], positions.chin[14][1]); | |
curveVertex(positions.chin[16][0], positions.chin[16][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
endShape(); | |
} | |
pop(); | |
//draw eye area(eye_mask and eye shapes) | |
push(); | |
// right part | |
if(eye_setting == 0) { | |
beginShape(); | |
fill("#c2c3c4") | |
vertex(1.2, -1); | |
bezierVertex( 3, -1, 5, -3,4.7,1) | |
bezierVertex( 3.6, 0, 3.5, 0.1, 1.5, -1); | |
bezierVertex(0.8, 0.6, 0.9, 0.3, 1.2, -0.8) | |
endShape(CLOSE); | |
beginShape(); | |
fill(0) | |
vertex(1.2, -1); | |
bezierVertex( 1.6, -0.9, 4.2, -1.7, 3.7,-0.6) | |
bezierVertex( 3.6, 0, 3.5, 0.1, 3, 0.5); | |
bezierVertex(0.8, 0.6, 0.9, 0.3, 1.2, -0.8) | |
endShape(CLOSE); | |
fill(0) | |
ellipse(2.3, -0.3, 1.7, 1.5) | |
fill(50) | |
arc(2.3, -0.3,0.6,0.6,PI-QUARTER_PI,QUARTER_PI, PIE) | |
//left EYE area | |
beginShape(); | |
fill("#c2c3c4") | |
vertex(-1.2, -1); | |
bezierVertex( -3, -1, -5, -3, -4.7,1) | |
bezierVertex( -3.6, 0, -3.5, 0.1, -1.5, -1); | |
bezierVertex(-0.8, 0.6, -0.9, 0.3, -1.2, -0.8) | |
endShape(CLOSE); | |
beginShape(); | |
fill(0) | |
vertex(-1.2, -1); | |
bezierVertex( -1.6, -0.9, -4.2, -1.7, -3.7,-0.6) | |
bezierVertex( -3.6, 0, -3.5, 0.1, -3, 0.5); | |
bezierVertex(-0.8, 0.6, -0.9, 0.3, -1.2, -0.8) | |
endShape(CLOSE); | |
fill(0); | |
ellipse(-2.3, -0.3, -1.7, 1.5) | |
fill(50); | |
arc(-2.3, -0.3,0.6,0.6,PI-QUARTER_PI,QUARTER_PI, PIE) | |
}else if | |
(eye_setting == 1) { | |
beginShape(); | |
fill("#f9a603") | |
stroke("#ffa600") | |
vertex(1.2, -1); | |
bezierVertex( 3, -1, 5, -4, 6.7,-1.6) | |
bezierVertex( 3.6, 0, 3.5, 0.1, 5, 1.5); | |
bezierVertex(0.8, 0.6, 0.9, 0.3, 1.2, -0.8) | |
endShape(CLOSE); | |
beginShape(); | |
fill("#f7ebd5") | |
vertex(1.2, -1); | |
bezierVertex( 1.6, -0.9, 4.2, -1.7, 3.7,-0.6) | |
bezierVertex( 3.6, 0, 3.5, 0.1, 3, 0.5); | |
bezierVertex(0.8, 0.6, 0.9, 0.3, 1.2, -0.8) | |
endShape(CLOSE); | |
fill("#f7ebd5") | |
ellipse(2.3, -0.3, 1.6, 1.2) | |
fill("#f9a603") | |
arc(2.3, -0.3,0.6,0.3,0,360, PIE) | |
//left EYE area | |
beginShape(); | |
fill("#f9a603") | |
stroke("#ffa600") | |
vertex(-1.2, -1); | |
bezierVertex( -3, -1, -5, -4, -6.7,-1.6) | |
bezierVertex( -3.6, 0, -3.5, 0.1, -5, 1.5); | |
bezierVertex(-0.8, 0.6, -0.9, 0.3, -1.2, -0.8) | |
endShape(CLOSE); | |
beginShape(); | |
fill("#f7edb5") | |
vertex(-1.2, -1); | |
bezierVertex( -1.6, -0.9, -4.2, -1.7, -3.7,-0.6) | |
bezierVertex( -3.6, 0, -3.5, 0.1, -3, 0.5); | |
bezierVertex(-0.8, 0.6, -0.9, 0.3, -1.2, -0.8) | |
endShape(CLOSE); | |
fill("#f7ebd5"); | |
ellipse(-2.3, -0.3, 1.6, 1.2) | |
fill("#f9a603"); | |
arc(-2.3, -0.3,0.6,0.3,0,360, PIE) | |
}else if(eye_setting == 2) { | |
// right EYE area | |
beginShape(); | |
fill("#F1FCFF"); | |
vertex(1.2, -1); | |
bezierVertex( 1.6, -0.9, 4.2, -1.7, 3.7,-0.6) | |
bezierVertex( 3.6, 0, 3.5, 0.1, 3, 0.5); | |
bezierVertex(0.8, 0.6, 0.9, 0.3, 1.2, -0.8) | |
endShape(CLOSE); | |
fill("#b5bdbf") | |
strokeWeight(0.2) | |
stroke("#000000") | |
ellipse(2.3, -0.3, 1.5, 1.4) | |
fill("#3c3f40") | |
arc(2.3, -0.3,0.6,0.6,0,180, PIE) | |
//left EYE area | |
beginShape(); | |
fill("f1fcff") | |
vertex(-1.2, -1); | |
bezierVertex( -1.6, -0.9, -4.2, -1.7, -3.7,-0.6) | |
bezierVertex( -3.6, 0, -3.5, 0.1, -3, 0.5); | |
bezierVertex(-0.8, 0.6, -0.9, 0.3, -1.2, -0.8) | |
endShape(CLOSE); | |
fill("#b5bdbf"); | |
stroke("#000000") | |
strokeWeight(0.2) | |
ellipse(-2.3, -0.3, 1.5, 1.4) | |
fill("#3c3f40"); | |
arc(-2.3, -0.3,0.6,0.6,0,180, PIE) | |
}else if (eye_setting == 3) { | |
//right EYE area | |
beginShape(); | |
stroke("#730217") | |
fill("#f20530") | |
vertex(1.2, -1); | |
bezierVertex( 3, -1, 5, -3, 8.7,-4) | |
bezierVertex( 3.6, 0, 3.5, 0.1, 6, 3.5); | |
bezierVertex(0.8, 0.6, 0.9, 0.3, 1.2, -0.8) | |
endShape(CLOSE); | |
beginShape(); | |
fill("#ffffff") | |
vertex(1.2, -1); | |
bezierVertex( 1.6, -0.9, 4.2, -1.7, 3.7,-0.6) | |
bezierVertex( 3.6, 0, 3.5, 0.1, 3, 0.5); | |
bezierVertex(0.8, 0.6, 0.9, 0.3, 1.2, -0.8) | |
endShape(CLOSE); | |
fill("#a7d5f2") | |
ellipse(2.3, -0.3, 1.5, 1.1) | |
fill("#0468bf") | |
arc(2.3, -0.3,0.3,0.6,0,360, PIE) | |
//left EYE area | |
beginShape(); | |
stroke("#730217") | |
fill("#f20530") | |
vertex(-1.2, -1); | |
bezierVertex( -3, -1, -5, -3, -8.7,-4) | |
bezierVertex( -3.6, 0, -3.5, 0.1, -6, 3.5); | |
bezierVertex(-0.8, 0.6, -0.9, 0.3, -1.2, -0.8) | |
endShape(CLOSE); | |
beginShape(); | |
fill("#ffffff") | |
vertex(-1.2, -1); | |
bezierVertex( -1.6, -0.9, -4.2, -1.7, -3.7,-0.6) | |
bezierVertex( -3.6, 0, -3.5, 0.1, -3, 0.5); | |
bezierVertex(-0.8, 0.6, -0.9, 0.3, -1.2, -0.8) | |
endShape(CLOSE); | |
fill("#a7d5f2"); | |
ellipse(-2.3, -0.3, 1.5, 1.1) | |
fill("#0468bf"); | |
arc(-2.3, -0.3,0.3,0.6,0,360, PIE) | |
}else { | |
// right EYE area | |
scale(3.3); | |
fill("#000000") | |
beginShape(); | |
curveVertex(positions.chin[0][0],positions.chin[0][1]) | |
curveVertex(positions.chin[0][0],positions.chin[0][1]) | |
curveVertex(positions.chin[2][0],positions.chin[2][1]) | |
curveVertex(positions.chin[14][0],positions.chin[14][1]) | |
curveVertex(positions.chin[16][0],positions.chin[16][1]) | |
curveVertex(positions.chin[16][0],positions.chin[16][1]) | |
endShape(CLOSE); | |
scale(0.33) | |
fill("#84bfbf") | |
stroke("#000000") | |
ellipse(2.3, -0.5, 3.2, 2.1) | |
stroke("#155fbf") | |
fill("#155fbf") | |
arc(2.3, -0.5,1.1,0.8,210,150, PIE) | |
//left EYE area | |
fill("#84bfbf") | |
stroke("#000000") | |
ellipse(-2.3, -0.5, 3.2, 2.1) | |
stroke("#155fbf") | |
fill("#155fbf") | |
arc(-2.3, -0.5,1.1,0.8,30,330, PIE) | |
} | |
pop() | |
//draw Nose area | |
push(); | |
stroke(0); | |
strokeJoin(ROUND); | |
fill(0); | |
if (nose_setting == 0){ | |
translate(-shift_face_x*0.1, -shift_face_y*1.2); | |
triangle(positions.nose_bridge[1][0], positions.nose_bridge[1][1],positions.nose_tip[1][0],positions.nose_tip[1][1],positions.nose_tip[3][0],positions.nose_tip[3][1]); | |
}else if (nose_setting == 1){ | |
translate(-shift_face_x*0.1, -shift_face_y*1.2); | |
triangle(positions.nose_bridge[0][0], positions.nose_bridge[0][1],positions.nose_tip[1][0],positions.nose_tip[1][1],positions.nose_tip[3][0],positions.nose_tip[3][1]); | |
}else{ | |
translate(-shift_face_x*0.1, -shift_face_y*1.2); | |
ellipse(positions.nose_bridge[2][0],positions.nose_bridge[2][1],0.1,1); | |
} | |
pop(); | |
//draw eyebrow | |
push() | |
if (eye_setting == 0){ | |
translate(shift_face_x*0.7,shift_face_y*0.6); | |
fill("#000000"); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[2][0],positions.left_eyebrow[2][1]); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]); | |
endShape(); | |
beginShape(); | |
curveVertex(positions.right_eyebrow[0][0]+2.5,positions.right_eyebrow[0][1]); | |
curveVertex(positions.right_eyebrow[0][0]+2.5,positions.right_eyebrow[0][1]); | |
curveVertex(positions.right_eyebrow[2][0]+2.5,positions.right_eyebrow[2][1]); | |
curveVertex(positions.right_eyebrow[4][0]+2.5,positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0]+2.5,positions.right_eyebrow[4][1]); | |
endShape(); | |
}else if (eye_setting == 1){ | |
translate(shift_face_x*0.7,shift_face_y*0.6); | |
noFill(); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[2][0],positions.left_eyebrow[2][1]); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]); | |
endShape(); | |
beginShape(); | |
curveVertex(positions.right_eyebrow[0][0]+2.5,positions.right_eyebrow[0][1]); | |
curveVertex(positions.right_eyebrow[0][0]+2.5,positions.right_eyebrow[0][1]); | |
curveVertex(positions.right_eyebrow[2][0]+2.5,positions.right_eyebrow[2][1]); | |
curveVertex(positions.right_eyebrow[4][0]+2.5,positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0]+2.5,positions.right_eyebrow[4][1]); | |
endShape(); | |
}else if (eye_setting == 2){ | |
translate(shift_face_x*0.7,shift_face_y*0.6); | |
fill("#000000"); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[3][0],positions.left_eyebrow[3][1]); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]); | |
endShape(); | |
beginShape(); | |
curveVertex(positions.right_eyebrow[0][0]+2.5,positions.right_eyebrow[0][1]); | |
curveVertex(positions.right_eyebrow[0][0]+2.5,positions.right_eyebrow[0][1]); | |
curveVertex(positions.right_eyebrow[3][0]+2.5,positions.right_eyebrow[3][1]); | |
curveVertex(positions.right_eyebrow[4][0]+2.5,positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0]+2.5,positions.right_eyebrow[4][1]); | |
endShape(); | |
}else { | |
translate(shift_face_x*0.7,shift_face_y*0.6); | |
noFill(); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[2][0],positions.left_eyebrow[2][1]); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]); | |
endShape(); | |
beginShape(); | |
curveVertex(positions.right_eyebrow[0][0]+2.5,positions.right_eyebrow[0][1]); | |
curveVertex(positions.right_eyebrow[0][0]+2.5,positions.right_eyebrow[0][1]); | |
curveVertex(positions.right_eyebrow[2][0]+2.5,positions.right_eyebrow[2][1]); | |
curveVertex(positions.right_eyebrow[4][0]+2.5,positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0]+2.5,positions.right_eyebrow[4][1]); | |
endShape(); | |
} | |
pop(); | |
//draw hair | |
push(); | |
strokeWeight(1.2); | |
scale(3.3); | |
if (hair_setting == 0){ | |
if (hair_colour == 0){ | |
stroke(hc1); | |
}else if (hair_colour == 1){ | |
stroke(hc2); | |
}else if (hair_colour ==2){ | |
stroke(hc3) | |
}else{ | |
stroke(hc1); | |
} | |
strokeWeight(0.7); | |
line(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1], positions.right_eyebrow[4][0],positions.right_eyebrow[4][1]); | |
}else if (hair_setting == 1){ | |
if (hair_colour == 0){ | |
fill(hc1); | |
}else if (hair_colour == 1){ | |
fill(hc2); | |
}else if (hair_colour ==2){ | |
fill(hc3) | |
}else if (hair_colour ==3){ | |
fill(hc4); | |
}else if (hair_colour ==4){ | |
fill(hc5); | |
}else{ | |
fill(hc6); | |
} | |
strokeWeight(0.2) | |
strokeJoin(ROUND); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0]-0.4,positions.left_eyebrow[0][1]-0.6); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]-0.8); | |
curveVertex(positions.right_eyebrow[3][0]+0.4,positions.right_eyebrow[3][1]-0.6); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0], positions.right_eyebrow[4][1]); | |
endShape(CLOSE); | |
}else if (hair_setting == 2){ | |
if (hair_colour == 0){ | |
fill(hc1); | |
}else if (hair_colour == 1){ | |
fill(hc2); | |
}else if (hair_colour ==2){ | |
fill(hc3) | |
}else if (hair_colour ==3){ | |
fill(hc4); | |
}else if (hair_colour ==4){ | |
fill(hc5); | |
}else{ | |
fill(hc6); | |
} | |
strokeWeight(0.2) | |
strokeJoin(ROUND); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[2][0]-0.8,positions.left_eyebrow[2][1]-1.2); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]-1.6); | |
curveVertex(positions.right_eyebrow[3][0]+0.8,positions.right_eyebrow[3][1]-0.6); | |
curveVertex(positions.right_eyebrow[4][0],positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0],positions.right_eyebrow[4][1]); | |
endShape(CLOSE); | |
}else if (hair_setting == 3){ | |
if (hair_colour == 0){ | |
fill(hc1); | |
}else if (hair_colour == 1){ | |
fill(hc2); | |
}else if (hair_colour ==2){ | |
fill(hc3) | |
}else if (hair_colour ==3){ | |
fill(hc4); | |
}else if (hair_colour ==4){ | |
fill(hc5); | |
}else{ | |
fill(hc6); | |
} | |
strokeWeight(0.2) | |
strokeJoin(ROUND); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[1][0]-0.3,positions.left_eyebrow[1][1]-0.8); | |
curveVertex(positions.left_eyebrow[2][0]+0.3,positions.left_eyebrow[2][1]-0.6); | |
curveVertex(positions.left_eyebrow[3][0]+0.4,positions.left_eyebrow[3][1]-0.5); | |
curveVertex(positions.left_eyebrow[4][0]+0.2,positions.left_eyebrow[4][1]-1.2); | |
curveVertex(positions.right_eyebrow[0][0]+0.6,positions.right_eyebrow[0][1]-0.6); | |
curveVertex(positions.right_eyebrow[1][0]+0.6,positions.right_eyebrow[1][1]-0.6); | |
curveVertex(positions.right_eyebrow[2][0]+0.4,positions.right_eyebrow[2][1]-0.8); | |
curveVertex(positions.right_eyebrow[3][0]+2, positions.right_eyebrow[3][1]+2); | |
curveVertex(positions.right_eyebrow[4][0]+2.5, positions.right_eyebrow[4][1]+1.2); | |
curveVertex(positions.right_eyebrow[4][0]+2, positions.right_eyebrow[4][1]+2); | |
curveVertex(positions.right_eyebrow[4][0],positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0],positions.right_eyebrow[4][1]); | |
endShape(CLOSE); | |
}else if (hair_setting == 4) { | |
if (hair_colour == 0){ | |
fill(hc1); | |
}else if (hair_colour == 1){ | |
fill(hc2); | |
}else if (hair_colour ==2){ | |
fill(hc3) | |
}else if (hair_colour ==3){ | |
fill(hc4); | |
}else if (hair_colour ==4){ | |
fill(hc5); | |
}else{ | |
fill(hc6); | |
} | |
strokeWeight(0.2) | |
strokeJoin(ROUND); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[0][0],positions.left_eyebrow[0][1]); | |
curveVertex(positions.left_eyebrow[3][0]-0.2,positions.left_eyebrow[3][1]-0.4); | |
curveVertex(positions.left_eyebrow[3][0]-0.3,positions.left_eyebrow[3][1]-0.6); | |
curveVertex(positions.left_eyebrow[2][0]-0.4,positions.left_eyebrow[2][1]-0.8); | |
curveVertex(positions.left_eyebrow[4][0],positions.left_eyebrow[4][1]-1.8); | |
curveVertex(positions.right_eyebrow[0][0]+0.6,positions.right_eyebrow[0][1]-0.5); | |
curveVertex(positions.right_eyebrow[1][0]+0.4,positions.right_eyebrow[1][1]-0.5); | |
curveVertex(positions.right_eyebrow[2][0]+0.2,positions.right_eyebrow[2][1]-0.8); | |
curveVertex(positions.right_eyebrow[4][0],positions.right_eyebrow[4][1]); | |
curveVertex(positions.right_eyebrow[4][0],positions.right_eyebrow[4][1]); | |
endShape(CLOSE); | |
}else { | |
if (hair_colour == 0){ | |
stroke(hc1); | |
}else if (hair_colour == 1){ | |
stroke(hc2); | |
}else{ | |
stroke(hc3); | |
} | |
noFill(); | |
translate(0,shift_face_y*0.15); | |
arc(positions.left_eyebrow[2][0], positions.left_eyebrow[2][1],1.5,0.3,0,180,open); | |
arc(positions.right_eyebrow[2][0], positions.right_eyebrow[2][1],1.5,0.3,0,180,open); | |
} | |
pop(); | |
//draw decorations (tatoo,headwear,etc) | |
push(); | |
translate(shift_face_x*2.2, shift_face_y*2.6); | |
if (symbol_value == 0){ | |
fill("#f20530") | |
stroke("#730217"); | |
let radius = 10; | |
beginShape(); | |
angleMode(RADIANS); | |
for(let i = 0; i<10; i++) { | |
var x = cos(radians(i * 18*2)) * radius*0.32; | |
var y = sin(radians(i * 18*2)) * radius*0.32; | |
vertex(x, y-2.2); | |
if (radius == 10) { | |
radius = 5; | |
}else{ | |
radius = 10; | |
} | |
} | |
endShape(CLOSE); | |
}else if (symbol_value == 1){ | |
fill("#4895d9"); | |
stroke("#052da6"); | |
let radius = 10; | |
beginShape(); | |
angleMode(RADIANS); | |
for(let i = 0; i<10; i++) { | |
var x = cos(radians(i * 18*8)) * radius*0.32; | |
var y = sin(radians(i * 18*8)) * radius*0.32; | |
vertex(x, y-2.2); | |
if (radius == 10) { | |
radius = 5; | |
}else{ | |
radius = 10; | |
} | |
}endShape(CLOSE); | |
}else if (symbol_value == 2){ | |
fill("#f2f2f2"); | |
stroke("#8c8984"); | |
let radius = 10; | |
beginShape(); | |
angleMode(RADIANS); | |
for(let i = 0; i<10; i++) { | |
var x = cos(radians(i * 18*9)) * radius*0.32; | |
var y = sin(radians(i * 18*9)) * radius*0.32; | |
vertex(x, y-2.2); | |
if (radius == 10) { | |
radius = 5; | |
}else{ | |
radius = 10; | |
} | |
} | |
endShape(CLOSE); | |
}else if (symbol_value == 3){ | |
translate(-shift_face_x*2.2, -shift_face_y*1.3); | |
fill("#000000"); | |
noStroke(); | |
ellipse(positions.nose_tip[4][0], positions.nose_bridge[0][1],0.6,3); | |
ellipse(positions.nose_tip[4][0], positions.nose_bridge[0][1],3,0.6); | |
}else if (symbol_value == 4){ | |
translate(-shift_face_x*2.2, -shift_face_y*1.8); | |
fill("#000000"); | |
noStroke(); | |
ellipse(positions.nose_tip[3][0], positions.nose_bridge[0][1],0.6,3.1); | |
ellipse(positions.nose_tip[3][0], 2*positions.nose_bridge[0][1],1,0.5); | |
}else if (symbol_value == 5){ | |
translate(-shift_face_x*2, -shift_face_y*1.8); | |
noFill() | |
stroke("#000000"); | |
rectMode(CENTER); | |
rect(positions.nose_tip[4][0], positions.nose_bridge[0][1],1.5,2.5,1,1,1,1); | |
fill("#000000"); | |
noStroke(); | |
ellipse(positions.nose_tip[4][0], positions.nose_bridge[0][1],0.6,3.1); | |
ellipse(positions.nose_tip[4][0], 2*positions.nose_bridge[0][1],1,0.5); | |
}else{ | |
translate(shift_face_x*0.4, -shift_face_y*0.2); | |
fill("#f29bb2") | |
stroke("#f24472") | |
angleMode(RADIANS); | |
strokeJoin(ROUND); | |
// triangle(positions.right_eyebrow[0][0],positions.right_eyebrow[0][1],positions.right_eyebrow[0][0]-3,positions.right_eyebrow[0][1]-2.5,positions.right_eyebrow[0][0]-3,positions.right_eyebrow[0][1]+2.5); | |
arc(positions.right_eyebrow[0][0],positions.right_eyebrow[0][1],8,4,PI-0.6*QUARTER_PI,PI+0.6*QUARTER_PI,PIE); | |
arc(positions.right_eyebrow[0][0],positions.right_eyebrow[0][1],8,4,0-0.6*QUARTER_PI,0+0.6*QUARTER_PI,PIE); | |
ellipse(positions.right_eyebrow[0][0],positions.right_eyebrow[0][1],2,1.6); | |
fill("#f24472"); | |
ellipse(positions.right_eyebrow[0][0],positions.right_eyebrow[0][1],0.4,1.55); | |
} | |
pop(); | |
angleMode(DEGREES); | |
//draw Mouth area | |
push(); | |
fill("#000000") | |
stroke(0); | |
if (eye_setting == 0) { | |
translate(0,-shift_face_y*1.5); | |
noFill() | |
beginShape(); | |
vertex(positions.top_lip[0][0],positions.top_lip[0][1]); | |
vertex(positions.top_lip[3][0],positions.top_lip[3][1]); | |
vertex(positions.top_lip[6][0],positions.top_lip[6][1]); | |
endShape(); | |
}else if (eye_setting == 1){ | |
translate(0,-shift_face_y*1.5); | |
fill("#f9a603") | |
beginShape(); | |
curveVertex(positions.bottom_lip[0][0],positions.bottom_lip[0][1]); | |
curveVertex(positions.bottom_lip[0][0],positions.bottom_lip[0][1]); | |
curveVertex(positions.bottom_lip[3][0],positions.bottom_lip[3][1]); | |
curveVertex(positions.bottom_lip[6][0],positions.bottom_lip[6][1]); | |
curveVertex(positions.bottom_lip[6][0],positions.bottom_lip[6][1]); | |
endShape(); | |
}else if(eye_setting == 2){ | |
translate(0,-shift_face_y*1.5); | |
noFill() | |
beginShape(); | |
vertex(positions.top_lip[0][0],positions.top_lip[0][1]); | |
vertex(positions.top_lip[3][0],positions.top_lip[3][1]); | |
vertex(positions.top_lip[6][0],positions.top_lip[6][1]); | |
endShape(); | |
}else { | |
translate(0,-shift_face_y*1.5); | |
fill("#f20530"); | |
beginShape(); | |
curveVertex(positions.bottom_lip[0][0],positions.bottom_lip[0][1]); | |
curveVertex(positions.bottom_lip[0][0],positions.bottom_lip[0][1]); | |
curveVertex(positions.bottom_lip[3][0],positions.bottom_lip[3][1]); | |
curveVertex(positions.bottom_lip[6][0],positions.bottom_lip[6][1]); | |
curveVertex(positions.bottom_lip[6][0],positions.bottom_lip[6][1]); | |
endShape(); | |
} | |
pop(); | |
//draw beard area | |
push(); | |
if (beard_setting == 0) { | |
} else if (beard_setting == 1) { | |
fill("#000000"); | |
beginShape(); | |
scale(3.3); | |
curveVertex(positions.chin[5][0],positions.chin[5][1]); | |
curveVertex(positions.chin[5][0],positions.chin[5][1]); | |
curveVertex(positions.chin[6][0],positions.chin[6][1]); | |
curveVertex(positions.chin[7][0],positions.chin[7][1]); | |
curveVertex(positions.chin[8][0],positions.chin[8][1]); | |
curveVertex(positions.chin[9][0],positions.chin[9][1]); | |
curveVertex(positions.chin[10][0],positions.chin[10][1]); | |
curveVertex(positions.chin[11][0],positions.chin[11][1]); | |
curveVertex(positions.chin[11][0],positions.chin[11][1]); | |
endShape(); | |
} else if (beard_setting == 2) { | |
translate(0,-shift_face_y*2.5); | |
fill("#141a26"); | |
strokeWeight(0.6) | |
stroke("#141a26"); | |
arc(positions.top_lip[3][0],positions.top_lip[3][1],1.5,0.7,0,180,CHORD); | |
} | |
pop(); | |
pop(); | |
} | |
/* set internal properties based on list numbers 0-100 */ | |
this.setProperties = function(settings) { | |
this.hair_setting = int(map(settings[0], 0, 100, 0, 5.1)); | |
this.face_setting = int(map(settings[1], 0, 100, 0, 3.1)); | |
this.nose_setting = int(map(settings[2], 0, 100, 0, 3)); | |
this.symbol_value = int(map(settings[3], 0, 100, 0, 6.1)); | |
this.eye_setting = int(map(settings[4], 0, 100, 0, 4.1)); | |
this.beard_setting = int(map(settings[5], 0, 100, 0, 2.1)); | |
this.hair_colour = int(map(settings[6],0, 100, 0,5.1)); | |
} | |
/* get internal properties as list of numbers 0-100 */ | |
this.getProperties = function() { | |
let settings = new Array(7); | |
settings[0] = int(map(this.hair_setting , 0, 5.1, 0, 100) + 50/5.1); | |
settings[1] = int(map(this.face_setting , 0, 3.1, 0, 100) + 50/3.1); | |
settings[2] = int(map(this.nose_setting , 0, 3, 0, 100) + 50/3); | |
settings[3] = int(map(this.symbol_value , 0, 6.1, 0, 100) + 50/6.1); | |
settings[4] = int(map(this.eye_setting , 0, 4.1,0,100) + 50/4.1); | |
settings[5] = int(map(this.beard_setting , 0, 2.1,0,100) + 50/2.1); | |
settings[6] = int(map(this.hair_colour , 0, 5.1,0,100) + 50/5.1); | |
return settings; | |
} | |
} |
/* | |
* FaceMap class - holds all informaiton about one mapped | |
* face and is able to draw itself. | |
*/ | |
// other variables can be in here too | |
// these control the colors used | |
const stroke_color = [95, 52, 8]; | |
function Face() { | |
// state variables for a face | |
this.cheek_size = 0; | |
this.cheek_colour = 0; | |
this.face_colour = 0; | |
this.lip_colour = 0; | |
this.eyelid_colour = 0; | |
//----------------------------------- | |
this.cheek_colour = ["#ffd1d1", "#ffb5b5", "#ffc1a6", "#fcb6e9", "#ffe6f2"]; | |
this.face_colour = ["#ffe9de", "#ffe3c2", "#fcd7c7", "#eba386", "#b37156"]; | |
this.lip_colour = ["#ff5c5c", "#fc8686", "#ffb3b3", "#ffc2e5", "#fa98d0", "#bf3459"]; | |
this.eyelid_colour =["#ff9696", "#ff7070", "#f5abff", "#945f9c", "#fca2cd", "#ffd9eb", "#ad6a89"]; | |
/* | |
* Draw a face with position lists that include: | |
* chin, right_eye, left_eye, right_eyebrow, left_eyebrow | |
* bottom_lip, top_lip, nose_tip, nose_bridge, | |
*/ | |
this.draw = function (positions) { | |
//---------------------------- | |
// FACE SHAPE | |
//---------------------------- | |
stroke(0); | |
strokeWeight(0.07) | |
fill(this.face_colour[this.skin_tone]); | |
beginShape(); | |
for(let i = 0; i < positions.chin.length; i++) { | |
curveVertex(positions.chin[i][0], positions.chin[i][1]); | |
curveVertex(positions.chin[i][0], positions.chin[i][1]); | |
} | |
for(let i = 4; i >= 0; i--) { | |
curveVertex(positions.right_eyebrow[i][0], positions.right_eyebrow[i][1]); | |
} | |
for(let i = 4; i >= 0; i--) { | |
curveVertex(positions.left_eyebrow[i][0], positions.left_eyebrow[i][1]); | |
} | |
curveVertex(positions.chin[1][0], positions.chin[0][1]); | |
curveVertex(positions.chin[0][0], positions.chin[0][1]); | |
curveVertex(positions.chin[0][0], positions.chin[0][1]); | |
endShape(); | |
//------------------------------ | |
// CHEEKS | |
//------------------------------ | |
noStroke(); | |
fill(this.cheek_colour[this.blush]); | |
// LEFT CHEEK | |
let left_cheek = average_point(positions.left_eye); | |
let right_cheek = average_point(positions.right_eye); | |
let cheek_sizes = [left_cheek[0]*0.75, left_cheek[0], left_cheek[0]*1.3]; | |
if(this.cheek_size == 0) { | |
ellipse(left_cheek[0], left_cheek[1] + 0.8, cheek_sizes[this.cheek_size], | |
cheek_sizes[this.cheek_size]); | |
ellipse(right_cheek[0], right_cheek[1] + 0.8, cheek_sizes[this.cheek_size], | |
cheek_sizes[this.cheek_size]); | |
} | |
else if(this.cheek_size == 1) { | |
ellipse(left_cheek[0], left_cheek[1] + 0.8, cheek_sizes[this.cheek_size], | |
cheek_sizes[this.cheek_size]); | |
ellipse(right_cheek[0], right_cheek[1] + 0.8, cheek_sizes[this.cheek_size], | |
cheek_sizes[this.cheek_size]); | |
} | |
else if(this.cheek_size == 2) { | |
ellipse(left_cheek[0], left_cheek[1] + 0.8, cheek_sizes[this.cheek_size], | |
cheek_sizes[this.cheek_size]); | |
ellipse(right_cheek[0], right_cheek[1] + 0.8, cheek_sizes[this.cheek_size], | |
cheek_sizes[this.cheek_size]); | |
} | |
//------------------------------ | |
// EYEBROWS | |
//------------------------------ | |
fill(0); | |
stroke(0); | |
strokeWeight(0.07); | |
// LEFT EYEBROW | |
beginShape(); | |
for(let i = 1; i < positions.left_eyebrow.length; i++) { | |
curveVertex(positions.left_eyebrow[i][0], positions.left_eyebrow[i][1]); | |
curveVertex(positions.left_eyebrow[i][0], positions.left_eyebrow[i][1]); | |
} | |
endShape(); | |
// RIGHT EYEBROW | |
beginShape(); | |
for(let i = 0; i < 4; i++) { | |
curveVertex(positions.right_eyebrow[i][0], positions.right_eyebrow[i][1]); | |
curveVertex(positions.right_eyebrow[i][0], positions.right_eyebrow[i][1]); | |
} | |
endShape(); | |
//---------------------------- | |
// EYELIDS | |
//---------------------------- | |
let left_eyelid = average_point(positions.left_eye); | |
let right_eyelid = average_point(positions.right_eye); | |
noStroke(); | |
fill(this.eyelid_colour[this.eyeshadow]); | |
arc(left_eyelid[0] + 0.03, left_eyelid[1] + 0.03, 0.6, 0.6, 180, 360); | |
arc(right_eyelid[0] + 0.03, right_eyelid[1] + 0.03, 0.6, 0.6, 180, 360); | |
//---------------------------- | |
// EYE SHAPE | |
//---------------------------- | |
fill(255); | |
stroke(0); | |
strokeWeight(0.05); | |
// LEFT EYE | |
beginShape(); | |
for(let i = 0; i < positions.left_eye.length; i++) { | |
curveVertex(positions.left_eye[i][0], positions.left_eye[i][1]); | |
curveVertex(positions.left_eye[i][0], positions.left_eye[i][1]); | |
} | |
curveVertex(positions.left_eye[0][0], positions.left_eye[0][1]); | |
curveVertex(positions.left_eye[0][0], positions.left_eye[0][1]); | |
endShape(); | |
//------------------ | |
// RIGHT EYE | |
beginShape(); | |
for(let i = 0; i < positions.left_eye.length; i++) { | |
curveVertex(positions.right_eye[i][0], positions.right_eye[i][1]); | |
curveVertex(positions.right_eye[i][0], positions.right_eye[i][1]); | |
} | |
curveVertex(positions.right_eye[0][0], positions.right_eye[0][1]); | |
curveVertex(positions.right_eye[0][0], positions.right_eye[0][1]); | |
endShape(); | |
//---------------------------- | |
// IRIS | |
//---------------------------- | |
let left_eye = average_point(positions.left_eye); | |
let right_eye = average_point(positions.right_eye); | |
noStroke(); | |
fill(0); | |
ellipse(left_eye[0], left_eye[1], 0.2, 0.15); | |
ellipse(right_eye[0], right_eye[1], 0.2, 0.15); | |
//---------------------------- | |
// TEETH | |
//---------------------------- | |
fill(255); | |
noStroke(); | |
beginShape(); | |
for(let i = 0; i < 7; i++) { | |
curveVertex(positions.top_lip[i][0], positions.top_lip[i][1]); | |
curveVertex(positions.top_lip[i][0], positions.top_lip[i][1]); | |
} | |
for(let i = 0; i < 7; i++) { | |
curveVertex(positions.bottom_lip[i][0], positions.bottom_lip[i][1]); | |
curveVertex(positions.bottom_lip[i][0], positions.bottom_lip[i][1]); | |
} | |
endShape(); | |
//---------------------------- | |
// TOP LIP | |
//---------------------------- | |
fill(this.lip_colour[this.lipstick]); | |
noStroke(); | |
beginShape(); | |
for(let i = 0; i < positions.top_lip.length; i++) { | |
curveVertex(positions.top_lip[i][0], positions.top_lip[i][1]); | |
curveVertex(positions.top_lip[i][0], positions.top_lip[i][1]); | |
} | |
curveVertex(positions.top_lip[0][0], positions.top_lip[0][1]); | |
curveVertex(positions.top_lip[0][0], positions.top_lip[0][1]); | |
endShape(); | |
//------------------------------- | |
// BOTTOM LIP | |
//------------------------------- | |
beginShape(); | |
for (let i = 0; i < positions.bottom_lip.length; i++) { | |
curveVertex(positions.bottom_lip[i][0], positions.bottom_lip[i][1]); | |
curveVertex(positions.bottom_lip[i][0], positions.bottom_lip[i][1]); | |
} | |
curveVertex(positions.bottom_lip[0][0], positions.bottom_lip[0][1]); | |
curveVertex(positions.bottom_lip[0][0], positions.bottom_lip[0][1]); | |
endShape(); | |
//------------------------------- | |
// NOSE BRIDGE | |
//------------------------------- | |
noFill(); | |
stroke(0); | |
strokeWeight(0.08); | |
beginShape(); | |
curveVertex(positions.nose_bridge[0][0], positions.nose_bridge[0][0]); | |
curveVertex(positions.nose_bridge[0][0], positions.nose_bridge[0][1]); | |
curveVertex(positions.nose_bridge[1][0], positions.nose_bridge[1][1]); | |
curveVertex(positions.nose_bridge[2][0], positions.nose_bridge[2][1]); | |
curveVertex(positions.nose_bridge[3][0], positions.nose_bridge[3][1]); | |
endShape(); | |
//------------------------------- | |
// NOSE TIP | |
//------------------------------- | |
stroke(0); | |
strokeWeight(0.08); | |
beginShape(); | |
curveVertex(positions.nose_tip[0][0], positions.nose_tip[0][1] -0.1); | |
curveVertex(positions.nose_tip[1][0], positions.nose_tip[1][1] -0.1); | |
curveVertex(positions.nose_tip[2][0], positions.nose_tip[2][1] -0.1); | |
curveVertex(positions.nose_tip[3][0], positions.nose_tip[3][1] -0.1); | |
curveVertex(positions.nose_tip[4][0], positions.nose_tip[4][1] -0.1); | |
endShape(); | |
} | |
//------------------------------------ | |
/* set internal properties based on list numbers 0-100 */ | |
this.setProperties = function (settings) { | |
this.cheek_size = int(map(settings[0], 0, 100, 0, 2)); | |
this.blush = int(map(settings[1], 0, 100, 0, 4)); | |
this.skin_tone = int(map(settings[2], 0, 100, 0, 4)); | |
this.lipstick = int(map(settings[3], 0, 100, 0, 5)); | |
this.eyeshadow = int(map(settings[4], 0, 100, 0, 6)); | |
} | |
/* get internal properties as list of numbers 0-100 */ | |
this.getProperties = function () { | |
let settings = new Array(5); | |
settings[0] = map(this.cheek_size, 0, 2, 0, 100); | |
settings[1] = map(this.blush, 0, 4, 0, 100); | |
settings[2] = map(this.skin_tone, 0, 4, 0, 100); | |
settings[3] = map(this.lipstick, 0, 5, 0, 100); | |
settings[4] = map(this.eyeshadow, 0, 6, 0, 100); | |
return settings; | |
} | |
} | |
// given an array of [x,y] points, return the average | |
function average_point(list) { | |
var sum_x = 0; | |
var sum_y = 0; | |
var num_points = 0; | |
for (var i = 0; i < list.length; i++) { | |
sum_x += list[i][0]; | |
sum_y += list[i][1]; | |
num_points += 1; | |
} | |
return [sum_x / num_points, sum_y / num_points]; | |
} |
/* | |
* FaceMap class - holds all informaiton about one mapped | |
* face and is able to draw itself. | |
*/ | |
// other variables can be in here too | |
// these control the colors used | |
const bg_color = [225, 206, 187]; | |
const fg_color = [151, 102, 52]; | |
const stroke_color = [95, 52, 8]; | |
// skin colors | |
let outLine1 = '#F2C7A9'; | |
let skin1 = '#FDF0E7'; // linen | |
let skinLt1 = 'FEF9F6' // snow | |
let outLine2 = '#CC7A51'; | |
let skin2 = '#FBBB9B'; // peach-orange | |
let skinLt2 = '#FDDDCD'; // unbleached silk | |
let outLine3 = '#9C531D'; | |
let skin3 = '#F58D3F'; // tyger's eye | |
let skinLt3 = '#FBD1B2'; // apricot | |
let outLine4 = '#723502'; | |
let skin4 = '#B25303'; // windsor tan | |
let skinLt4 = '#DCB08C'; // tumbleweed | |
let outLine5 = '#451405'; | |
let skin5 = '#6C1E07'; // kenyan copper | |
let skinLt5 = '#D6C1BB'; // pale silver | |
let outLine; | |
let skinColor; | |
let skinLt; | |
// mouth colors | |
let mouthColor = '#BA2E2E'; | |
function Face() { | |
// these are state variables for a face | |
// variables change from 0 - 1 | |
this.skin = 2; | |
this.eyeOpenL = 0.5; | |
this.eyeOpenR = 0.5; | |
this.earL = 0.5; | |
this.earR = 0.5; | |
this.gender = 1; | |
this.blush = 1; | |
this.freckles = 1; | |
this.mouthOpen = 0; | |
/* | |
* Draw a face with position lists that include: | |
* chin, right_eye, left_eye, right_eyebrow, left_eyebrow | |
* bottom_lip, top_lip, nose_tip, nose_bridge, | |
*/ | |
this.draw = function(positions) { | |
// vars | |
// eyes positon | |
let eyePosL = average_point(positions.left_eye); | |
let eyePosR = average_point(positions.right_eye); | |
// chin position | |
let chinLs = [positions.chin[7], positions.chin[8], positions.chin[9]]; | |
let chinBt = average_point(chinLs); | |
// nose position | |
let nose = average_point(positions.nose_tip); | |
// mouth position | |
let mouthUp = average_point(positions.top_lip); | |
let mouthDw = average_point(positions.bottom_lip); | |
// overall face width | |
let faceWidth = abs(positions.chin[0][0] - positions.chin[16][0]); | |
let faceScaleX = map(faceWidth, 3, 4.5, 0.8, 1.1); | |
// center point of the face | |
let centerX = (eyePosL[0] + eyePosR[0]) / 2; | |
let centerY = (eyePosL[1] + eyePosR[1]) / 1.0; | |
angleMode(DEGREES); | |
strokeWeight(0.1); | |
// set up skin colours | |
if(this.skin == 1){ | |
outLine = outLine1; | |
skinColor = skin1; | |
skinLt = skinLt1; | |
}else if(this.skin == 2){ | |
outLine = outLine2; | |
skinColor = skin2; | |
skinLt = skinLt2; | |
}else if(this.skin == 3){ | |
outLine = outLine3; | |
skinColor = skin3; | |
skinLt = skinLt3; | |
}else if(this.skin == 4){ | |
outLine = outLine4; | |
skinColor = skin4; | |
skinLt = skinLt4; | |
}else{ | |
outLine = outLine5; | |
skinColor = skin5; | |
skinLt = skinLt5; | |
} | |
push(); | |
// ears | |
stroke(outLine); | |
fill(skinColor); | |
let earOffsetX = map(faceWidth, 3, 4.5, -0.2, 0.1); | |
// left ear | |
push(); | |
let earRotL = map(this.earL, 0, 1, -10, 10); | |
translate(centerX - (1 + earOffsetX), centerY ); | |
rotate(earRotL); | |
bezier(-0.7, 0.3, -0.9, -2, 0.1, -4, 0.9, 0.3); | |
translate(0.05, 0); | |
scale(0.7, 0.6); | |
fill(skinLt); | |
noStroke(); | |
bezier(-0.7, 0.3, -0.9, -2, 0.1, -4, 0.9, 0.3); | |
pop(); | |
// right ear | |
push(); | |
let earRotR = map(this.earR, 0, 1, 10, -10); | |
translate(centerX + (1 + earOffsetX), centerY ); | |
rotate(earRotR); | |
bezier(-0.9, 0.3, -0.1, -4, 0.9, -2, 0.7, 0.3); | |
translate(-0.05, 0); | |
scale(0.7, 0.6); | |
fill(skinLt); | |
noStroke(); | |
bezier(-0.9, 0.3, -0.1, -4, 0.9, -2, 0.7, 0.3); | |
pop(); | |
// face (color) | |
push(); //push for whole face change | |
translate(0, -0.1); | |
scale(faceScaleX, 0.9); | |
push(); | |
noStroke(); | |
fill(skinColor); | |
arc(0, -1.45, 3.7, 3.5, 200, 340, OPEN); | |
beginShape(); | |
vertex(-1.71, - 2.11); | |
vertex( 1.71, - 2.11); | |
vertex( 2.01, chinBt[1] - 1.49); | |
vertex(-2.01, chinBt[1] - 1.49); | |
endShape(); | |
bezier(-1.7, -2.1, -1.9, -1.9, -2.25, -0.1, -2, chinBt[1] - 1.5); | |
bezier( 1.7, -2.1, 1.9, -1.9, 2.25, -0.1, 2, chinBt[1] - 1.5); | |
bezier(-2, chinBt[1] - 1.5, -1.8, chinBt[1], 1.8, chinBt[1], 2, chinBt[1] - 1.5); | |
// light-color parts | |
fill(skinLt); | |
bezier(-1.6, chinBt[1] - 1.59, -1.0, -0.8, 1.0, -0.8, 1.6, chinBt[1] - 1.59); | |
bezier(-1.6, chinBt[1] - 1.6, -2.2, chinBt[1], 2.2, chinBt[1], 1.6, chinBt[1] - 1.6); | |
pop(); | |
// face (stroke) | |
push(); | |
stroke(outLine); | |
noFill(); | |
arc(0, -1.45, 3.7, 3.5, 240, 250, OPEN); | |
arc(0, -1.45, 3.7, 3.5, 280, 295, OPEN); | |
arc(0, -1.45, 3.7, 3.5, 210, 215, OPEN); | |
arc(0, -1.45, 3.7, 3.5, 325, 330, OPEN); | |
bezier(-1.8, -1.8, -1.93, -1.6, -2.02, -1.3, -2.0, -1.1); | |
bezier(-2.0, -1.1, -2.1, -0.9, -2.15, -0.4, -2.05, -0.2); | |
bezier( 1.8, -1.8, 1.93, -1.6, 2.02, -1.3, 2.0, -1.1); | |
bezier( 2.0, -1.1, 2.1, -0.9, 2.15, -0.4, 2.05, -0.2); | |
bezier(-2, chinBt[1] - 1.5, -1.8, chinBt[1], 1.8, chinBt[1], 2, chinBt[1] - 1.5); | |
pop(); | |
// fur | |
fill(skinColor); | |
//left cheek fur | |
push(); | |
translate(-2.05, -0.08); | |
rotate(-90); | |
noStroke(); | |
arc(0, 0, 0.2, 0.15, 180, 360, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.2, 0.15, 280, 360, OPEN); | |
pop(); | |
push(); | |
translate(-2.0, 0.25); | |
rotate(-95); | |
noStroke(); | |
arc(0, 0, 0.35, 0.35, 180, 360, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.35, 0.35, 250, 360, OPEN); | |
pop(); | |
push(); | |
translate(-2.0, 0.45); | |
rotate(-95); | |
noStroke(); | |
arc(0, 0, 0.15, 0.1, 180, 360, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.15, 0.1, 270, 360, OPEN); | |
pop(); | |
//right cheek fur | |
push(); | |
translate( 2.05, -0.08); | |
rotate( 90); | |
noStroke(); | |
arc(0, 0, 0.2, 0.15, 180, 360, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.2, 0.15, 180, 280, OPEN); | |
pop(); | |
push(); | |
translate( 2.0, 0.25); | |
rotate( 95); | |
noStroke(); | |
arc(0, 0, 0.35, 0.35, 180, 360, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.35, 0.35, 180, 300, OPEN); | |
pop(); | |
push(); | |
translate( 2.0, 0.45); | |
rotate( 95); | |
noStroke(); | |
arc(0, 0, 0.15, 0.1, 180, 360, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.15, 0.1, 180, 260, OPEN); | |
pop(); | |
// left ear fur | |
push(); | |
translate( -1.65, -2.1); | |
rotate( 100); | |
noStroke(); | |
arc(0, 0, 0.45, 0.4, 0, 180, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.45, 0.5, 80, 180, OPEN); | |
pop(); | |
push(); | |
translate( -1.75, -1.95); | |
rotate(80); | |
noStroke(); | |
arc(0, 0, 0.2, 0.15, 0, 180, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.2, 0.15, 90, 180, OPEN); | |
pop(); | |
// right ear fur | |
push(); | |
translate( 1.65, -2.1); | |
rotate(80); | |
noStroke(); | |
arc(0, 0, 0.45, 0.4, 180, 0, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.45, 0.5, 180, 260, OPEN); | |
pop(); | |
push(); | |
translate( 1.75, -1.95); | |
rotate( 100); | |
noStroke(); | |
arc(0, 0, 0.2, 0.15, 180, 0, OPEN); | |
stroke(outLine); | |
arc(0, 0, 0.2, 0.15, 180, 270, OPEN); | |
pop(); | |
// head-top fur | |
push(); | |
translate(-0.45, -3.15); | |
rotate(-9); | |
noStroke(); | |
arc(0, 0, 0.2, 0.15, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.2, 0.15, 180, 270, OPEN); | |
pop(); | |
push(); | |
translate(-0.15, -3.18); | |
noStroke(); | |
arc(0, 0, 0.4, 0.35, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.4, 0.35, 190, 280, OPEN); | |
pop(); | |
push(); | |
translate(0.15, -3.15); | |
rotate(5); | |
noStroke(); | |
arc(0, 0, 0.25, 0.2, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.25, 0.2, 200, 280, OPEN); | |
pop(); | |
// left up fur | |
push(); | |
translate(-0.96, -2.94); | |
rotate(-30); | |
noStroke(); | |
arc(0, 0, 0.15, 0.1, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.15, 0.1, 320, 360, OPEN); | |
pop(); | |
push(); | |
translate(-1.2, -2.79); | |
rotate(-40); | |
noStroke(); | |
arc(0, 0, 0.4, 0.35, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.4, 0.35, 285, 360, OPEN); | |
pop(); | |
push(); | |
translate(-1.36, -2.62); | |
rotate(-45); | |
noStroke(); | |
arc(0, 0, 0.28, 0.25, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.28, 0.25, 300, 360, OPEN); | |
pop(); | |
// right up fur | |
push(); | |
translate(0.9, -2.98); | |
rotate(30); | |
noStroke(); | |
arc(0, 0, 0.25, 0.2, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.25, 0.2, 180, 280, OPEN); | |
pop(); | |
push(); | |
translate(1.2, -2.79); | |
rotate(40); | |
noStroke(); | |
arc(0, 0, 0.4, 0.35, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.4, 0.35, 185, 280, OPEN); | |
pop(); | |
push(); | |
translate(1.36, -2.62); | |
rotate(45); | |
noStroke(); | |
arc(0, 0, 0.25, 0.2, 175, 5, OPEN); | |
stroke(outLine); | |
noFill(); | |
arc(0, 0, 0.25, 0.2, 240, 280, OPEN); | |
pop(); | |
pop(); // pop for whole face change | |
// eye-borws | |
push(); | |
stroke(skinLt); | |
strokeWeight(0.15); | |
noFill(); | |
translate(0, 0.1); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[1][0], positions.left_eyebrow[1][1]); | |
curveVertex(positions.left_eyebrow[2][0] + 0.08, positions.left_eyebrow[2][1]); | |
curveVertex(positions.left_eyebrow[3][0] - 0.08, positions.left_eyebrow[3][1]); | |
curveVertex(positions.left_eyebrow[4][0], positions.left_eyebrow[4][1]); | |
endShape(); | |
beginShape(); | |
curveVertex(positions.right_eyebrow[3][0], positions.right_eyebrow[3][1]); | |
curveVertex(positions.right_eyebrow[2][0] - 0.08, positions.right_eyebrow[2][1]); | |
curveVertex(positions.right_eyebrow[1][0] + 0.08, positions.right_eyebrow[1][1]); | |
curveVertex(positions.right_eyebrow[0][0], positions.right_eyebrow[0][1]); | |
endShape(); | |
pop(); | |
push(); | |
noFill(); | |
beginShape(); | |
curveVertex(positions.left_eyebrow[1][0], positions.left_eyebrow[1][1]); | |
curveVertex(positions.left_eyebrow[2][0], positions.left_eyebrow[2][1]); | |
curveVertex(positions.left_eyebrow[3][0], positions.left_eyebrow[3][1]); | |
curveVertex(positions.left_eyebrow[4][0], positions.left_eyebrow[4][1]); | |
endShape(); | |
beginShape(); | |
curveVertex(positions.right_eyebrow[3][0], positions.right_eyebrow[3][1]); | |
curveVertex(positions.right_eyebrow[2][0], positions.right_eyebrow[2][1]); | |
curveVertex(positions.right_eyebrow[1][0], positions.right_eyebrow[1][1]); | |
curveVertex(positions.right_eyebrow[0][0], positions.right_eyebrow[0][1]); | |
endShape(); | |
pop(); | |
// left eye | |
push(); | |
translate(eyePosL[0] - 0.05, eyePosL[1] + 0.1); | |
noStroke(); | |
let eyeLipL = map (this.eyeOpenL, 0, 1, -0.09, 0.12); | |
// eye base | |
let fixerL = map(this.eyeOpenL, 0, 1, - 0.5, - 0.3); | |
noStroke(); | |
fill(skinLt); | |
arc(0, 0, 0.6, 0.5, 0, 180); | |
bezier(- 0.3, 0, -0.32, fixerL, 0.32, fixerL, 0.3, 0); | |
// pupil | |
fill(10); | |
ellipse(0, 0, 0.5); | |
// eye-lip | |
push(); | |
stroke(10); | |
strokeWeight(0.08); | |
noFill(); | |
rotate(-5); | |
arc(0, -0.15 + eyeLipL, 0.6, 0.4, 200, 340); | |
// eye-lash | |
if(this.gender == 0){ | |
// female, eye-lashes | |
arc(-0.04, -0.4 + eyeLipL, 0.5, 0.5, 148, 165); | |
}else{ | |
// male, nothing | |
} | |
pop(); | |
// fixer | |
noStroke(); | |
let fixL1 = map (this.eyeOpenL, 0, 1, 180, 269); | |
let fixL2 = map (this.eyeOpenL, 0, 1, 360, 270); | |
pop(); | |
// right eye | |
push(); | |
translate(eyePosR[0] + 0.05, eyePosR[1] + 0.1); | |
noStroke(); | |
let eyeLipR = map (this.eyeOpenR, 0, 1, -0.09, 0.12); | |
// eye base | |
let fixerR = map(this.eyeOpenR, 0, 1, - 0.5, - 0.3); | |
noStroke(); | |
fill(skinLt); | |
arc(0, 0, 0.6, 0.5, 0, 180); | |
bezier(- 0.3, 0, -0.32, fixerR, 0.32, fixerR, 0.3, 0); | |
// pupil | |
fill(10); | |
ellipse(0, 0, 0.5); | |
// eye-lip | |
push(); | |
stroke(10); | |
strokeWeight(0.08); | |
noFill(); | |
rotate(5); | |
arc(0, -0.15 + eyeLipR, 0.6, 0.4, 200, 340); | |
// eye-lash | |
if(this.gender == 0){ | |
// female, eye-lashes | |
arc( 0.04, -0.4 + eyeLipR, 0.5, 0.5, 10, 27); | |
}else{ | |
// male, nothing | |
} | |
pop(); | |
pop(); | |
// nose | |
push(); | |
noStroke(); | |
strokeJoin(ROUND); | |
fill(10); | |
push(); | |
translate(nose[0] - 0.05, nose[1]); | |
rotate(-45); | |
arc(0, 0, 0.25, 0.4, 180, 360, OPEN); | |
pop(); | |
push(); | |
translate(nose[0] + 0.05, nose[1]); | |
rotate( 45); | |
arc(0, 0, 0.25, 0.4, 180, 360, OPEN); | |
pop(); | |
push(); | |
translate(nose[0], nose[1] + 0.04); | |
arc(0, 0, 0.31, 0.2, 0, 180, OPEN); | |
pop(); | |
quad(nose[0] - 0.15, nose[1] - 0.15, nose[0] + 0.15, nose[1] - 0.15, nose[0] + 0.1, nose[1] + 0.05, nose[0] - 0.1, nose[1] + 0.05); | |
pop(); | |
// mouth | |
let mouthDis = abs(mouthUp[1] - mouthDw[1]); | |
push(); | |
translate(mouthUp[0], mouthUp[1]); | |
noStroke(); | |
fill(mouthColor); | |
arc(0, 0.01, 0.6, mouthDis * 2, 10, 170, OPEN); | |
fill(skinLt); | |
stroke(10); | |
strokeWeight(0.08); | |
arc(-0.2, 0, 0.4, 0.3, 0, 170); | |
arc( 0.2, 0, 0.4, 0.3, 10, 180); | |
pop(); | |
// gender | |
if(this.gender == 0){ | |
// female | |
push(); | |
translate(-1.35, -2.55); | |
rotate(10); | |
noStroke(); | |
fill('#5fa55a'); | |
for (let i = 0; i < 3; i ++) { | |
ellipse(0, 0, 0.45, 0.22); | |
rotate(60); | |
} | |
fill(255); | |
ellipse(0, 0, 0.1); | |
pop(); | |
push(); | |
translate(-1, -2.78); | |
noStroke(); | |
fill('#f6d51f'); | |
for (let i = 0; i < 3; i ++) { | |
ellipse(0, 0, 0.7, 0.35); | |
rotate(60); | |
} | |
fill(255); | |
ellipse(0, 0, 0.15); | |
pop(); | |
push(); | |
translate(-0.6, -2.9); | |
rotate(20); | |
noStroke(); | |
fill('#fa8925'); | |
for (let i = 0; i < 3; i ++) { | |
ellipse(0, 0, 0.45, 0.22); | |
rotate(60); | |
} | |
fill(255); | |
ellipse(0, 0, 0.1); | |
pop(); | |
push(); | |
translate( 1.2, -2.65); | |
rotate(20); | |
noStroke(); | |
fill('#01b4bc'); | |
for (let i = 0; i < 3; i ++) { | |
ellipse(0, 0, 0.45, 0.22); | |
rotate(60); | |
} | |
fill(255); | |
ellipse(0, 0, 0.1); | |
pop(); | |
push(); | |
translate( 0.8, -2.85); | |
rotate(15); | |
noStroke(); | |
fill('#fa5457'); | |
for (let i = 0; i < 3; i ++) { | |
ellipse(0, 0, 0.7, 0.35); | |
rotate(60); | |
} | |
fill(255); | |
ellipse(0, 0, 0.15); | |
pop(); | |
}else{ | |
// male | |
fill(50); | |
stroke(0); | |
rectMode(CENTER); | |
push(); | |
translate(chinBt[0] - 0.45, chinBt[1] - 0.52); | |
rotate(-15); | |
rect(0, 0.2, 0.6, 0.28, 0.1); | |
rotate(20); | |
rect(0, 0, 0.6, 0.38, 0.1); | |
line(0.1, 0, 0.2, 0); | |
pop(); | |
push(); | |
translate(chinBt[0] + 0.45, chinBt[1] - 0.52); | |
rotate(15); | |
rect(0, 0.2, 0.6, 0.28, 0.1); | |
rotate(-20); | |
rect(0, 0, 0.6, 0.38, 0.1); | |
line(- 0.1, 0, - 0.2, 0); | |
pop(); | |
rect(chinBt[0], chinBt[1] - 0.47, 0.4, 0.5, 0.1); | |
} | |
// blush | |
if(this.blush == 0){ | |
push(); | |
stroke('#EC6054'); | |
strokeWeight(0.18); | |
line(nose[0] - 0.6, nose[1] - 0.35, nose[0] - 0.8, nose[1] - 0.15); | |
line(nose[0] - 0.9, nose[1] - 0.35, nose[0] - 1.1, nose[1] - 0.15); | |
line(nose[0] + 0.8, nose[1] - 0.35, nose[0] + 0.6, nose[1] - 0.15); | |
line(nose[0] + 1.1, nose[1] - 0.35, nose[0] + 0.9, nose[1] - 0.15); | |
pop(); | |
}else{ | |
// do not do anything | |
} | |
// freckles | |
if(this.freckles == 0){ | |
push(); | |
fill(outLine); | |
noStroke(); | |
ellipse(nose[0] - 0.4, nose[1] - 0.4, 0.08); | |
ellipse(nose[0] - 0.6, nose[1] - 0.15, 0.08); | |
ellipse(nose[0] - 0.8, nose[1] - 0.35, 0.08); | |
ellipse(nose[0] - 1.1, nose[1] - 0.2, 0.08); | |
ellipse(nose[0] + 0.4, nose[1] - 0.4, 0.08); | |
ellipse(nose[0] + 0.6, nose[1] - 0.15, 0.08); | |
ellipse(nose[0] + 0.8, nose[1] - 0.35, 0.08); | |
ellipse(nose[0] + 1.1, nose[1] - 0.2, 0.08); | |
pop(); | |
}else{ | |
// do not do anything | |
} | |
pop(); | |
} | |
/* set internal properties based on list numbers 0-100 */ | |
this.setProperties = function(settings) { | |
this.skin = int(map(settings[0], 0, 100, 1, 6)); | |
this.eyeOpenL = map(settings[1], 0, 100, 0, 1); | |
this.eyeOpenR = map(settings[2], 0, 100, 0, 1); | |
this.earL = map(settings[3], 0, 100, 0, 1); | |
this.earR = map(settings[4], 0, 100, 0, 1); | |
this.gender = int(map(settings[5], 0, 100, 0, 2)); | |
this.blush = int(map(settings[6], 0, 100, 0, 2)); | |
this.freckles = int(map(settings[7], 0, 100, 0, 2)); | |
} | |
/* get internal properties as list of numbers 0-100 */ | |
this.getProperties = function() { | |
let settings = new Array(3); | |
settings[0] = map(this.skin, 1, 6, 0, 100); | |
settings[1] = map(this.eyeOpenL, 0, 1, 0, 100); | |
settings[2] = map(this.eyeOpenR, 0, 1, 0, 100); | |
settings[3] = map(this.earL, 0, 1, 0, 100); | |
settings[4] = map(this.earR, 0, 1, 0, 100); | |
settings[5] = map(this.gender, 0, 2, 0, 100); | |
settings[6] = map(this.blush, 0, 2, 0, 100); | |
settings[7] = map(this.freckles, 0, 2, 0, 100); | |
return settings; | |
} | |
} | |
// given an array of [x,y] points, return the average | |
function average_point(list) { | |
var sum_x = 0; | |
var sum_y = 0; | |
var num_points = 0; | |
for(var i=0; i<list.length; i++) { | |
sum_x += list[i][0]; | |
sum_y += list[i][1]; | |
num_points += 1; | |
} | |
return [sum_x / num_points, sum_y / num_points]; | |
} |
(function (global, factory) { | |
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | |
typeof define === 'function' && define.amd ? define(factory) : | |
(global.clm = factory()); | |
}(this, (function () { 'use strict'; | |
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | |
function createCommonjsModule(fn, module) { | |
return module = { exports: {} }, fn(module, module.exports), module.exports; | |
} | |
var numeric1_2_6 = createCommonjsModule(function (module, exports) { | |
"use strict"; | |
var numeric = exports; | |
if(typeof commonjsGlobal !== "undefined") { commonjsGlobal.numeric = numeric; } | |
numeric.version = "1.2.6"; | |
// 1. Utility functions | |
numeric.bench = function bench (f,interval) { | |
var t1,t2,n,i; | |
if(typeof interval === "undefined") { interval = 15; } | |
n = 0.5; | |
t1 = new Date(); | |
while(1) { | |
n*=2; | |
for(i=n;i>3;i-=4) { f(); f(); f(); f(); } | |
while(i>0) { f(); i--; } | |
t2 = new Date(); | |
if(t2-t1 > interval) break; | |
} | |
for(i=n;i>3;i-=4) { f(); f(); f(); f(); } | |
while(i>0) { f(); i--; } | |
t2 = new Date(); | |
return 1000*(3*n-1)/(t2-t1); | |
}; | |
numeric._myIndexOf = (function _myIndexOf(w) { | |
var n = this.length,k; | |
for(k=0;k<n;++k) if(this[k]===w) return k; | |
return -1; | |
}); | |
numeric.myIndexOf = (Array.prototype.indexOf)?Array.prototype.indexOf:numeric._myIndexOf; | |
numeric.Function = Function; | |
numeric.precision = 4; | |
numeric.largeArray = 50; | |
numeric.prettyPrint = function prettyPrint(x) { | |
function fmtnum(x) { | |
if(x === 0) { return '0'; } | |
if(isNaN(x)) { return 'NaN'; } | |
if(x<0) { return '-'+fmtnum(-x); } | |
if(isFinite(x)) { | |
var scale = Math.floor(Math.log(x) / Math.log(10)); | |
var normalized = x / Math.pow(10,scale); | |
var basic = normalized.toPrecision(numeric.precision); | |
if(parseFloat(basic) === 10) { scale++; normalized = 1; basic = normalized.toPrecision(numeric.precision); } | |
return parseFloat(basic).toString()+'e'+scale.toString(); | |
} | |
return 'Infinity'; | |
} | |
var ret = []; | |
function foo(x) { | |
var k; | |
if(typeof x === "undefined") { ret.push(Array(numeric.precision+8).join(' ')); return false; } | |
if(typeof x === "string") { ret.push('"'+x+'"'); return false; } | |
if(typeof x === "boolean") { ret.push(x.toString()); return false; } | |
if(typeof x === "number") { | |
var a = fmtnum(x); | |
var b = x.toPrecision(numeric.precision); | |
var c = parseFloat(x.toString()).toString(); | |
var d = [a,b,c,parseFloat(b).toString(),parseFloat(c).toString()]; | |
for(k=1;k<d.length;k++) { if(d[k].length < a.length) a = d[k]; } | |
ret.push(Array(numeric.precision+8-a.length).join(' ')+a); | |
return false; | |
} | |
if(x === null) { ret.push("null"); return false; } | |
if(typeof x === "function") { | |
ret.push(x.toString()); | |
var flag = false; | |
for(k in x) { if(x.hasOwnProperty(k)) { | |
if(flag) ret.push(',\n'); | |
else ret.push('\n{'); | |
flag = true; | |
ret.push(k); | |
ret.push(': \n'); | |
foo(x[k]); | |
} } | |
if(flag) ret.push('}\n'); | |
return true; | |
} | |
if(x instanceof Array) { | |
if(x.length > numeric.largeArray) { ret.push('...Large Array...'); return true; } | |
var flag = false; | |
ret.push('['); | |
for(k=0;k<x.length;k++) { if(k>0) { ret.push(','); if(flag) ret.push('\n '); } flag = foo(x[k]); } | |
ret.push(']'); | |
return true; | |
} | |
ret.push('{'); | |
var flag = false; | |
for(k in x) { if(x.hasOwnProperty(k)) { if(flag) ret.push(',\n'); flag = true; ret.push(k); ret.push(': \n'); foo(x[k]); } } | |
ret.push('}'); | |
return true; | |
} | |
foo(x); | |
return ret.join(''); | |
}; | |
numeric.parseDate = function parseDate(d) { | |
function foo(d) { | |
if(typeof d === 'string') { return Date.parse(d.replace(/-/g,'/')); } | |
if(!(d instanceof Array)) { throw new Error("parseDate: parameter must be arrays of strings"); } | |
var ret = [],k; | |
for(k=0;k<d.length;k++) { ret[k] = foo(d[k]); } | |
return ret; | |
} | |
return foo(d); | |
}; | |
numeric.parseFloat = function parseFloat_(d) { | |
function foo(d) { | |
if(typeof d === 'string') { return parseFloat(d); } | |
if(!(d instanceof Array)) { throw new Error("parseFloat: parameter must be arrays of strings"); } | |
var ret = [],k; | |
for(k=0;k<d.length;k++) { ret[k] = foo(d[k]); } | |
return ret; | |
} | |
return foo(d); | |
}; | |
numeric.parseCSV = function parseCSV(t) { | |
var foo = t.split('\n'); | |
var j,k; | |
var ret = []; | |
var pat = /(([^'",]*)|('[^']*')|("[^"]*")),/g; | |
var patnum = /^\s*(([+-]?[0-9]+(\.[0-9]*)?(e[+-]?[0-9]+)?)|([+-]?[0-9]*(\.[0-9]+)?(e[+-]?[0-9]+)?))\s*$/; | |
var stripper = function(n) { return n.substr(0,n.length-1); }; | |
var count = 0; | |
for(k=0;k<foo.length;k++) { | |
var bar = (foo[k]+",").match(pat),baz; | |
if(bar.length>0) { | |
ret[count] = []; | |
for(j=0;j<bar.length;j++) { | |
baz = stripper(bar[j]); | |
if(patnum.test(baz)) { ret[count][j] = parseFloat(baz); } | |
else ret[count][j] = baz; | |
} | |
count++; | |
} | |
} | |
return ret; | |
}; | |
numeric.toCSV = function toCSV(A) { | |
var s = numeric.dim(A); | |
var i,j,m,n,row,ret; | |
m = s[0]; | |
n = s[1]; | |
ret = []; | |
for(i=0;i<m;i++) { | |
row = []; | |
for(j=0;j<m;j++) { row[j] = A[i][j].toString(); } | |
ret[i] = row.join(', '); | |
} | |
return ret.join('\n')+'\n'; | |
}; | |
numeric.getURL = function getURL(url) { | |
var client = new XMLHttpRequest(); | |
client.open("GET",url,false); | |
client.send(); | |
return client; | |
}; | |
numeric.imageURL = function imageURL(img) { | |
function base64(A) { | |
var n = A.length, i,x,y,z,p,q,r,s; | |
var key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | |
var ret = ""; | |
for(i=0;i<n;i+=3) { | |
x = A[i]; | |
y = A[i+1]; | |
z = A[i+2]; | |
p = x >> 2; | |
q = ((x & 3) << 4) + (y >> 4); | |
r = ((y & 15) << 2) + (z >> 6); | |
s = z & 63; | |
if(i+1>=n) { r = s = 64; } | |
else if(i+2>=n) { s = 64; } | |
ret += key.charAt(p) + key.charAt(q) + key.charAt(r) + key.charAt(s); | |
} | |
return ret; | |
} | |
function crc32Array (a,from,to) { | |
if(typeof from === "undefined") { from = 0; } | |
if(typeof to === "undefined") { to = a.length; } | |
var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, | |
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, | |
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, | |
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, | |
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, | |
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, | |
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, | |
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, | |
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, | |
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, | |
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, | |
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, | |
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, | |
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, | |
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, | |
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, | |
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, | |
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, | |
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, | |
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, | |
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, | |
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, | |
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, | |
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, | |
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, | |
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, | |
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, | |
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, | |
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, | |
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, | |
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, | |
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]; | |
var crc = -1, y = 0, n = a.length,i; | |
for (i = from; i < to; i++) { | |
y = (crc ^ a[i]) & 0xFF; | |
crc = (crc >>> 8) ^ table[y]; | |
} | |
return crc ^ (-1); | |
} | |
var h = img[0].length, w = img[0][0].length, s1, s2, next,k,length,a,b,i,j,adler32,crc32; | |
var stream = [ | |
137, 80, 78, 71, 13, 10, 26, 10, // 0: PNG signature | |
0,0,0,13, // 8: IHDR Chunk length | |
73, 72, 68, 82, // 12: "IHDR" | |
(w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w&255, // 16: Width | |
(h >> 24) & 255, (h >> 16) & 255, (h >> 8) & 255, h&255, // 20: Height | |
8, // 24: bit depth | |
2, // 25: RGB | |
0, // 26: deflate | |
0, // 27: no filter | |
0, // 28: no interlace | |
-1,-2,-3,-4, // 29: CRC | |
-5,-6,-7,-8, // 33: IDAT Chunk length | |
73, 68, 65, 84, // 37: "IDAT" | |
// RFC 1950 header starts here | |
8, // 41: RFC1950 CMF | |
29 // 42: RFC1950 FLG | |
]; | |
crc32 = crc32Array(stream,12,29); | |
stream[29] = (crc32>>24)&255; | |
stream[30] = (crc32>>16)&255; | |
stream[31] = (crc32>>8)&255; | |
stream[32] = (crc32)&255; | |
s1 = 1; | |
s2 = 0; | |
for(i=0;i<h;i++) { | |
if(i<h-1) { stream.push(0); } | |
else { stream.push(1); } | |
a = (3*w+1+(i===0))&255; b = ((3*w+1+(i===0))>>8)&255; | |
stream.push(a); stream.push(b); | |
stream.push((~a)&255); stream.push((~b)&255); | |
if(i===0) stream.push(0); | |
for(j=0;j<w;j++) { | |
for(k=0;k<3;k++) { | |
a = img[k][i][j]; | |
if(a>255) a = 255; | |
else if(a<0) a=0; | |
else a = Math.round(a); | |
s1 = (s1 + a )%65521; | |
s2 = (s2 + s1)%65521; | |
stream.push(a); | |
} | |
} | |
stream.push(0); | |
} | |
adler32 = (s2<<16)+s1; | |
stream.push((adler32>>24)&255); | |
stream.push((adler32>>16)&255); | |
stream.push((adler32>>8)&255); | |
stream.push((adler32)&255); | |
length = stream.length - 41; | |
stream[33] = (length>>24)&255; | |
stream[34] = (length>>16)&255; | |
stream[35] = (length>>8)&255; | |
stream[36] = (length)&255; | |
crc32 = crc32Array(stream,37); | |
stream.push((crc32>>24)&255); | |
stream.push((crc32>>16)&255); | |
stream.push((crc32>>8)&255); | |
stream.push((crc32)&255); | |
stream.push(0); | |
stream.push(0); | |
stream.push(0); | |
stream.push(0); | |
// a = stream.length; | |
stream.push(73); // I | |
stream.push(69); // E | |
stream.push(78); // N | |
stream.push(68); // D | |
stream.push(174); // CRC1 | |
stream.push(66); // CRC2 | |
stream.push(96); // CRC3 | |
stream.push(130); // CRC4 | |
return 'data:image/png;base64,'+base64(stream); | |
}; | |
// 2. Linear algebra with Arrays. | |
numeric._dim = function _dim(x) { | |
var ret = []; | |
while(typeof x === "object") { ret.push(x.length); x = x[0]; } | |
return ret; | |
}; | |
numeric.dim = function dim(x) { | |
var y,z; | |
if(typeof x === "object") { | |
y = x[0]; | |
if(typeof y === "object") { | |
z = y[0]; | |
if(typeof z === "object") { | |
return numeric._dim(x); | |
} | |
return [x.length,y.length]; | |
} | |
return [x.length]; | |
} | |
return []; | |
}; | |
numeric.mapreduce = function mapreduce(body,init) { | |
return Function('x','accum','_s','_k', | |
'if(typeof accum === "undefined") accum = '+init+';\n'+ | |
'if(typeof x === "number") { var xi = x; '+body+'; return accum; }\n'+ | |
'if(typeof _s === "undefined") _s = numeric.dim(x);\n'+ | |
'if(typeof _k === "undefined") _k = 0;\n'+ | |
'var _n = _s[_k];\n'+ | |
'var i,xi;\n'+ | |
'if(_k < _s.length-1) {\n'+ | |
' for(i=_n-1;i>=0;i--) {\n'+ | |
' accum = arguments.callee(x[i],accum,_s,_k+1);\n'+ | |
' }'+ | |
' return accum;\n'+ | |
'}\n'+ | |
'for(i=_n-1;i>=1;i-=2) { \n'+ | |
' xi = x[i];\n'+ | |
' '+body+';\n'+ | |
' xi = x[i-1];\n'+ | |
' '+body+';\n'+ | |
'}\n'+ | |
'if(i === 0) {\n'+ | |
' xi = x[i];\n'+ | |
' '+body+'\n'+ | |
'}\n'+ | |
'return accum;' | |
); | |
}; | |
numeric.mapreduce2 = function mapreduce2(body,setup) { | |
return Function('x', | |
'var n = x.length;\n'+ | |
'var i,xi;\n'+setup+';\n'+ | |
'for(i=n-1;i!==-1;--i) { \n'+ | |
' xi = x[i];\n'+ | |
' '+body+';\n'+ | |
'}\n'+ | |
'return accum;' | |
); | |
}; | |
numeric.same = function same(x,y) { | |
var i,n; | |
if(!(x instanceof Array) || !(y instanceof Array)) { return false; } | |
n = x.length; | |
if(n !== y.length) { return false; } | |
for(i=0;i<n;i++) { | |
if(x[i] === y[i]) { continue; } | |
if(typeof x[i] === "object") { if(!same(x[i],y[i])) return false; } | |
else { return false; } | |
} | |
return true; | |
}; | |
numeric.rep = function rep(s,v,k) { | |
if(typeof k === "undefined") { k=0; } | |
var n = s[k], ret = Array(n), i; | |
if(k === s.length-1) { | |
for(i=n-2;i>=0;i-=2) { ret[i+1] = v; ret[i] = v; } | |
if(i===-1) { ret[0] = v; } | |
return ret; | |
} | |
for(i=n-1;i>=0;i--) { ret[i] = numeric.rep(s,v,k+1); } | |
return ret; | |
}; | |
numeric.dotMMsmall = function dotMMsmall(x,y) { | |
var i,j,k,p,q,r,ret,foo,bar,woo,i0,k0,p0,r0; | |
p = x.length; q = y.length; r = y[0].length; | |
ret = Array(p); | |
for(i=p-1;i>=0;i--) { | |
foo = Array(r); | |
bar = x[i]; | |
for(k=r-1;k>=0;k--) { | |
woo = bar[q-1]*y[q-1][k]; | |
for(j=q-2;j>=1;j-=2) { | |
i0 = j-1; | |
woo += bar[j]*y[j][k] + bar[i0]*y[i0][k]; | |
} | |
if(j===0) { woo += bar[0]*y[0][k]; } | |
foo[k] = woo; | |
} | |
ret[i] = foo; | |
} | |
return ret; | |
}; | |
numeric._getCol = function _getCol(A,j,x) { | |
var n = A.length, i; | |
for(i=n-1;i>0;--i) { | |
x[i] = A[i][j]; | |
--i; | |
x[i] = A[i][j]; | |
} | |
if(i===0) x[0] = A[0][j]; | |
}; | |
numeric.dotMMbig = function dotMMbig(x,y){ | |
var gc = numeric._getCol, p = y.length, v = Array(p); | |
var m = x.length, n = y[0].length, A = new Array(m), xj; | |
var VV = numeric.dotVV; | |
var i,j,k,z; | |
--p; | |
--m; | |
for(i=m;i!==-1;--i) A[i] = Array(n); | |
--n; | |
for(i=n;i!==-1;--i) { | |
gc(y,i,v); | |
for(j=m;j!==-1;--j) { | |
z=0; | |
xj = x[j]; | |
A[j][i] = VV(xj,v); | |
} | |
} | |
return A; | |
}; | |
numeric.dotMV = function dotMV(x,y) { | |
var p = x.length, q = y.length,i; | |
var ret = Array(p), dotVV = numeric.dotVV; | |
for(i=p-1;i>=0;i--) { ret[i] = dotVV(x[i],y); } | |
return ret; | |
}; | |
numeric.dotVM = function dotVM(x,y) { | |
var i,j,k,p,q,r,ret,foo,bar,woo,i0,k0,p0,r0,s1,s2,s3,baz,accum; | |
p = x.length; q = y[0].length; | |
ret = Array(q); | |
for(k=q-1;k>=0;k--) { | |
woo = x[p-1]*y[p-1][k]; | |
for(j=p-2;j>=1;j-=2) { | |
i0 = j-1; | |
woo += x[j]*y[j][k] + x[i0]*y[i0][k]; | |
} | |
if(j===0) { woo += x[0]*y[0][k]; } | |
ret[k] = woo; | |
} | |
return ret; | |
}; | |
numeric.dotVV = function dotVV(x,y) { | |
var i,n=x.length,i1,ret = x[n-1]*y[n-1]; | |
for(i=n-2;i>=1;i-=2) { | |
i1 = i-1; | |
ret += x[i]*y[i] + x[i1]*y[i1]; | |
} | |
if(i===0) { ret += x[0]*y[0]; } | |
return ret; | |
}; | |
numeric.dot = function dot(x,y) { | |
var d = numeric.dim; | |
switch(d(x).length*1000+d(y).length) { | |
case 2002: | |
if(y.length < 10) return numeric.dotMMsmall(x,y); | |
else return numeric.dotMMbig(x,y); | |
case 2001: return numeric.dotMV(x,y); | |
case 1002: return numeric.dotVM(x,y); | |
case 1001: return numeric.dotVV(x,y); | |
case 1000: return numeric.mulVS(x,y); | |
case 1: return numeric.mulSV(x,y); | |
case 0: return x*y; | |
default: throw new Error('numeric.dot only works on vectors and matrices'); | |
} | |
}; | |
numeric.diag = function diag(d) { | |
var i,i1,j,n = d.length, A = Array(n), Ai; | |
for(i=n-1;i>=0;i--) { | |
Ai = Array(n); | |
i1 = i+2; | |
for(j=n-1;j>=i1;j-=2) { | |
Ai[j] = 0; | |
Ai[j-1] = 0; | |
} | |
if(j>i) { Ai[j] = 0; } | |
Ai[i] = d[i]; | |
for(j=i-1;j>=1;j-=2) { | |
Ai[j] = 0; | |
Ai[j-1] = 0; | |
} | |
if(j===0) { Ai[0] = 0; } | |
A[i] = Ai; | |
} | |
return A; | |
}; | |
numeric.getDiag = function(A) { | |
var n = Math.min(A.length,A[0].length),i,ret = Array(n); | |
for(i=n-1;i>=1;--i) { | |
ret[i] = A[i][i]; | |
--i; | |
ret[i] = A[i][i]; | |
} | |
if(i===0) { | |
ret[0] = A[0][0]; | |
} | |
return ret; | |
}; | |
numeric.identity = function identity(n) { return numeric.diag(numeric.rep([n],1)); }; | |
numeric.pointwise = function pointwise(params,body,setup) { | |
if(typeof setup === "undefined") { setup = ""; } | |
var fun = []; | |
var k; | |
var avec = /\[i\]$/,p,thevec = ''; | |
var haveret = false; | |
for(k=0;k<params.length;k++) { | |
if(avec.test(params[k])) { | |
p = params[k].substring(0,params[k].length-3); | |
thevec = p; | |
} else { p = params[k]; } | |
if(p==='ret') haveret = true; | |
fun.push(p); | |
} | |
fun[params.length] = '_s'; | |
fun[params.length+1] = '_k'; | |
fun[params.length+2] = ( | |
'if(typeof _s === "undefined") _s = numeric.dim('+thevec+');\n'+ | |
'if(typeof _k === "undefined") _k = 0;\n'+ | |
'var _n = _s[_k];\n'+ | |
'var i'+(haveret?'':', ret = Array(_n)')+';\n'+ | |
'if(_k < _s.length-1) {\n'+ | |
' for(i=_n-1;i>=0;i--) ret[i] = arguments.callee('+params.join(',')+',_s,_k+1);\n'+ | |
' return ret;\n'+ | |
'}\n'+ | |
setup+'\n'+ | |
'for(i=_n-1;i!==-1;--i) {\n'+ | |
' '+body+'\n'+ | |
'}\n'+ | |
'return ret;' | |
); | |
return Function.apply(null,fun); | |
}; | |
numeric.pointwise2 = function pointwise2(params,body,setup) { | |
if(typeof setup === "undefined") { setup = ""; } | |
var fun = []; | |
var k; | |
var avec = /\[i\]$/,p,thevec = ''; | |
var haveret = false; | |
for(k=0;k<params.length;k++) { | |
if(avec.test(params[k])) { | |
p = params[k].substring(0,params[k].length-3); | |
thevec = p; | |
} else { p = params[k]; } | |
if(p==='ret') haveret = true; | |
fun.push(p); | |
} | |
fun[params.length] = ( | |
'var _n = '+thevec+'.length;\n'+ | |
'var i'+(haveret?'':', ret = Array(_n)')+';\n'+ | |
setup+'\n'+ | |
'for(i=_n-1;i!==-1;--i) {\n'+ | |
body+'\n'+ | |
'}\n'+ | |
'return ret;' | |
); | |
return Function.apply(null,fun); | |
}; | |
numeric._biforeach = (function _biforeach(x,y,s,k,f) { | |
if(k === s.length-1) { f(x,y); return; } | |
var i,n=s[k]; | |
for(i=n-1;i>=0;i--) { _biforeach(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } | |
}); | |
numeric._biforeach2 = (function _biforeach2(x,y,s,k,f) { | |
if(k === s.length-1) { return f(x,y); } | |
var i,n=s[k],ret = Array(n); | |
for(i=n-1;i>=0;--i) { ret[i] = _biforeach2(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } | |
return ret; | |
}); | |
numeric._foreach = (function _foreach(x,s,k,f) { | |
if(k === s.length-1) { f(x); return; } | |
var i,n=s[k]; | |
for(i=n-1;i>=0;i--) { _foreach(x[i],s,k+1,f); } | |
}); | |
numeric._foreach2 = (function _foreach2(x,s,k,f) { | |
if(k === s.length-1) { return f(x); } | |
var i,n=s[k], ret = Array(n); | |
for(i=n-1;i>=0;i--) { ret[i] = _foreach2(x[i],s,k+1,f); } | |
return ret; | |
}); | |
/*numeric.anyV = numeric.mapreduce('if(xi) return true;','false'); | |
numeric.allV = numeric.mapreduce('if(!xi) return false;','true'); | |
numeric.any = function(x) { if(typeof x.length === "undefined") return x; return numeric.anyV(x); } | |
numeric.all = function(x) { if(typeof x.length === "undefined") return x; return numeric.allV(x); }*/ | |
numeric.ops2 = { | |
add: '+', | |
sub: '-', | |
mul: '*', | |
div: '/', | |
mod: '%', | |
and: '&&', | |
or: '||', | |
eq: '===', | |
neq: '!==', | |
lt: '<', | |
gt: '>', | |
leq: '<=', | |
geq: '>=', | |
band: '&', | |
bor: '|', | |
bxor: '^', | |
lshift: '<<', | |
rshift: '>>', | |
rrshift: '>>>' | |
}; | |
numeric.opseq = { | |
addeq: '+=', | |
subeq: '-=', | |
muleq: '*=', | |
diveq: '/=', | |
modeq: '%=', | |
lshifteq: '<<=', | |
rshifteq: '>>=', | |
rrshifteq: '>>>=', | |
bandeq: '&=', | |
boreq: '|=', | |
bxoreq: '^=' | |
}; | |
numeric.mathfuns = ['abs','acos','asin','atan','ceil','cos', | |
'exp','floor','log','round','sin','sqrt','tan', | |
'isNaN','isFinite']; | |
numeric.mathfuns2 = ['atan2','pow','max','min']; | |
numeric.ops1 = { | |
neg: '-', | |
not: '!', | |
bnot: '~', | |
clone: '' | |
}; | |
numeric.mapreducers = { | |
any: ['if(xi) return true;','var accum = false;'], | |
all: ['if(!xi) return false;','var accum = true;'], | |
sum: ['accum += xi;','var accum = 0;'], | |
prod: ['accum *= xi;','var accum = 1;'], | |
norm2Squared: ['accum += xi*xi;','var accum = 0;'], | |
norminf: ['accum = max(accum,abs(xi));','var accum = 0, max = Math.max, abs = Math.abs;'], | |
norm1: ['accum += abs(xi)','var accum = 0, abs = Math.abs;'], | |
sup: ['accum = max(accum,xi);','var accum = -Infinity, max = Math.max;'], | |
inf: ['accum = min(accum,xi);','var accum = Infinity, min = Math.min;'] | |
}; | |
(function () { | |
var i,o; | |
for(i=0;i<numeric.mathfuns2.length;++i) { | |
o = numeric.mathfuns2[i]; | |
numeric.ops2[o] = o; | |
} | |
for(i in numeric.ops2) { | |
if(numeric.ops2.hasOwnProperty(i)) { | |
o = numeric.ops2[i]; | |
var code, codeeq, setup = ''; | |
if(numeric.myIndexOf.call(numeric.mathfuns2,i)!==-1) { | |
setup = 'var '+o+' = Math.'+o+';\n'; | |
code = function(r,x,y) { return r+' = '+o+'('+x+','+y+')'; }; | |
codeeq = function(x,y) { return x+' = '+o+'('+x+','+y+')'; }; | |
} else { | |
code = function(r,x,y) { return r+' = '+x+' '+o+' '+y; }; | |
if(numeric.opseq.hasOwnProperty(i+'eq')) { | |
codeeq = function(x,y) { return x+' '+o+'= '+y; }; | |
} else { | |
codeeq = function(x,y) { return x+' = '+x+' '+o+' '+y; }; | |
} | |
} | |
numeric[i+'VV'] = numeric.pointwise2(['x[i]','y[i]'],code('ret[i]','x[i]','y[i]'),setup); | |
numeric[i+'SV'] = numeric.pointwise2(['x','y[i]'],code('ret[i]','x','y[i]'),setup); | |
numeric[i+'VS'] = numeric.pointwise2(['x[i]','y'],code('ret[i]','x[i]','y'),setup); | |
numeric[i] = Function( | |
'var n = arguments.length, i, x = arguments[0], y;\n'+ | |
'var VV = numeric.'+i+'VV, VS = numeric.'+i+'VS, SV = numeric.'+i+'SV;\n'+ | |
'var dim = numeric.dim;\n'+ | |
'for(i=1;i!==n;++i) { \n'+ | |
' y = arguments[i];\n'+ | |
' if(typeof x === "object") {\n'+ | |
' if(typeof y === "object") x = numeric._biforeach2(x,y,dim(x),0,VV);\n'+ | |
' else x = numeric._biforeach2(x,y,dim(x),0,VS);\n'+ | |
' } else if(typeof y === "object") x = numeric._biforeach2(x,y,dim(y),0,SV);\n'+ | |
' else '+codeeq('x','y')+'\n'+ | |
'}\nreturn x;\n'); | |
numeric[o] = numeric[i]; | |
numeric[i+'eqV'] = numeric.pointwise2(['ret[i]','x[i]'], codeeq('ret[i]','x[i]'),setup); | |
numeric[i+'eqS'] = numeric.pointwise2(['ret[i]','x'], codeeq('ret[i]','x'),setup); | |
numeric[i+'eq'] = Function( | |
'var n = arguments.length, i, x = arguments[0], y;\n'+ | |
'var V = numeric.'+i+'eqV, S = numeric.'+i+'eqS\n'+ | |
'var s = numeric.dim(x);\n'+ | |
'for(i=1;i!==n;++i) { \n'+ | |
' y = arguments[i];\n'+ | |
' if(typeof y === "object") numeric._biforeach(x,y,s,0,V);\n'+ | |
' else numeric._biforeach(x,y,s,0,S);\n'+ | |
'}\nreturn x;\n'); | |
} | |
} | |
for(i=0;i<numeric.mathfuns2.length;++i) { | |
o = numeric.mathfuns2[i]; | |
delete numeric.ops2[o]; | |
} | |
for(i=0;i<numeric.mathfuns.length;++i) { | |
o = numeric.mathfuns[i]; | |
numeric.ops1[o] = o; | |
} | |
for(i in numeric.ops1) { | |
if(numeric.ops1.hasOwnProperty(i)) { | |
setup = ''; | |
o = numeric.ops1[i]; | |
if(numeric.myIndexOf.call(numeric.mathfuns,i)!==-1) { | |
if(Math.hasOwnProperty(o)) setup = 'var '+o+' = Math.'+o+';\n'; | |
} | |
numeric[i+'eqV'] = numeric.pointwise2(['ret[i]'],'ret[i] = '+o+'(ret[i]);',setup); | |
numeric[i+'eq'] = Function('x', | |
'if(typeof x !== "object") return '+o+'x\n'+ | |
'var i;\n'+ | |
'var V = numeric.'+i+'eqV;\n'+ | |
'var s = numeric.dim(x);\n'+ | |
'numeric._foreach(x,s,0,V);\n'+ | |
'return x;\n'); | |
numeric[i+'V'] = numeric.pointwise2(['x[i]'],'ret[i] = '+o+'(x[i]);',setup); | |
numeric[i] = Function('x', | |
'if(typeof x !== "object") return '+o+'(x)\n'+ | |
'var i;\n'+ | |
'var V = numeric.'+i+'V;\n'+ | |
'var s = numeric.dim(x);\n'+ | |
'return numeric._foreach2(x,s,0,V);\n'); | |
} | |
} | |
for(i=0;i<numeric.mathfuns.length;++i) { | |
o = numeric.mathfuns[i]; | |
delete numeric.ops1[o]; | |
} | |
for(i in numeric.mapreducers) { | |
if(numeric.mapreducers.hasOwnProperty(i)) { | |
o = numeric.mapreducers[i]; | |
numeric[i+'V'] = numeric.mapreduce2(o[0],o[1]); | |
numeric[i] = Function('x','s','k', | |
o[1]+ | |
'if(typeof x !== "object") {'+ | |
' xi = x;\n'+ | |
o[0]+';\n'+ | |
' return accum;\n'+ | |
'}'+ | |
'if(typeof s === "undefined") s = numeric.dim(x);\n'+ | |
'if(typeof k === "undefined") k = 0;\n'+ | |
'if(k === s.length-1) return numeric.'+i+'V(x);\n'+ | |
'var xi;\n'+ | |
'var n = x.length, i;\n'+ | |
'for(i=n-1;i!==-1;--i) {\n'+ | |
' xi = arguments.callee(x[i]);\n'+ | |
o[0]+';\n'+ | |
'}\n'+ | |
'return accum;\n'); | |
} | |
} | |
}()); | |
numeric.truncVV = numeric.pointwise(['x[i]','y[i]'],'ret[i] = round(x[i]/y[i])*y[i];','var round = Math.round;'); | |
numeric.truncVS = numeric.pointwise(['x[i]','y'],'ret[i] = round(x[i]/y)*y;','var round = Math.round;'); | |
numeric.truncSV = numeric.pointwise(['x','y[i]'],'ret[i] = round(x/y[i])*y[i];','var round = Math.round;'); | |
numeric.trunc = function trunc(x,y) { | |
if(typeof x === "object") { | |
if(typeof y === "object") return numeric.truncVV(x,y); | |
return numeric.truncVS(x,y); | |
} | |
if (typeof y === "object") return numeric.truncSV(x,y); | |
return Math.round(x/y)*y; | |
}; | |
numeric.inv = function inv(x) { | |
var s = numeric.dim(x), abs = Math.abs, m = s[0], n = s[1]; | |
var A = numeric.clone(x), Ai, Aj; | |
var I = numeric.identity(m), Ii, Ij; | |
var i,j,k,x; | |
for(j=0;j<n;++j) { | |
var i0 = -1; | |
var v0 = -1; | |
for(i=j;i!==m;++i) { k = abs(A[i][j]); if(k>v0) { i0 = i; v0 = k; } } | |
Aj = A[i0]; A[i0] = A[j]; A[j] = Aj; | |
Ij = I[i0]; I[i0] = I[j]; I[j] = Ij; | |
x = Aj[j]; | |
for(k=j;k!==n;++k) Aj[k] /= x; | |
for(k=n-1;k!==-1;--k) Ij[k] /= x; | |
for(i=m-1;i!==-1;--i) { | |
if(i!==j) { | |
Ai = A[i]; | |
Ii = I[i]; | |
x = Ai[j]; | |
for(k=j+1;k!==n;++k) Ai[k] -= Aj[k]*x; | |
for(k=n-1;k>0;--k) { Ii[k] -= Ij[k]*x; --k; Ii[k] -= Ij[k]*x; } | |
if(k===0) Ii[0] -= Ij[0]*x; | |
} | |
} | |
} | |
return I; | |
}; | |
numeric.det = function det(x) { | |
var s = numeric.dim(x); | |
if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: det() only works on square matrices'); } | |
var n = s[0], ret = 1,i,j,k,A = numeric.clone(x),Aj,Ai,alpha,temp,k1,k2,k3; | |
for(j=0;j<n-1;j++) { | |
k=j; | |
for(i=j+1;i<n;i++) { if(Math.abs(A[i][j]) > Math.abs(A[k][j])) { k = i; } } | |
if(k !== j) { | |
temp = A[k]; A[k] = A[j]; A[j] = temp; | |
ret *= -1; | |
} | |
Aj = A[j]; | |
for(i=j+1;i<n;i++) { | |
Ai = A[i]; | |
alpha = Ai[j]/Aj[j]; | |
for(k=j+1;k<n-1;k+=2) { | |
k1 = k+1; | |
Ai[k] -= Aj[k]*alpha; | |
Ai[k1] -= Aj[k1]*alpha; | |
} | |
if(k!==n) { Ai[k] -= Aj[k]*alpha; } | |
} | |
if(Aj[j] === 0) { return 0; } | |
ret *= Aj[j]; | |
} | |
return ret*A[j][j]; | |
}; | |
numeric.transpose = function transpose(x) { | |
var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj; | |
for(j=0;j<n;j++) ret[j] = Array(m); | |
for(i=m-1;i>=1;i-=2) { | |
A1 = x[i]; | |
A0 = x[i-1]; | |
for(j=n-1;j>=1;--j) { | |
Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; | |
--j; | |
Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; | |
} | |
if(j===0) { | |
Bj = ret[0]; Bj[i] = A1[0]; Bj[i-1] = A0[0]; | |
} | |
} | |
if(i===0) { | |
A0 = x[0]; | |
for(j=n-1;j>=1;--j) { | |
ret[j][0] = A0[j]; | |
--j; | |
ret[j][0] = A0[j]; | |
} | |
if(j===0) { ret[0][0] = A0[0]; } | |
} | |
return ret; | |
}; | |
numeric.negtranspose = function negtranspose(x) { | |
var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj; | |
for(j=0;j<n;j++) ret[j] = Array(m); | |
for(i=m-1;i>=1;i-=2) { | |
A1 = x[i]; | |
A0 = x[i-1]; | |
for(j=n-1;j>=1;--j) { | |
Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; | |
--j; | |
Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; | |
} | |
if(j===0) { | |
Bj = ret[0]; Bj[i] = -A1[0]; Bj[i-1] = -A0[0]; | |
} | |
} | |
if(i===0) { | |
A0 = x[0]; | |
for(j=n-1;j>=1;--j) { | |
ret[j][0] = -A0[j]; | |
--j; | |
ret[j][0] = -A0[j]; | |
} | |
if(j===0) { ret[0][0] = -A0[0]; } | |
} | |
return ret; | |
}; | |
numeric._random = function _random(s,k) { | |
var i,n=s[k],ret=Array(n), rnd; | |
if(k === s.length-1) { | |
rnd = Math.random; | |
for(i=n-1;i>=1;i-=2) { | |
ret[i] = rnd(); | |
ret[i-1] = rnd(); | |
} | |
if(i===0) { ret[0] = rnd(); } | |
return ret; | |
} | |
for(i=n-1;i>=0;i--) ret[i] = _random(s,k+1); | |
return ret; | |
}; | |
numeric.random = function random(s) { return numeric._random(s,0); }; | |
numeric.norm2 = function norm2(x) { return Math.sqrt(numeric.norm2Squared(x)); }; | |
numeric.linspace = function linspace(a,b,n) { | |
if(typeof n === "undefined") n = Math.max(Math.round(b-a)+1,1); | |
if(n<2) { return n===1?[a]:[]; } | |
var i,ret = Array(n); | |
n--; | |
for(i=n;i>=0;i--) { ret[i] = (i*b+(n-i)*a)/n; } | |
return ret; | |
}; | |
numeric.getBlock = function getBlock(x,from,to) { | |
var s = numeric.dim(x); | |
function foo(x,k) { | |
var i,a = from[k], n = to[k]-a, ret = Array(n); | |
if(k === s.length-1) { | |
for(i=n;i>=0;i--) { ret[i] = x[i+a]; } | |
return ret; | |
} | |
for(i=n;i>=0;i--) { ret[i] = foo(x[i+a],k+1); } | |
return ret; | |
} | |
return foo(x,0); | |
}; | |
numeric.setBlock = function setBlock(x,from,to,B) { | |
var s = numeric.dim(x); | |
function foo(x,y,k) { | |
var i,a = from[k], n = to[k]-a; | |
if(k === s.length-1) { for(i=n;i>=0;i--) { x[i+a] = y[i]; } } | |
for(i=n;i>=0;i--) { foo(x[i+a],y[i],k+1); } | |
} | |
foo(x,B,0); | |
return x; | |
}; | |
numeric.getRange = function getRange(A,I,J) { | |
var m = I.length, n = J.length; | |
var i,j; | |
var B = Array(m), Bi, AI; | |
for(i=m-1;i!==-1;--i) { | |
B[i] = Array(n); | |
Bi = B[i]; | |
AI = A[I[i]]; | |
for(j=n-1;j!==-1;--j) Bi[j] = AI[J[j]]; | |
} | |
return B; | |
}; | |
numeric.blockMatrix = function blockMatrix(X) { | |
var s = numeric.dim(X); | |
if(s.length<4) return numeric.blockMatrix([X]); | |
var m=s[0],n=s[1],M,N,i,j,Xij; | |
M = 0; N = 0; | |
for(i=0;i<m;++i) M+=X[i][0].length; | |
for(j=0;j<n;++j) N+=X[0][j][0].length; | |
var Z = Array(M); | |
for(i=0;i<M;++i) Z[i] = Array(N); | |
var I=0,J,ZI,k,l,Xijk; | |
for(i=0;i<m;++i) { | |
J=N; | |
for(j=n-1;j!==-1;--j) { | |
Xij = X[i][j]; | |
J -= Xij[0].length; | |
for(k=Xij.length-1;k!==-1;--k) { | |
Xijk = Xij[k]; | |
ZI = Z[I+k]; | |
for(l = Xijk.length-1;l!==-1;--l) ZI[J+l] = Xijk[l]; | |
} | |
} | |
I += X[i][0].length; | |
} | |
return Z; | |
}; | |
numeric.tensor = function tensor(x,y) { | |
if(typeof x === "number" || typeof y === "number") return numeric.mul(x,y); | |
var s1 = numeric.dim(x), s2 = numeric.dim(y); | |
if(s1.length !== 1 || s2.length !== 1) { | |
throw new Error('numeric: tensor product is only defined for vectors'); | |
} | |
var m = s1[0], n = s2[0], A = Array(m), Ai, i,j,xi; | |
for(i=m-1;i>=0;i--) { | |
Ai = Array(n); | |
xi = x[i]; | |
for(j=n-1;j>=3;--j) { | |
Ai[j] = xi * y[j]; | |
--j; | |
Ai[j] = xi * y[j]; | |
--j; | |
Ai[j] = xi * y[j]; | |
--j; | |
Ai[j] = xi * y[j]; | |
} | |
while(j>=0) { Ai[j] = xi * y[j]; --j; } | |
A[i] = Ai; | |
} | |
return A; | |
}; | |
// 3. The Tensor type T | |
numeric.T = function T(x,y) { this.x = x; this.y = y; }; | |
numeric.t = function t(x,y) { return new numeric.T(x,y); }; | |
numeric.Tbinop = function Tbinop(rr,rc,cr,cc,setup) { | |
var io = numeric.indexOf; | |
if(typeof setup !== "string") { | |
var k; | |
setup = ''; | |
for(k in numeric) { | |
if(numeric.hasOwnProperty(k) && (rr.indexOf(k)>=0 || rc.indexOf(k)>=0 || cr.indexOf(k)>=0 || cc.indexOf(k)>=0) && k.length>1) { | |
setup += 'var '+k+' = numeric.'+k+';\n'; | |
} | |
} | |
} | |
return Function(['y'], | |
'var x = this;\n'+ | |
'if(!(y instanceof numeric.T)) { y = new numeric.T(y); }\n'+ | |
setup+'\n'+ | |
'if(x.y) {'+ | |
' if(y.y) {'+ | |
' return new numeric.T('+cc+');\n'+ | |
' }\n'+ | |
' return new numeric.T('+cr+');\n'+ | |
'}\n'+ | |
'if(y.y) {\n'+ | |
' return new numeric.T('+rc+');\n'+ | |
'}\n'+ | |
'return new numeric.T('+rr+');\n' | |
); | |
}; | |
numeric.T.prototype.add = numeric.Tbinop( | |
'add(x.x,y.x)', | |
'add(x.x,y.x),y.y', | |
'add(x.x,y.x),x.y', | |
'add(x.x,y.x),add(x.y,y.y)'); | |
numeric.T.prototype.sub = numeric.Tbinop( | |
'sub(x.x,y.x)', | |
'sub(x.x,y.x),neg(y.y)', | |
'sub(x.x,y.x),x.y', | |
'sub(x.x,y.x),sub(x.y,y.y)'); | |
numeric.T.prototype.mul = numeric.Tbinop( | |
'mul(x.x,y.x)', | |
'mul(x.x,y.x),mul(x.x,y.y)', | |
'mul(x.x,y.x),mul(x.y,y.x)', | |
'sub(mul(x.x,y.x),mul(x.y,y.y)),add(mul(x.x,y.y),mul(x.y,y.x))'); | |
numeric.T.prototype.reciprocal = function reciprocal() { | |
var mul = numeric.mul, div = numeric.div; | |
if(this.y) { | |
var d = numeric.add(mul(this.x,this.x),mul(this.y,this.y)); | |
return new numeric.T(div(this.x,d),div(numeric.neg(this.y),d)); | |
} | |
return new T(div(1,this.x)); | |
}; | |
numeric.T.prototype.div = function div(y) { | |
if(!(y instanceof numeric.T)) y = new numeric.T(y); | |
if(y.y) { return this.mul(y.reciprocal()); } | |
var div = numeric.div; | |
if(this.y) { return new numeric.T(div(this.x,y.x),div(this.y,y.x)); } | |
return new numeric.T(div(this.x,y.x)); | |
}; | |
numeric.T.prototype.dot = numeric.Tbinop( | |
'dot(x.x,y.x)', | |
'dot(x.x,y.x),dot(x.x,y.y)', | |
'dot(x.x,y.x),dot(x.y,y.x)', | |
'sub(dot(x.x,y.x),dot(x.y,y.y)),add(dot(x.x,y.y),dot(x.y,y.x))' | |
); | |
numeric.T.prototype.transpose = function transpose() { | |
var t = numeric.transpose, x = this.x, y = this.y; | |
if(y) { return new numeric.T(t(x),t(y)); } | |
return new numeric.T(t(x)); | |
}; | |
numeric.T.prototype.transjugate = function transjugate() { | |
var t = numeric.transpose, x = this.x, y = this.y; | |
if(y) { return new numeric.T(t(x),numeric.negtranspose(y)); } | |
return new numeric.T(t(x)); | |
}; | |
numeric.Tunop = function Tunop(r,c,s) { | |
if(typeof s !== "string") { s = ''; } | |
return Function( | |
'var x = this;\n'+ | |
s+'\n'+ | |
'if(x.y) {'+ | |
' '+c+';\n'+ | |
'}\n'+ | |
r+';\n' | |
); | |
}; | |
numeric.T.prototype.exp = numeric.Tunop( | |
'return new numeric.T(ex)', | |
'return new numeric.T(mul(cos(x.y),ex),mul(sin(x.y),ex))', | |
'var ex = numeric.exp(x.x), cos = numeric.cos, sin = numeric.sin, mul = numeric.mul;'); | |
numeric.T.prototype.conj = numeric.Tunop( | |
'return new numeric.T(x.x);', | |
'return new numeric.T(x.x,numeric.neg(x.y));'); | |
numeric.T.prototype.neg = numeric.Tunop( | |
'return new numeric.T(neg(x.x));', | |
'return new numeric.T(neg(x.x),neg(x.y));', | |
'var neg = numeric.neg;'); | |
numeric.T.prototype.sin = numeric.Tunop( | |
'return new numeric.T(numeric.sin(x.x))', | |
'return x.exp().sub(x.neg().exp()).div(new numeric.T(0,2));'); | |
numeric.T.prototype.cos = numeric.Tunop( | |
'return new numeric.T(numeric.cos(x.x))', | |
'return x.exp().add(x.neg().exp()).div(2);'); | |
numeric.T.prototype.abs = numeric.Tunop( | |
'return new numeric.T(numeric.abs(x.x));', | |
'return new numeric.T(numeric.sqrt(numeric.add(mul(x.x,x.x),mul(x.y,x.y))));', | |
'var mul = numeric.mul;'); | |
numeric.T.prototype.log = numeric.Tunop( | |
'return new numeric.T(numeric.log(x.x));', | |
'var theta = new numeric.T(numeric.atan2(x.y,x.x)), r = x.abs();\n'+ | |
'return new numeric.T(numeric.log(r.x),theta.x);'); | |
numeric.T.prototype.norm2 = numeric.Tunop( | |
'return numeric.norm2(x.x);', | |
'var f = numeric.norm2Squared;\n'+ | |
'return Math.sqrt(f(x.x)+f(x.y));'); | |
numeric.T.prototype.inv = function inv() { | |
var A = this; | |
if(typeof A.y === "undefined") { return new numeric.T(numeric.inv(A.x)); } | |
var n = A.x.length, i, j, k; | |
var Rx = numeric.identity(n),Ry = numeric.rep([n,n],0); | |
var Ax = numeric.clone(A.x), Ay = numeric.clone(A.y); | |
var Aix, Aiy, Ajx, Ajy, Rix, Riy, Rjx, Rjy; | |
var i,j,k,d,d1,ax,ay,bx,by,temp; | |
for(i=0;i<n;i++) { | |
ax = Ax[i][i]; ay = Ay[i][i]; | |
d = ax*ax+ay*ay; | |
k = i; | |
for(j=i+1;j<n;j++) { | |
ax = Ax[j][i]; ay = Ay[j][i]; | |
d1 = ax*ax+ay*ay; | |
if(d1 > d) { k=j; d = d1; } | |
} | |
if(k!==i) { | |
temp = Ax[i]; Ax[i] = Ax[k]; Ax[k] = temp; | |
temp = Ay[i]; Ay[i] = Ay[k]; Ay[k] = temp; | |
temp = Rx[i]; Rx[i] = Rx[k]; Rx[k] = temp; | |
temp = Ry[i]; Ry[i] = Ry[k]; Ry[k] = temp; | |
} | |
Aix = Ax[i]; Aiy = Ay[i]; | |
Rix = Rx[i]; Riy = Ry[i]; | |
ax = Aix[i]; ay = Aiy[i]; | |
for(j=i+1;j<n;j++) { | |
bx = Aix[j]; by = Aiy[j]; | |
Aix[j] = (bx*ax+by*ay)/d; | |
Aiy[j] = (by*ax-bx*ay)/d; | |
} | |
for(j=0;j<n;j++) { | |
bx = Rix[j]; by = Riy[j]; | |
Rix[j] = (bx*ax+by*ay)/d; | |
Riy[j] = (by*ax-bx*ay)/d; | |
} | |
for(j=i+1;j<n;j++) { | |
Ajx = Ax[j]; Ajy = Ay[j]; | |
Rjx = Rx[j]; Rjy = Ry[j]; | |
ax = Ajx[i]; ay = Ajy[i]; | |
for(k=i+1;k<n;k++) { | |
bx = Aix[k]; by = Aiy[k]; | |
Ajx[k] -= bx*ax-by*ay; | |
Ajy[k] -= by*ax+bx*ay; | |
} | |
for(k=0;k<n;k++) { | |
bx = Rix[k]; by = Riy[k]; | |
Rjx[k] -= bx*ax-by*ay; | |
Rjy[k] -= by*ax+bx*ay; | |
} | |
} | |
} | |
for(i=n-1;i>0;i--) { | |
Rix = Rx[i]; Riy = Ry[i]; | |
for(j=i-1;j>=0;j--) { | |
Rjx = Rx[j]; Rjy = Ry[j]; | |
ax = Ax[j][i]; ay = Ay[j][i]; | |
for(k=n-1;k>=0;k--) { | |
bx = Rix[k]; by = Riy[k]; | |
Rjx[k] -= ax*bx - ay*by; | |
Rjy[k] -= ax*by + ay*bx; | |
} | |
} | |
} | |
return new numeric.T(Rx,Ry); | |
}; | |
numeric.T.prototype.get = function get(i) { | |
var x = this.x, y = this.y, k = 0, ik, n = i.length; | |
if(y) { | |
while(k<n) { | |
ik = i[k]; | |
x = x[ik]; | |
y = y[ik]; | |
k++; | |
} | |
return new numeric.T(x,y); | |
} | |
while(k<n) { | |
ik = i[k]; | |
x = x[ik]; | |
k++; | |
} | |
return new numeric.T(x); | |
}; | |
numeric.T.prototype.set = function set(i,v) { | |
var x = this.x, y = this.y, k = 0, ik, n = i.length, vx = v.x, vy = v.y; | |
if(n===0) { | |
if(vy) { this.y = vy; } | |
else if(y) { this.y = undefined; } | |
this.x = x; | |
return this; | |
} | |
if(vy) { | |
if(y) { /* ok */ } | |
else { | |
y = numeric.rep(numeric.dim(x),0); | |
this.y = y; | |
} | |
while(k<n-1) { | |
ik = i[k]; | |
x = x[ik]; | |
y = y[ik]; | |
k++; | |
} | |
ik = i[k]; | |
x[ik] = vx; | |
y[ik] = vy; | |
return this; | |
} | |
if(y) { | |
while(k<n-1) { | |
ik = i[k]; | |
x = x[ik]; | |
y = y[ik]; | |
k++; | |
} | |
ik = i[k]; | |
x[ik] = vx; | |
if(vx instanceof Array) y[ik] = numeric.rep(numeric.dim(vx),0); | |
else y[ik] = 0; | |
return this; | |
} | |
while(k<n-1) { | |
ik = i[k]; | |
x = x[ik]; | |
k++; | |
} | |
ik = i[k]; | |
x[ik] = vx; | |
return this; | |
}; | |
numeric.T.prototype.getRows = function getRows(i0,i1) { | |
var n = i1-i0+1, j; | |
var rx = Array(n), ry, x = this.x, y = this.y; | |
for(j=i0;j<=i1;j++) { rx[j-i0] = x[j]; } | |
if(y) { | |
ry = Array(n); | |
for(j=i0;j<=i1;j++) { ry[j-i0] = y[j]; } | |
return new numeric.T(rx,ry); | |
} | |
return new numeric.T(rx); | |
}; | |
numeric.T.prototype.setRows = function setRows(i0,i1,A) { | |
var j; | |
var rx = this.x, ry = this.y, x = A.x, y = A.y; | |
for(j=i0;j<=i1;j++) { rx[j] = x[j-i0]; } | |
if(y) { | |
if(!ry) { ry = numeric.rep(numeric.dim(rx),0); this.y = ry; } | |
for(j=i0;j<=i1;j++) { ry[j] = y[j-i0]; } | |
} else if(ry) { | |
for(j=i0;j<=i1;j++) { ry[j] = numeric.rep([x[j-i0].length],0); } | |
} | |
return this; | |
}; | |
numeric.T.prototype.getRow = function getRow(k) { | |
var x = this.x, y = this.y; | |
if(y) { return new numeric.T(x[k],y[k]); } | |
return new numeric.T(x[k]); | |
}; | |
numeric.T.prototype.setRow = function setRow(i,v) { | |
var rx = this.x, ry = this.y, x = v.x, y = v.y; | |
rx[i] = x; | |
if(y) { | |
if(!ry) { ry = numeric.rep(numeric.dim(rx),0); this.y = ry; } | |
ry[i] = y; | |
} else if(ry) { | |
ry = numeric.rep([x.length],0); | |
} | |
return this; | |
}; | |
numeric.T.prototype.getBlock = function getBlock(from,to) { | |
var x = this.x, y = this.y, b = numeric.getBlock; | |
if(y) { return new numeric.T(b(x,from,to),b(y,from,to)); } | |
return new numeric.T(b(x,from,to)); | |
}; | |
numeric.T.prototype.setBlock = function setBlock(from,to,A) { | |
if(!(A instanceof numeric.T)) A = new numeric.T(A); | |
var x = this.x, y = this.y, b = numeric.setBlock, Ax = A.x, Ay = A.y; | |
if(Ay) { | |
if(!y) { this.y = numeric.rep(numeric.dim(this),0); y = this.y; } | |
b(x,from,to,Ax); | |
b(y,from,to,Ay); | |
return this; | |
} | |
b(x,from,to,Ax); | |
if(y) b(y,from,to,numeric.rep(numeric.dim(Ax),0)); | |
}; | |
numeric.T.rep = function rep(s,v) { | |
var T = numeric.T; | |
if(!(v instanceof T)) v = new T(v); | |
var x = v.x, y = v.y, r = numeric.rep; | |
if(y) return new T(r(s,x),r(s,y)); | |
return new T(r(s,x)); | |
}; | |
numeric.T.diag = function diag(d) { | |
if(!(d instanceof numeric.T)) d = new numeric.T(d); | |
var x = d.x, y = d.y, diag = numeric.diag; | |
if(y) return new numeric.T(diag(x),diag(y)); | |
return new numeric.T(diag(x)); | |
}; | |
numeric.T.eig = function eig() { | |
if(this.y) { throw new Error('eig: not implemented for complex matrices.'); } | |
return numeric.eig(this.x); | |
}; | |
numeric.T.identity = function identity(n) { return new numeric.T(numeric.identity(n)); }; | |
numeric.T.prototype.getDiag = function getDiag() { | |
var n = numeric; | |
var x = this.x, y = this.y; | |
if(y) { return new n.T(n.getDiag(x),n.getDiag(y)); } | |
return new n.T(n.getDiag(x)); | |
}; | |
// 4. Eigenvalues of real matrices | |
numeric.house = function house(x) { | |
var v = numeric.clone(x); | |
var s = x[0] >= 0 ? 1 : -1; | |
var alpha = s*numeric.norm2(x); | |
v[0] += alpha; | |
var foo = numeric.norm2(v); | |
if(foo === 0) { /* this should not happen */ throw new Error('eig: internal error'); } | |
return numeric.div(v,foo); | |
}; | |
numeric.toUpperHessenberg = function toUpperHessenberg(me) { | |
var s = numeric.dim(me); | |
if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: toUpperHessenberg() only works on square matrices'); } | |
var m = s[0], i,j,k,x,v,A = numeric.clone(me),B,C,Ai,Ci,Q = numeric.identity(m),Qi; | |
for(j=0;j<m-2;j++) { | |
x = Array(m-j-1); | |
for(i=j+1;i<m;i++) { x[i-j-1] = A[i][j]; } | |
if(numeric.norm2(x)>0) { | |
v = numeric.house(x); | |
B = numeric.getBlock(A,[j+1,j],[m-1,m-1]); | |
C = numeric.tensor(v,numeric.dot(v,B)); | |
for(i=j+1;i<m;i++) { Ai = A[i]; Ci = C[i-j-1]; for(k=j;k<m;k++) Ai[k] -= 2*Ci[k-j]; } | |
B = numeric.getBlock(A,[0,j+1],[m-1,m-1]); | |
C = numeric.tensor(numeric.dot(B,v),v); | |
for(i=0;i<m;i++) { Ai = A[i]; Ci = C[i]; for(k=j+1;k<m;k++) Ai[k] -= 2*Ci[k-j-1]; } | |
B = Array(m-j-1); | |
for(i=j+1;i<m;i++) B[i-j-1] = Q[i]; | |
C = numeric.tensor(v,numeric.dot(v,B)); | |
for(i=j+1;i<m;i++) { Qi = Q[i]; Ci = C[i-j-1]; for(k=0;k<m;k++) Qi[k] -= 2*Ci[k]; } | |
} | |
} | |
return {H:A, Q:Q}; | |
}; | |
numeric.epsilon = 2.220446049250313e-16; | |
numeric.QRFrancis = function(H,maxiter) { | |
if(typeof maxiter === "undefined") { maxiter = 10000; } | |
H = numeric.clone(H); | |
var H0 = numeric.clone(H); | |
var s = numeric.dim(H),m=s[0],x,v,a,b,c,d,det,tr, Hloc, Q = numeric.identity(m), Qi, Hi, B, C, Ci,i,j,k,iter; | |
if(m<3) { return {Q:Q, B:[ [0,m-1] ]}; } | |
var epsilon = numeric.epsilon; | |
for(iter=0;iter<maxiter;iter++) { | |
for(j=0;j<m-1;j++) { | |
if(Math.abs(H[j+1][j]) < epsilon*(Math.abs(H[j][j])+Math.abs(H[j+1][j+1]))) { | |
var QH1 = numeric.QRFrancis(numeric.getBlock(H,[0,0],[j,j]),maxiter); | |
var QH2 = numeric.QRFrancis(numeric.getBlock(H,[j+1,j+1],[m-1,m-1]),maxiter); | |
B = Array(j+1); | |
for(i=0;i<=j;i++) { B[i] = Q[i]; } | |
C = numeric.dot(QH1.Q,B); | |
for(i=0;i<=j;i++) { Q[i] = C[i]; } | |
B = Array(m-j-1); | |
for(i=j+1;i<m;i++) { B[i-j-1] = Q[i]; } | |
C = numeric.dot(QH2.Q,B); | |
for(i=j+1;i<m;i++) { Q[i] = C[i-j-1]; } | |
return {Q:Q,B:QH1.B.concat(numeric.add(QH2.B,j+1))}; | |
} | |
} | |
a = H[m-2][m-2]; b = H[m-2][m-1]; | |
c = H[m-1][m-2]; d = H[m-1][m-1]; | |
tr = a+d; | |
det = (a*d-b*c); | |
Hloc = numeric.getBlock(H, [0,0], [2,2]); | |
if(tr*tr>=4*det) { | |
var s1,s2; | |
s1 = 0.5*(tr+Math.sqrt(tr*tr-4*det)); | |
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)
(Sorry about that, but we can’t show files that are this big right now.)