Adaptation of code from Fran Armstrong’s submisison in 2019.
<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>
/*
* 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];
}
[
"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>
{
"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;
}
}
/*
* 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];
}
[{"weights":[{"name":"dense0/conv0/filters","shape":[3,3,3,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004853619781194949,"min":-0.5872879935245888}},{"name":"dense0/conv0/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004396426443960153,"min":-0.7298067896973853}},{"name":"dense0/conv1/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00635151559231328,"min":-0.5589333721235686}},{"name":"dense0/conv1/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009354315552057004,"min":-1.2628325995276957}},{"name":"dense0/conv1/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0029380727048013726,"min":-0.5846764682554731}},{"name":"dense0/conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0049374802439820535,"min":-0.6171850304977566}},{"name":"dense0/conv2/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009941946758943446,"min":-1.3421628124573652}},{"name":"dense0/conv2/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0030300481062309416,"min":-0.5272283704841838}},{"name":"dense0/conv3/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005672684837790097,"min":-0.7431217137505026}},{"name":"dense0/conv3/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010712201455060173,"min":-1.5639814124387852}},{"name":"dense0/conv3/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0030966934035806097,"min":-0.3839899820439956}},{"name":"dense1/conv0/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0039155554537679636,"min":-0.48161332081345953}},{"name":"dense1/conv0/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01023082966898002,"min":-1.094698774580862}},{"name":"dense1/conv0/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0027264176630506327,"min":-0.3871513081531898}},{"name":"dense1/conv1/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004583378632863362,"min":-0.5454220573107401}},{"name":"dense1/conv1/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00915846403907327,"min":-1.117332612766939}},{"name":"dense1/conv1/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003091680419211294,"min":-0.5966943209077797}},{"name":"dense1/conv2/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005407439727409214,"min":-0.708374604290607}},{"name":"dense1/conv2/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00946493943532308,"min":-1.2399070660273235}},{"name":"dense1/conv2/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004409168514550901,"min":-0.9788354102303}},{"name":"dense1/conv3/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004478132958505668,"min":-0.6493292789833219}},{"name":"dense1/conv3/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011063695888893277,"min":-1.2501976354449402}},{"name":"dense1/conv3/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003909627596537272,"min":-0.6646366914113363}},{"name":"dense2/conv0/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003213915404151468,"min":-0.3374611174359041}},{"name":"dense2/conv0/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010917326048308728,"min":-1.4520043644250609}},{"name":"dense2/conv0/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002800439152063108,"min":-0.38085972468058266}},{"name":"dense2/conv1/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0050568851770139206,"min":-0.6927932692509071}},{"name":"dense2/conv1/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01074961213504567,"min":-1.3222022926106174}},{"name":"dense2/conv1/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0030654204242369708,"min":-0.5487102559384177}},{"name":"dense2/conv2/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00591809165244009,"min":-0.917304206128214}},{"name":"dense2/conv2/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01092823346455892,"min":-1.366029183069865}},{"name":"dense2/conv2/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002681120470458386,"min":-0.36463238398234055}},{"name":"dense2/conv3/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0048311497650894465,"min":-0.5797379718107336}},{"name":"dense2/conv3/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011227761062921263,"min":-1.4483811771168429}},{"name":"dense2/conv3/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0034643323982463162,"min":-0.3360402426298927}},{"name":"dense3/conv0/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003394978887894574,"min":-0.49227193874471326}},{"name":"dense3/conv0/pointwise_filter","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010051267287310432,"min":-1.2765109454884247}},{"name":"dense3/conv0/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003142924752889895,"min":-0.4588670139219247}},{"name":"dense3/conv1/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00448304671867221,"min":-0.5872791201460595}},{"name":"dense3/conv1/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.016063522357566685,"min":-2.3613377865623026}},{"name":"dense3/conv1/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00287135781026354,"min":-0.47664539650374765}},{"name":"dense3/conv2/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006002906724518421,"min":-0.7923836876364315}},{"name":"dense3/conv2/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.017087187019048954,"min":-1.6061955797906016}},{"name":"dense3/conv2/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003124481205846749,"min":-0.46242321846531886}},{"name":"dense3/conv3/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006576311588287353,"min":-1.0193282961845398}},{"name":"dense3/conv3/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015590153955945782,"min":-1.99553970636106}},{"name":"dense3/conv3/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004453541601405424,"min":-0.6546706154065973}},{"name":"fc/weights","shape":[256,136],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010417488509533453,"min":-1.500118345372817}},{"name":"fc/bias","shape":[136],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0025084222648658005,"min":0.07683877646923065}}],"paths":["z_face_landmark_68_model-shard1"]}]
[{"weights":[{"name":"conv32_down/conv/filters","shape":[7,7,3,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0005260649557207145,"min":-0.07101876902229645}},{"name":"conv32_down/conv/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":8.471445956577858e-7,"min":-0.00014740315964445472}},{"name":"conv32_down/scale/weights","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.06814416062598135,"min":5.788674831390381}},{"name":"conv32_down/scale/biases","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008471635042452345,"min":-0.931879854669758}},{"name":"conv32_1/conv1/conv/filters","shape":[3,3,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0007328585666768691,"min":-0.0974701893680236}},{"name":"conv32_1/conv1/conv/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":1.5952091238361e-8,"min":-0.000001978059313556764}},{"name":"conv32_1/conv1/scale/weights","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.02146628510718252,"min":3.1103382110595703}},{"name":"conv32_1/conv1/scale/biases","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0194976619645661,"min":-2.3787147596770644}},{"name":"conv32_1/conv2/conv/filters","shape":[3,3,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0004114975824075587,"min":-0.05267169054816751}},{"name":"conv32_1/conv2/conv/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":4.600177166424806e-9,"min":-5.70421968636676e-7}},{"name":"conv32_1/conv2/scale/weights","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.03400764932819441,"min":2.1677730083465576}},{"name":"conv32_1/conv2/scale/biases","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010974494616190593,"min":-1.240117891629537}},{"name":"conv32_2/conv1/conv/filters","shape":[3,3,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0005358753251094444,"min":-0.0760942961655411}},{"name":"conv32_2/conv1/conv/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":5.9886454383719385e-9,"min":-7.366033889197485e-7}},{"name":"conv32_2/conv1/scale/weights","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.014633869657329485,"min":2.769575357437134}},{"name":"conv32_2/conv1/scale/biases","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.022131107367721257,"min":-2.5229462399202234}},{"name":"conv32_2/conv2/conv/filters","shape":[3,3,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00030145110452876373,"min":-0.03949009469326805}},{"name":"conv32_2/conv2/conv/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":6.8779549306497095e-9,"min":-9.010120959151119e-7}},{"name":"conv32_2/conv2/scale/weights","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.03929369870354148,"min":4.8010945320129395}},{"name":"conv32_2/conv2/scale/biases","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010553357180427103,"min":-1.2452961472903983}},{"name":"conv32_3/conv1/conv/filters","shape":[3,3,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0003133527642371608,"min":-0.040735859350830905}},{"name":"conv32_3/conv1/conv/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":4.1064200719547974e-9,"min":-3.0387508532465503e-7}},{"name":"conv32_3/conv1/scale/weights","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009252088210161994,"min":2.333256721496582}},{"name":"conv32_3/conv1/scale/biases","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.007104101251153385,"min":-0.34810096130651585}},{"name":"conv32_3/conv2/conv/filters","shape":[3,3,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00029995629892629733,"min":-0.031195455088334923}},{"name":"conv32_3/conv2/conv/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":5.62726418316814e-9,"min":-6.921534945296811e-7}},{"name":"conv32_3/conv2/scale/weights","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0467432975769043,"min":5.362040996551514}},{"name":"conv32_3/conv2/scale/biases","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010314425300149357,"min":-1.268674311918371}},{"name":"conv64_down/conv1/conv/filters","shape":[3,3,32,64],"dtype":"float32"},{"name":"conv64_down/conv1/conv/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":8.373908033218849e-10,"min":-1.172347124650639e-7}},{"name":"conv64_down/conv1/scale/weights","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0066875364266189875,"min":2.5088400840759277}},{"name":"conv64_down/conv1/scale/biases","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01691421620986041,"min":-2.0973628100226906}},{"name":"conv64_down/conv2/conv/filters","shape":[3,3,64,64],"dtype":"float32"},{"name":"conv64_down/conv2/conv/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":2.3252014483766877e-9,"min":-2.673981665633191e-7}},{"name":"conv64_down/conv2/scale/weights","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.032557439804077146,"min":2.6351239681243896}},{"name":"conv64_down/conv2/scale/biases","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015429047509735706,"min":-1.5429047509735707}},{"name":"conv64_1/conv1/conv/filters","shape":[3,3,64,64],"dtype":"float32"},{"name":"conv64_1/conv1/conv/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":1.1319172039756998e-9,"min":-1.4941307092479238e-7}},{"name":"conv64_1/conv1/scale/weights","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.007802607031429515,"min":3.401733160018921}},{"name":"conv64_1/conv1/scale/biases","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01425027146058924,"min":-0.6982633015688727}},{"name":"conv64_1/conv2/conv/filters","shape":[3,3,64,64],"dtype":"float32"},{"name":"conv64_1/conv2/conv/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":2.5635019893325435e-9,"min":-2.717312108692496e-7}},{"name":"conv64_1/conv2/scale/weights","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.04062801716374416,"min":3.542381525039673}},{"name":"conv64_1/conv2/scale/biases","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.007973166306813557,"min":-0.7415044665336609}},{"name":"conv64_2/conv1/conv/filters","shape":[3,3,64,64],"dtype":"float32"},{"name":"conv64_2/conv1/conv/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":1.2535732661062331e-9,"min":-1.8302169685151004e-7}},{"name":"conv64_2/conv1/scale/weights","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005631206549850164,"min":2.9051668643951416}},{"name":"conv64_2/conv1/scale/biases","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01859012585060269,"min":-2.3795361088771445}},{"name":"conv64_2/conv2/conv/filters","shape":[3,3,64,64],"dtype":"float32"},{"name":"conv64_2/conv2/conv/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":2.486726369919351e-9,"min":-3.5311514452854786e-7}},{"name":"conv64_2/conv2/scale/weights","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.03740917467603497,"min":5.571568965911865}},{"name":"conv64_2/conv2/scale/biases","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006418555858088475,"min":-0.5263215803632549}},{"name":"conv64_3/conv1/conv/filters","shape":[3,3,64,64],"dtype":"float32"},{"name":"conv64_3/conv1/conv/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":7.432564576875473e-10,"min":-8.47312361763804e-8}},{"name":"conv64_3/conv1/scale/weights","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006400122362024644,"min":2.268010377883911}},{"name":"conv64_3/conv1/scale/biases","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010945847922680425,"min":-1.3353934465670119}},{"name":"conv64_3/conv2/conv/filters","shape":[3,3,64,64],"dtype":"float32"},{"name":"conv64_3/conv2/conv/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":2.278228722014533e-9,"min":-3.212302498040492e-7}},{"name":"conv64_3/conv2/scale/weights","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.029840927498013366,"min":7.038398265838623}},{"name":"conv64_3/conv2/scale/biases","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010651412197187834,"min":-1.161003929493474}},{"name":"conv128_down/conv1/conv/filters","shape":[3,3,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00020040544662989823,"min":-0.022245004575918704}},{"name":"conv128_down/conv1/conv/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":4.3550543563576545e-10,"min":-4.311503812794078e-8}},{"name":"conv128_down/conv1/scale/weights","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.007448580685783835,"min":2.830846071243286}},{"name":"conv128_down/conv1/scale/biases","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01211262824488621,"min":-1.6957679542840696}},{"name":"conv128_down/conv2/conv/filters","shape":[3,3,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00022380277514457702,"min":-0.02484210804104805}},{"name":"conv128_down/conv2/conv/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":9.031058637304466e-10,"min":-1.1650065642122761e-7}},{"name":"conv128_down/conv2/scale/weights","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.027663578706629135,"min":3.1111555099487305}},{"name":"conv128_down/conv2/scale/biases","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008878476946961646,"min":-1.029903325847551}},{"name":"conv128_1/conv1/conv/filters","shape":[3,3,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00022380667574265425,"min":-0.032899581334170175}},{"name":"conv128_1/conv1/conv/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":4.4147297756478345e-10,"min":-5.253528433020923e-8}},{"name":"conv128_1/conv1/scale/weights","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.013599334978589825,"min":3.634530782699585}},{"name":"conv128_1/conv1/scale/biases","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.014059314073300829,"min":-1.4059314073300828}},{"name":"conv128_1/conv2/conv/filters","shape":[3,3,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00021715293474057143,"min":-0.02909849325523657}},{"name":"conv128_1/conv2/conv/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":9.887046963276768e-10,"min":-1.1370104007768284e-7}},{"name":"conv128_1/conv2/scale/weights","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.029993299409454943,"min":3.630716562271118}},{"name":"conv128_1/conv2/scale/biases","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00782704236460667,"min":-0.7200878975438136}},{"name":"conv128_2/conv1/conv/filters","shape":[3,3,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00017718105923895743,"min":-0.022324813464108636}},{"name":"conv128_2/conv1/conv/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":3.567012027797675e-10,"min":-5.243507680862582e-8}},{"name":"conv128_2/conv1/scale/weights","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.007940645778880399,"min":4.927767753601074}},{"name":"conv128_2/conv1/scale/biases","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015933452867994122,"min":-1.5614783810634238}},{"name":"conv128_2/conv2/conv/filters","shape":[3,3,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0001451439717236687,"min":-0.01712698866339291}},{"name":"conv128_2/conv2/conv/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":1.0383988570966347e-9,"min":-1.2356946399449953e-7}},{"name":"conv128_2/conv2/scale/weights","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.02892604528688917,"min":4.750600814819336}},{"name":"conv128_2/conv2/scale/biases","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00797275748907351,"min":-0.7414664464838364}},{"name":"conv256_down/conv1/conv/filters","shape":[3,3,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0002698827827093648,"min":-0.03994265184098599}},{"name":"conv256_down/conv1/conv/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":5.036909834755123e-10,"min":-6.396875490139006e-8}},{"name":"conv256_down/conv1/scale/weights","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.014870181738161573,"min":4.269900798797607}},{"name":"conv256_down/conv1/scale/biases","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.022031106200872685,"min":-3.1063859743230484}},{"name":"conv256_down/conv2/conv/filters","shape":[3,3,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00046430734150549946,"min":-0.03946612402796745}},{"name":"conv256_down/conv2/conv/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":6.693064577513153e-10,"min":-7.630093618364995e-8}},{"name":"conv256_down/conv2/scale/weights","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.03475512242784687,"min":3.608360528945923}},{"name":"conv256_down/conv2/scale/biases","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01290142021927179,"min":-1.1482263995151893}},{"name":"conv256_1/conv1/conv/filters","shape":[3,3,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00037147209924810076,"min":-0.04234781931428348}},{"name":"conv256_1/conv1/conv/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":3.2105515457510146e-10,"min":-3.467395669411096e-8}},{"name":"conv256_1/conv1/scale/weights","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.043242172166412955,"min":5.28542947769165}},{"name":"conv256_1/conv1/scale/biases","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01643658619300992,"min":-1.3149268954407936}},{"name":"conv256_1/conv2/conv/filters","shape":[3,3,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0003289232651392619,"min":-0.041773254672686264}},{"name":"conv256_1/conv2/conv/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":9.13591691187321e-10,"min":-1.2333487831028833e-7}},{"name":"conv256_1/conv2/scale/weights","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0573908618852204,"min":4.360693454742432}},{"name":"conv256_1/conv2/scale/biases","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0164216583850337,"min":-1.3958409627278647}},{"name":"conv256_2/conv1/conv/filters","shape":[3,3,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00010476927912118389,"min":-0.015610622589056398}},{"name":"conv256_2/conv1/conv/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":2.418552539068639e-10,"min":-2.539480166022071e-8}},{"name":"conv256_2/conv1/scale/weights","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.06024209564807368,"min":6.598613739013672}},{"name":"conv256_2/conv1/scale/biases","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01578534350675695,"min":-1.1049740454729864}},{"name":"conv256_2/conv2/conv/filters","shape":[3,3,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00005543030908002573,"min":-0.007427661416723448}},{"name":"conv256_2/conv2/conv/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":1.0822061852320308e-9,"min":-1.515088659324843e-7}},{"name":"conv256_2/conv2/scale/weights","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.04302893993901272,"min":2.2855491638183594}},{"name":"conv256_2/conv2/scale/biases","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006792667566561232,"min":-0.8083274404207865}},{"name":"conv256_down_out/conv1/conv/filters","shape":[3,3,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.000568966465253456,"min":-0.05632768006009214}},{"name":"conv256_down_out/conv1/conv/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":4.5347887884881677e-10,"min":-6.530095855422961e-8}},{"name":"conv256_down_out/conv1/scale/weights","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.017565592597512638,"min":4.594101905822754}},{"name":"conv256_down_out/conv1/scale/biases","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.04850864223405427,"min":-6.306123490427055}},{"name":"conv256_down_out/conv2/conv/filters","shape":[3,3,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0003739110687199761,"min":-0.06954745878191555}},{"name":"conv256_down_out/conv2/conv/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":1.2668428328152895e-9,"min":-2.2549802424112154e-7}},{"name":"conv256_down_out/conv2/scale/weights","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.04351314469879749,"min":4.31956672668457}},{"name":"conv256_down_out/conv2/scale/biases","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.021499746921015722,"min":-1.2039858275768804}},{"name":"fc","shape":[256,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.000357687911566566,"min":-0.04578405268052045}}],"paths":["z_face_recognition_model-shard1","z_face_recognition_model-shard2"]}]
// Arithmetic mean
let getMean = function (data) {
return data.reduce(function (a, b) {
return Number(a) + Number(b);
}) / data.length;
};
// Standard deviation
let getSD = function (data) {
let m = getMean(data);
return Math.sqrt(data.reduce(function (sq, n) {
return sq + Math.pow(n - m, 2);
}, 0) / (data.length - 1));
};
const LM_LEN = 68;
const LM_parts = ['chin', 'left_eyebrow', 'right_eyebrow',
'nose_bridge', 'nose_tip', 'left_eye', 'right_eye',
'top_lip', 'bottom_lip'];
const LM_names = [
'chin', 'chin', 'chin', 'chin', 'chin',
'chin', 'chin', 'chin', 'chin', 'chin',
'chin', 'chin', 'chin', 'chin', 'chin',
'chin', 'chin',
'left_eyebrow', 'left_eyebrow', 'left_eyebrow', 'left_eyebrow', 'left_eyebrow',
'right_eyebrow', 'right_eyebrow', 'right_eyebrow', 'right_eyebrow', 'right_eyebrow',
'nose_bridge', 'nose_bridge', 'nose_bridge', 'nose_bridge',
'nose_tip', 'nose_tip', 'nose_tip', 'nose_tip', 'nose_tip',
'left_eye', 'left_eye', 'left_eye', 'left_eye', 'left_eye', 'left_eye',
'right_eye', 'right_eye', 'right_eye', 'right_eye', 'right_eye', 'right_eye',
'lip', 'lip', 'lip', 'lip',
'lip', 'lip', 'lip', 'lip',
'lip', 'lip', 'lip', 'lip',
'lip', 'lip', 'lip', 'lip',
'lip', 'lip', 'lip', 'lip'
]
// https://github.com/ageitgey/face_recognition/blob/d34c622bf42e2c619505a4884017051ecf61ac77/face_recognition/api.py#L190
const top_lip_indices = [48, 49, 50, 51, 52, 53, 54, 64, 63, 62, 61, 60];
const bottom_lip_indices = [54, 55, 56, 57, 58, 59, 48, 60, 67, 66, 65, 64];
function get_landmarks(faceDescriptions) {
let landmarks = []
for(let i=0; i<faceDescriptions.length; i++) {
let curLM = {
'chin': [],
'left_eyebrow': [],
'right_eyebrow': [],
'nose_bridge': [],
'nose_tip': [],
'left_eye': [],
'right_eye': [],
'top_lip': [],
'bottom_lip': []
};
let lm = faceDescriptions[i].landmarks;
let lpts = lm.positions;
let x_points = [];
let y_points = [];
// print(lpts.length)
for(let j=0; j<LM_LEN; j++) {
x_points.push(lpts[j].x)
y_points.push(lpts[j].y)
}
let mean_x = getMean(x_points);
let mean_y = getMean(y_points);
for(let j=0; j<LM_LEN; j++) {
x_points[j] = x_points[j] - mean_x;
y_points[j] = y_points[j] - mean_y;
}
let sdev_x = getSD(x_points);
let sdev_y = getSD(y_points);
let sdev = sdev_x > sdev_y ? sdev_x : sdev_y;
// let p1 = lpts[27]
// let p2 = lpts[28]
// EYES VERSION
// let p1 = lpts[36];
// let p2 = lpts[42];
// EARS VERSION
let p1 = lpts[2];
let p2 = lpts[14];
let xd = p1.x - p2.x;
let yd = p1.y - p2.y;
let angle = Math.atan2(-yd, -xd);
let s_a = Math.sin(-angle);
let c_a = Math.cos(-angle);
let raw_points = []
for(let j=0; j<LM_LEN; j++) {
let pt = [0, 0]
pt[0] = lpts[j].x - mean_x;
pt[1] = lpts[j].y - mean_y;
pt[0] = pt[0] / sdev;
pt[1] = pt[1] / sdev;
let x_new = pt[0] * c_a - pt[1] * s_a;
let y_new = pt[0] * s_a + pt[1] * c_a;
pt[0] = x_new;
pt[1] = y_new;
raw_points.push(pt);
}
// put all raw points into landmarks objects
// first everything but the lips (which start at 48)
for(let j=0; j<48; j++) {
let key = LM_names[j];
curLM[key].push(raw_points[j]);
}
// now the lips, which have dupes
for(let j=0; j<top_lip_indices.length; j++) {
let cur_ix = top_lip_indices[j];
let cur_pt = raw_points[cur_ix];
let pt_copy = [cur_pt[0], cur_pt[1]];
curLM['top_lip'].push(pt_copy);
}
for(let j=0; j<bottom_lip_indices.length; j++) {
let cur_ix = bottom_lip_indices[j];
let cur_pt = raw_points[cur_ix];
let pt_copy = [cur_pt[0], cur_pt[1]];
curLM['bottom_lip'].push(pt_copy);
}
curLM['transform'] = {
'center': [mean_x, mean_y],
'scale': sdev,
'angle': angle
}
landmarks.push(curLM);
}
// print(JSON.stringify(landmarks));
return landmarks;
}
function get_latents(faceDescriptions) {
latents = [];
for(let i=0; i<faceDescriptions.length; i++) {
let lm = faceDescriptions[i].descriptor;
latents.push(lm);
// print(lm);
}
return latents;
}
function resetFocusedRandom() {
return Math.seedrandom(arguments);
}
function focusedRandom(min, max, focus, mean) {
// console.log("hello")
if(max === undefined) {
max = min;
min = 0;
}
if(focus === undefined) {
focus = 1.0;
}
if(mean === undefined) {
mean = (min + max) / 2.0;
}
if(focus == 0) {
return d3.randomUniform(min, max)();
}
else if(focus < 0) {
focus = -1 / focus;
}
let sigma = (max - min) / (2 * focus);
let val = d3.randomNormal(mean, sigma)();
if (val >= min && val < max) {
return val;
}
return d3.randomUniform(min, max)();
}
/**
* k-d Tree JavaScript - V 1.01
*
* https://github.com/ubilabs/kd-tree-javascript
*
* @author Mircea Pricop <pricop@ubilabs.net>, 2012
* @author Martin Kleppe <kleppe@ubilabs.net>, 2012
* @author Ubilabs http://ubilabs.net, 2012
* @license MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['exports'], factory);
} else if (typeof exports === 'object') {
factory(exports);
} else {
factory((root.commonJsStrict = {}));
}
}(this, function (exports) {
function Node(obj, dimension, parent) {
this.obj = obj;
this.left = null;
this.right = null;
this.parent = parent;
this.dimension = dimension;
}
function kdTree(points, metric, dimensions) {
var self = this;
function buildTree(points, depth, parent) {
var dim = depth % dimensions.length,
median,
node;
if (points.length === 0) {
return null;
}
if (points.length === 1) {
return new Node(points[0], dim, parent);
}
points.sort(function (a, b) {
return a[dimensions[dim]] - b[dimensions[dim]];
});
median = Math.floor(points.length / 2);
node = new Node(points[median], dim, parent);
node.left = buildTree(points.slice(0, median), depth + 1, node);
node.right = buildTree(points.slice(median + 1), depth + 1, node);
return node;
}
// Reloads a serialied tree
function loadTree (data) {
// Just need to restore the `parent` parameter
self.root = data;
function restoreParent (root) {
if (root.left) {
root.left.parent = root;
restoreParent(root.left);
}
if (root.right) {
root.right.parent = root;
restoreParent(root.right);
}
}
restoreParent(self.root);
}
// If points is not an array, assume we're loading a pre-built tree
if (!Array.isArray(points)) loadTree(points, metric, dimensions);
else this.root = buildTree(points, 0, null);
// Convert to a JSON serializable structure; this just requires removing
// the `parent` property
this.toJSON = function (src) {
if (!src) src = this.root;
var dest = new Node(src.obj, src.dimension, null);
if (src.left) dest.left = self.toJSON(src.left);
if (src.right) dest.right = self.toJSON(src.right);
return dest;
};
this.insert = function (point) {
function innerSearch(node, parent) {
if (node === null) {
return parent;
}
var dimension = dimensions[node.dimension];
if (point[dimension] < node.obj[dimension]) {
return innerSearch(node.left, node);
} else {
return innerSearch(node.right, node);
}
}
var insertPosition = innerSearch(this.root, null),
newNode,
dimension;
if (insertPosition === null) {
this.root = new Node(point, 0, null);
return;
}
newNode = new Node(point, (insertPosition.dimension + 1) % dimensions.length, insertPosition);
dimension = dimensions[insertPosition.dimension];
if (point[dimension] < insertPosition.obj[dimension]) {
insertPosition.left = newNode;
} else {
insertPosition.right = newNode;
}
};
this.remove = function (point) {
var node;
function nodeSearch(node) {
if (node === null) {
return null;
}
if (node.obj === point) {
return node;
}
var dimension = dimensions[node.dimension];
if (point[dimension] < node.obj[dimension]) {
return nodeSearch(node.left, node);
} else {
return nodeSearch(node.right, node);
}
}
function removeNode(node) {
var nextNode,
nextObj,
pDimension;
function findMin(node, dim) {
var dimension,
own,
left,
right,
min;
if (node === null) {
return null;
}
dimension = dimensions[dim];
if (node.dimension === dim) {
if (node.left !== null) {
return findMin(node.left, dim);
}
return node;
}
own = node.obj[dimension];
left = findMin(node.left, dim);
right = findMin(node.right, dim);
min = node;
if (left !== null && left.obj[dimension] < own) {
min = left;
}
if (right !== null && right.obj[dimension] < min.obj[dimension]) {
min = right;
}
return min;
}
if (node.left === null && node.right === null) {
if (node.parent === null) {
self.root = null;
return;
}
pDimension = dimensions[node.parent.dimension];
if (node.obj[pDimension] < node.parent.obj[pDimension]) {
node.parent.left = null;
} else {
node.parent.right = null;
}
return;
}
// If the right subtree is not empty, swap with the minimum element on the
// node's dimension. If it is empty, we swap the left and right subtrees and
// do the same.
if (node.right !== null) {
nextNode = findMin(node.right, node.dimension);
nextObj = nextNode.obj;
removeNode(nextNode);
node.obj = nextObj;
} else {
nextNode = findMin(node.left, node.dimension);
nextObj = nextNode.obj;
removeNode(nextNode);
node.right = node.left;
node.left = null;
node.obj = nextObj;
}
}
node = nodeSearch(self.root);
if (node === null) { return; }
removeNode(node);
};
this.nearest = function (point, maxNodes, maxDistance) {
var i,
result,
bestNodes;
bestNodes = new BinaryHeap(
function (e) { return -e[1]; }
);
function nearestSearch(node) {
var bestChild,
dimension = dimensions[node.dimension],
ownDistance = metric(point, node.obj),
linearPoint = {},
linearDistance,
otherChild,
i;
function saveNode(node, distance) {
bestNodes.push([node, distance]);
if (bestNodes.size() > maxNodes) {
bestNodes.pop();
}
}
for (i = 0; i < dimensions.length; i += 1) {
if (i === node.dimension) {
linearPoint[dimensions[i]] = point[dimensions[i]];
} else {
linearPoint[dimensions[i]] = node.obj[dimensions[i]];
}
}
linearDistance = metric(linearPoint, node.obj);
if (node.right === null && node.left === null) {
if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[1]) {
saveNode(node, ownDistance);
}
return;
}
if (node.right === null) {
bestChild = node.left;
} else if (node.left === null) {
bestChild = node.right;
} else {
if (point[dimension] < node.obj[dimension]) {
bestChild = node.left;
} else {
bestChild = node.right;
}
}
nearestSearch(bestChild);
if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[1]) {
saveNode(node, ownDistance);
}
if (bestNodes.size() < maxNodes || Math.abs(linearDistance) < bestNodes.peek()[1]) {
if (bestChild === node.left) {
otherChild = node.right;
} else {
otherChild = node.left;
}
if (otherChild !== null) {
nearestSearch(otherChild);
}
}
}
if (maxDistance) {
for (i = 0; i < maxNodes; i += 1) {
bestNodes.push([null, maxDistance]);
}
}
if(self.root)
nearestSearch(self.root);
result = [];
for (i = 0; i < Math.min(maxNodes, bestNodes.content.length); i += 1) {
if (bestNodes.content[i][0]) {
result.push([bestNodes.content[i][0].obj, bestNodes.content[i][1]]);
}
}
return result;
};
this.balanceFactor = function () {
function height(node) {
if (node === null) {
return 0;
}
return Math.max(height(node.left), height(node.right)) + 1;
}
function count(node) {
if (node === null) {
return 0;
}
return count(node.left) + count(node.right) + 1;
}
return height(self.root) / (Math.log(count(self.root)) / Math.log(2));
};
}
// Binary heap implementation from:
// http://eloquentjavascript.net/appendix2.html
function BinaryHeap(scoreFunction){
this.content = [];
this.scoreFunction = scoreFunction;
}
BinaryHeap.prototype = {
push: function(element) {
// Add the new element to the end of the array.
this.content.push(element);
// Allow it to bubble up.
this.bubbleUp(this.content.length - 1);
},
pop: function() {
// Store the first element so we can return it later.
var result = this.content[0];
// Get the element at the end of the array.
var end = this.content.pop();
// If there are any elements left, put the end element at the
// start, and let it sink down.
if (this.content.length > 0) {
this.content[0] = end;
this.sinkDown(0);
}
return result;
},
peek: function() {
return this.content[0];
},
remove: function(node) {
var len = this.content.length;
// To remove a value, we must search through the array to find
// it.
for (var i = 0; i < len; i++) {
if (this.content[i] == node) {
// When it is found, the process seen in 'pop' is repeated
// to fill up the hole.
var end = this.content.pop();
if (i != len - 1) {
this.content[i] = end;
if (this.scoreFunction(end) < this.scoreFunction(node))
this.bubbleUp(i);
else
this.sinkDown(i);
}
return;
}
}
throw new Error("Node not found.");
},
size: function() {
return this.content.length;
},
bubbleUp: function(n) {
// Fetch the element that has to be moved.
var element = this.content[n];
// When at 0, an element can not go up any further.
while (n > 0) {
// Compute the parent element's index, and fetch it.
var parentN = Math.floor((n + 1) / 2) - 1,
parent = this.content[parentN];
// Swap the elements if the parent is greater.
if (this.scoreFunction(element) < this.scoreFunction(parent)) {
this.content[parentN] = element;
this.content[n] = parent;
// Update 'n' to continue at the new position.
n = parentN;
}
// Found a parent that is less, no need to move it further.
else {
break;
}
}
},
sinkDown: function(n) {
// Look up the target element and its score.
var length = this.content.length,
element = this.content[n],
elemScore = this.scoreFunction(element);
while(true) {
// Compute the indices of the child elements.
var child2N = (n + 1) * 2, child1N = child2N - 1;
// This is used to store the new position of the element,
// if any.
var swap = null;
// If the first child exists (is inside the array)...
if (child1N < length) {
// Look it up and compute its score.
var child1 = this.content[child1N],
child1Score = this.scoreFunction(child1);
// If the score is less than our element's, we need to swap.
if (child1Score < elemScore)
swap = child1N;
}
// Do the same checks for the other child.
if (child2N < length) {
var child2 = this.content[child2N],
child2Score = this.scoreFunction(child2);
if (child2Score < (swap == null ? elemScore : child1Score)){
swap = child2N;
}
}
// If the element needs to be moved, swap it, and continue.
if (swap != null) {
this.content[n] = this.content[swap];
this.content[swap] = element;
n = swap;
}
// Otherwise, we are done.
else {
break;
}
}
}
};
this.kdTree = kdTree;
exports.kdTree = kdTree;
exports.BinaryHeap = BinaryHeap;
}));
// note: this file is poorly named - it can generally be ignored.
// helper functions below for supporting blocks/purview
function saveBlocksImages(doZoom) {
if(doZoom == null) {
doZoom = false;
}
// generate 960x500 preview.jpg of entire canvas
// TODO: should this be recycled?
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = 960;
offscreenCanvas.height = 500;
var context = offscreenCanvas.getContext('2d');
// background is flat white
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 960, 500);
context.drawImage(this.canvas, 0, 0, 960, 500);
// save to browser
var downloadMime = 'image/octet-stream';
var imageData = offscreenCanvas.toDataURL('image/jpeg');
imageData = imageData.replace('image/jpeg', downloadMime);
p5.prototype.downloadFile(imageData, 'preview.jpg', 'jpg');
// generate 230x120 thumbnail.png centered on mouse
offscreenCanvas.width = 230;
offscreenCanvas.height = 120;
// background is flat white
context = offscreenCanvas.getContext('2d');
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 230, 120);
if(doZoom) {
// pixelDensity does the right thing on retina displays
var pd = this._pixelDensity;
var sx = pd * mouseX - pd * 230/2;
var sy = pd * mouseY - pd * 120/2;
var sw = pd * 230;
var sh = pd * 120;
// bounds checking - just displace if necessary
if (sx < 0) {
sx = 0;
}
if (sx > this.canvas.width - sw) {
sx = this.canvas.width - sw;
}
if (sy < 0) {
sy = 0;
}
if (sy > this.canvas.height - sh) {
sy = this.canvas.height - sh;
}
// save to browser
context.drawImage(this.canvas, sx, sy, sw, sh, 0, 0, 230, 120);
}
else {
// now scaledown
var full_width = this.canvas.width;
var full_height = this.canvas.height;
context.drawImage(this.canvas, 0, 0, full_width, full_height, 0, 0, 230, 120);
}
imageData = offscreenCanvas.toDataURL('image/png');
imageData = imageData.replace('image/png', downloadMime);
// call this function after 1 second
setTimeout(function(){
p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png');
}, 1000);
}