Gazelle/classes/artists_similar.class.php

386 lines
11 KiB
PHP
Raw Normal View History

2011-03-28 14:21:28 +00:00
<?
2012-10-11 08:00:15 +00:00
class ARTIST {
var $ID = 0;
var $Name = 0;
var $NameLength = 0;
var $SimilarID = 0;
var $Displayed = false;
var $x = 0;
var $y = 0;
var $Similar = array();
2013-04-20 08:01:01 +00:00
function ARTIST($ID = '', $Name = '') {
2012-10-11 08:00:15 +00:00
$this->ID = $ID;
$this->NameLength = mb_strlen($Name, 'utf8');
$this->Name = display_str($Name);
}
}
2011-03-28 14:21:28 +00:00
class ARTISTS_SIMILAR extends ARTIST{
var $Artists = array();
var $TotalScore = 0;
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
var $xValues = array(WIDTH=>1);
var $yValues = array(HEIGHT=>1);
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
var $LargestDecimal = 0;
var $LowestDecimal = 1;
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function dump_data() {
2011-03-28 14:21:28 +00:00
return serialize(array(time(), $this->Name, $this->x, $this->y, serialize($this->Artists), serialize($this->Similar)));
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function load_data($Data) {
2011-03-28 14:21:28 +00:00
list($LastUpdated, $this->Name, $this->x, $this->y, $this->Artists, $this->Similar) = unserialize($Data);
$this->Artists = unserialize($this->Artists);
$this->Similar = unserialize($this->Similar);
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function set_up() {
2013-08-28 23:08:41 +00:00
$QueryID = G::$DB->get_query_id();
2013-04-20 08:01:01 +00:00
$this->x = ceil(WIDTH / 2);
$this->y = ceil(HEIGHT / 2);
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
$this->xValues[$this->x] = $this->ID;
$this->yValues[$this->y] = $this->ID;
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Get artists that are directly similar to the artist
$ArtistIDs = array();
2013-08-28 23:08:41 +00:00
G::$DB->query("
2011-03-28 14:21:28 +00:00
SELECT
2013-04-20 08:01:01 +00:00
s2.ArtistID,
ag.Name,
ass.Score
2011-03-28 14:21:28 +00:00
FROM artists_similar AS s1
2013-04-20 08:01:01 +00:00
JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
JOIN artists_group AS ag ON ag.ArtistID=s2.ArtistID
2011-03-28 14:21:28 +00:00
WHERE s1.ArtistID=".$this->ID."
ORDER BY ass.Score DESC
LIMIT 14");
2012-10-11 08:00:15 +00:00
2013-08-28 23:08:41 +00:00
if (!G::$DB->has_results()) {
2011-03-28 14:21:28 +00:00
return;
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Build into array. Each artist is its own object in $this->Artists
2013-08-28 23:08:41 +00:00
while (list($ArtistID, $Name, $Score) = G::$DB->next_record(MYSQLI_NUM, false)) {
2013-04-20 08:01:01 +00:00
if ($Score < 0) {
2011-03-28 14:21:28 +00:00
continue;
}
$this->Artists[$ArtistID] = new ARTIST($ArtistID, $Name);
2013-06-18 08:00:48 +00:00
$this->Similar[$ArtistID] = array('ID' => $ArtistID, 'Score' => $Score);
2013-05-25 08:01:03 +00:00
$this->TotalScore += $Score;
$ArtistIDs[] = $ArtistID;
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Get similarities between artists on the map
2013-08-28 23:08:41 +00:00
G::$DB->query("
2013-04-20 08:01:01 +00:00
SELECT
s1.ArtistID,
s2.ArtistID
2011-03-28 14:21:28 +00:00
FROM artists_similar AS s1
2013-04-20 08:01:01 +00:00
JOIN artists_similar AS s2 ON s1.SimilarID=s2.SimilarID AND s1.ArtistID!=s2.ArtistID
JOIN artists_similar_scores AS ass ON ass.SimilarID=s1.SimilarID
JOIN artists_group AS a ON a.ArtistID=s2.ArtistID
2013-06-18 08:00:48 +00:00
WHERE s1.ArtistID IN(".implode(',', $ArtistIDs).')
AND s2.ArtistID IN('.implode(',', $ArtistIDs).')');
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Build into array
2013-08-28 23:08:41 +00:00
while (list($Artist1ID, $Artist2ID) = G::$DB->next_record()) {
2011-03-28 14:21:28 +00:00
$this->Artists[$Artist1ID]->Similar[$Artist2ID] = array('ID'=>$Artist2ID);
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Calculate decimal point scores between artists
2013-04-20 08:01:01 +00:00
foreach ($this->Similar as $SimilarArtist) {
2011-03-28 14:21:28 +00:00
list($ArtistID, $Similar) = array_values($SimilarArtist);
$this->Similar[$ArtistID]['Decimal'] = $this->similarity($Similar['Score'], $this->TotalScore);
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
if ($this->Similar[$ArtistID]['Decimal'] < $this->LowestDecimal) {
2011-03-28 14:21:28 +00:00
$this->LowestDecimal = $this->Similar[$ArtistID]['Decimal'];
}
2013-04-20 08:01:01 +00:00
if ($this->Similar[$ArtistID]['Decimal'] > $this->LargestDecimal) {
2011-03-28 14:21:28 +00:00
$this->LargestDecimal = $this->Similar[$ArtistID]['Decimal'];
}
}
reset($this->Artists);
2013-08-28 23:08:41 +00:00
G::$DB->set_query_id($QueryID);
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function set_positions() {
2011-03-28 14:21:28 +00:00
$xValues = array(); // Possible x values
2013-04-20 08:01:01 +00:00
$Root = ceil(WIDTH / 4); // Half-way into half of the image
2011-03-28 14:21:28 +00:00
$Offset = 4; // Distance from the root (a quarter of the way into the image) to the x value
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// The number of artists placed in the top or the bottom
$NumTop = 0;
$NumBottom = 0;
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// The number of artists placed in the left or the right
$NumLeft = 0;
$NumRight = 0;
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
$Multiplier = 0;
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Build up an impressive list of possible x values
// We later iterate through these, and pick out the ones we want
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// These x values are all below WIDTH/2 (all on the left)
// The script later chooses which side to put them on
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// We create more very low x values because they're more likely to be skipped
2013-04-20 08:01:01 +00:00
for ($i = 0; $i <= count($this->Artists) * 4; $i++) {
if ($Offset >= ((WIDTH / 4))) {
$Offset = $Offset % (WIDTH / 4);
2011-03-28 14:21:28 +00:00
}
2013-04-20 08:01:01 +00:00
$Plus = $Root + $Offset; // Point on the right of the root
$Minus = abs($Root - $Offset); // Point on the left of the root
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
$xValues[$Plus] = $Plus;
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
$xValues[$Minus] = $Minus;
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Throw in an extra x value closer to the edge, because they're more likely to be skipped
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
if ($Minus > 30) {
// $xValues[$Minus - 30] = $Minus - 30;
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2013-05-25 08:01:03 +00:00
$Offset = $Offset + rand(5, 20); // Increase offset, and go again
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
foreach ($this->Artists as $Artist) {
2011-03-28 14:21:28 +00:00
$ArtistID = $Artist->ID;
2013-04-20 08:01:01 +00:00
if ($Artist->Displayed == true) {
2011-03-28 14:21:28 +00:00
continue;
}
2013-04-20 08:01:01 +00:00
$this->Similar[$ArtistID]['Decimal'] = $this->Similar[$ArtistID]['Decimal'] * (1 / ($this->LargestDecimal)) - 0.1;
2011-03-28 14:21:28 +00:00
// Calculate the distance away from the center, based on similarity
$IdealDistance = $this->calculate_distance($this->Similar[$ArtistID]['Decimal'], $this->x, $this->y);
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
$this->Similar[$ArtistID]['Distance'] = $IdealDistance;
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// 1 = left, 2 = right
$Horizontal = 0;
$Vertical = 0;
2012-10-11 08:00:15 +00:00
// See if any similar artists have been placed yet. If so, place artist in that half
2011-03-28 14:21:28 +00:00
// (provided that there are enough in the other half to visually balance out)
reset($Artist->Similar);
2013-04-20 08:01:01 +00:00
foreach ($Artist->Similar as $SimilarArtist) {
2011-03-28 14:21:28 +00:00
list($Artist2ID) = array_values($SimilarArtist);
2013-04-20 08:01:01 +00:00
if ($this->Artists[$Artist2ID]) {
if ($this->Artists[$Artist2ID]->x > (WIDTH / 2) && ($NumRight-$NumLeft) < 1) {
2011-03-28 14:21:28 +00:00
$Horizontal = 2;
2013-04-20 08:01:01 +00:00
} elseif ($NumLeft - $NumRight < 1) {
2011-03-28 14:21:28 +00:00
$Horizontal = 1;
}
break;
}
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
shuffle($xValues);
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
while ($xValue = array_shift($xValues)) {
if (abs($this->x - $xValue) <= $IdealDistance) {
if (hypot(abs($this->x - $xValue), ($this->y - 50)) > $IdealDistance
|| ceil(sqrt(pow($IdealDistance, 2) - pow($this->x - $xValue, 2))) > (HEIGHT / 2)) {
$xValue = $this->x - ceil(sqrt(pow($IdealDistance, 2) - pow($IdealDistance * 0.1 * rand(5,9), 2)));
2011-03-28 14:21:28 +00:00
//echo "Had to change x value for ".$Artist->Name." to ".$xValue."\n";
}
2012-10-11 08:00:15 +00:00
// Found a match (Is close enough to the center to satisfy $IdealDistance),
2011-03-28 14:21:28 +00:00
// Now it's time to choose which half to put it on
2013-04-20 08:01:01 +00:00
if (!$Horizontal) {
2011-03-28 14:21:28 +00:00
// No similar artists displayed
2013-04-20 08:01:01 +00:00
$Horizontal = ($NumLeft < $NumRight) ? 1 : 2;
2011-03-28 14:21:28 +00:00
}
2013-04-20 08:01:01 +00:00
if ($Horizontal == 2) {
$xValue = WIDTH - $xValue;
2011-03-28 14:21:28 +00:00
$NumRight++;
} else {
$NumLeft++;
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
$Artist->x = $xValue;
$this->xValues[$xValue] = $ArtistID;
unset($xValues[$xValue]);
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
break;
}
}
2013-04-20 08:01:01 +00:00
if (!$xValue) { // Uh-oh, we were unable to choose an x value.
$xValue = ceil(sqrt(pow($IdealDistance, 2) / 2));
$xValue = (WIDTH / 2) - $xValue;
2011-03-28 14:21:28 +00:00
$Artist->x = $xValue;
$this->xValues[$xValue] = $ArtistID;
unset($xValues[$xValue]);
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Pythagoras. $yValue is the vertical distance from the center to the y value
$yValue = sqrt(pow($IdealDistance, 2) - pow(abs($this->x - $Artist->x), 2));
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Now we pick if it should go on the top or bottom
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
if ($NumTop > $NumBottom) { // Send it to the bottom half
$yValue = (HEIGHT / 2) + $yValue;
2011-03-28 14:21:28 +00:00
$NumBottom++;
} else {
2013-04-20 08:01:01 +00:00
$yValue=(HEIGHT / 2) - $yValue;
2011-03-28 14:21:28 +00:00
$NumTop++;
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
$yValue = ceil($yValue);
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// $yValue is now a proper y coordinate
// Now time to do some spacing out
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
if ($yValue < 10) {
$yValue += (10 + abs($yValue)) + rand(10,20);
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
if ($yValue > (HEIGHT - 10)) {
$yValue -= ((HEIGHT / 2) - rand(10,20));
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
$i = 1;
2013-04-20 08:01:01 +00:00
while ($Conflict = $this->scan_array_range($this->yValues, abs($yValue - 13), $yValue + 13)) {
if ($i > 10) {
2011-03-28 14:21:28 +00:00
break;
}
2013-04-20 08:01:01 +00:00
if (!$this->scan_array_range($this->yValues, abs($yValue - 5), $yValue - 20)) {
2011-03-28 14:21:28 +00:00
$yValue -= 20;
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
$yValue = $Conflict + rand(10, 20);
if ($yValue > HEIGHT - 10) {
$yValue -= ceil(HEIGHT / 2.5);
} elseif ($yValue < 10) {
$yValue += ceil(HEIGHT / 2.5);
2011-03-28 14:21:28 +00:00
}
$i++;
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
$Artist->y = $yValue;
$this->yValues[$yValue] = $ArtistID;
}
reset($this->Artists);
reset($this->xValues);
reset($this->yValues);
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
// Calculate the ideal distance from the center point ($Rootx, $Rooty) to the artist's point on the board
// Pythagoras as fun!
2013-04-20 08:01:01 +00:00
function calculate_distance($SimilarityCoefficient, $Rootx, $Rooty) {
2011-03-28 14:21:28 +00:00
$MaxWidth = WIDTH - $Rootx;
$MaxHeight = HEIGHT - $Rooty;
2013-04-20 08:01:01 +00:00
$x = $MaxWidth - ($SimilarityCoefficient * $MaxWidth * 0.01); // Possible x value
$y = $MaxHeight - ($SimilarityCoefficient * $MaxHeight); // Possible y value
2011-03-28 14:21:28 +00:00
$Hypot = hypot($Rootx - $x, $Rooty - $y);
return $MaxWidth - $Hypot;
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function similarity($Score, $TotalArtistScore) {
return (pow(($Score / ($TotalArtistScore + 1)), (1 / 1)));
2011-03-28 14:21:28 +00:00
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function scan_array_range($Array, $Start, $Finish) {
if ($Start < 0) {
2011-03-28 14:21:28 +00:00
die($Start);
}
2013-04-20 08:01:01 +00:00
for ($i = $Start; $i <= $Finish; $i++) {
if (isset($Array[$i])) {
2011-03-28 14:21:28 +00:00
return $i;
}
}
return false;
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function write_artists() {
2011-03-28 14:21:28 +00:00
?>
2013-05-25 08:01:03 +00:00
<div style="position: absolute; bottom: <?=($this->y - 10)?>px; left: <?=($this->x - $this->NameLength * 4)?>px; font-size: 13pt; white-space: nowrap;" class="similar_artist_header">
<?=($this->Name)?>
2011-03-28 14:21:28 +00:00
</div>
<?
2013-04-20 08:01:01 +00:00
foreach ($this->Artists as $Artist) {
if ($Artist->ID == $this->ID) {
2011-03-28 14:21:28 +00:00
continue;
}
2013-04-20 08:01:01 +00:00
$xPosition = $Artist->x - $Artist->NameLength * 4;
if ($xPosition < 0) {
$xPosition = 3;
2011-03-28 14:21:28 +00:00
$Artist->x = $xPosition;
}
$Decimal = $this->Similar[$Artist->ID]['Decimal'];
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
if ($Decimal < 0.2) {
2011-03-28 14:21:28 +00:00
$FontSize = 8;
2013-04-20 08:01:01 +00:00
} elseif ($Decimal < 0.3) {
2011-03-28 14:21:28 +00:00
$FontSize = 9;
2013-04-20 08:01:01 +00:00
} elseif ($Decimal < 0.4) {
2011-03-28 14:21:28 +00:00
$FontSize = 10;
} else {
$FontSize = 12;
}
?>
2013-05-25 08:01:03 +00:00
<div style="position: absolute; top: <?=($Artist->y - 5)?>px; left: <?=$xPosition?>px; font-size: <?=$FontSize?>pt; white-space: nowrap;">
<a href="artist.php?id=<?=($Artist->ID)?>" class="similar_artist"><?=($Artist->Name)?></a>
2011-03-28 14:21:28 +00:00
</div>
<?
}
reset($this->Artists);
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function background_image() {
2011-03-28 14:21:28 +00:00
global $Img;
reset($this->Similar);
2013-04-20 08:01:01 +00:00
foreach ($this->Similar as $SimilarArtist) {
2011-03-28 14:21:28 +00:00
list($ArtistID, $Val) = array_values($SimilarArtist);
$Artist = $this->Artists[$ArtistID];
$Decimal = $this->Similar[$ArtistID]['Decimal'];
2013-04-20 08:01:01 +00:00
$Width = ceil($Decimal * 4) + 1;
2012-10-11 08:00:15 +00:00
2013-05-25 08:01:03 +00:00
$Img->line($this->x, $this->y, $Artist->x, $Artist->y, $Img->color(199, 218, 255), $Width);
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
unset($Artist->Similar[$this->ID]);
reset($Artist->Similar);
2013-04-20 08:01:01 +00:00
foreach ($Artist->Similar as $SimilarArtist2) {
2011-03-28 14:21:28 +00:00
list($Artist2ID) = array_values($SimilarArtist2);
2013-04-20 08:01:01 +00:00
if ($this->Artists[$Artist2ID]) {
2011-03-28 14:21:28 +00:00
$Artist2 = $this->Artists[$Artist2ID];
2013-05-25 08:01:03 +00:00
$Img->line($Artist->x, $Artist->y, $Artist2->x, $Artist2->y, $Img->color(173, 201, 255));
2011-03-28 14:21:28 +00:00
unset($Artist2->Similar[$ArtistID]);
}
}
reset($this->xValues);
}
$Img->make_png(SERVER_ROOT.'/static/similar/'.$this->ID.'.png');
}
2012-10-11 08:00:15 +00:00
2013-04-20 08:01:01 +00:00
function dump() {
2011-03-28 14:21:28 +00:00
echo "Similarities:\n";
2013-04-20 08:01:01 +00:00
foreach ($this->Artists as $Artist) {
2011-03-28 14:21:28 +00:00
echo $Artist->ID;
echo ' - ';
echo $Artist->Name;
echo "\n";
2013-05-25 08:01:03 +00:00
echo 'x - ' . $Artist->x . "\n";
echo 'y - ' . $Artist->y . "\n";
2011-03-28 14:21:28 +00:00
print_r($this->Similar[$Artist->ID]);
//print_r($Artist->Similar);
echo "\n\n---\n\n";
}
2012-10-11 08:00:15 +00:00
2011-03-28 14:21:28 +00:00
}
}
?>