Search

Geek Girl Joy

Artificial Intelligence, Simulations & Software

Tag

GIF

OCR 2 – The MNIST Database

I know I probably haven’t been posting as frequently as many of you would like or even at my normal quality because… well, like for many of you, this year has just sucked!

Someone I’ve known my whole life died recently, not from the virus though it didn’t help things.

She went in for a “routine” procedure where they needed to use general anesthesia and there were “complications” during the procedure. Something to do with her heart but if I’m being honest, I don’t know all the details at this time.

Also, I’m not sure how by anyone’s definition anything involving anesthesia is routine?

An ambulance was called and she was rushed to the hospital, long story short, despite being otherwise fine when she went in, she never woke up from her coma. 😥

The hospital is/was on lock down like everyone else and so friends and family were unable to visit her before she died.

Her family intends to sue the Dr. for malpractice, personally… I think they should!

To add insult to injury, she was cremated without a funeral due to the whole pandemic social distancing BS that I’m just about ready to tell the government to go fuck itself over! 😦

I’m sorry, do my harsh words offend you? SHE DIED ALONE! That offends me!

Going forward, my advice… any procedure where they need to administer general anesthesia to you… or maybe any procedure at all… make sure it’s in a hospital or hospital adjacent (NOT A CLINIC) because those minutes waiting for an ambulance really do mean your life!

And if your doctor is like, “No worries this is routine… I’ve done this a thousand times”, maybe think carefully before putting your trust in that person.

Yes, we want doctors that are confident in their ability to treat us but make sure that it is confidence and not complacent hubris!

Further, no procedure is truly “routine” and a doctor, of all people, should know that and act accordingly!

“Primum non nocere”

~Hippocrates… (allegedly)

Regardless of the historical veracity of that quote, does the spirit of that principle still not apply?

Look, I’m not saying this to detract from the important life saving work doctors and medical workers do every day, it’s just that this is part of what’s going on in my life right now (and for many of you as well) and I’m sharing because I guess that’s what you do when you have a blog.

Additionally, less close to home, though still another terrible loss, John Horton Conway, notable math hero to geeks and nerds alike died as a result of complications from his contracting the Covid-19 virus. 😦

I’ve previously written a little about Conway’s work in my ancestor simulations series of posts.

Mysterious Game of Life Posts:

But that only scratches the surface of his work and famously Conway’s Game of Life was perhaps his least favorite but most well known work among non-mathematicians and it would both amuse and bug him if I only mentioned his game of life here so I’m not going to list his other accomplishments.

I’ll have a little chuckle off camera on his behalf. 😛

He really was a math genius and you would learn a lot of interesting, not to mention surreal… but I’ve said too much, ideas by reading about his accomplishments, which I encourage you to do!

In any case, people I know and admire need to stop dying because its killing me… not to mention my ratings and readership because I keep talking about it! 😛

I may have a terribly dark sense of humor at times, but going forward I demand strict adherence from all of you to the Oasis Doctrine! 😥

Oh, and speaking of pretentious art…

The OCR 2 Wallpaper

The original OCR didn’t exactly have a wallpaper but I did create an image/logo to go along with the project and its blog posts:

For the reason you might think I made it look like an eye… because it looks like an non-evil Hal 9000! 😛

Also, I like the idea of depicting a robotic eye in relation to AI and neural networks because, even though I am not superstitious in any way, it carries some of the symbology of Illuminati, “The gaze of the Beholder”, “The Eye of Providence”, “The Evil Eye”, The Eye of Horus, The Eye of Ra, Eye of newt and needle… sorry. 😛

In this case, the eye of a robot invokes a sense of literal “Deus ex machina” (God from the machine) and it illustrates some peoples fears of “The Singularity” and of the possibility of an intelligence that is so much greater than our own that it calls in to question our ability to even comprehend it… hmmm… is that too lovecraftian? 😛

Anyway, because I enjoy the thought provoking symbology (maybe it’s just me), I wanted to keep the same concept of the robot eye but update it to look a little less like a simple cartoon to subtly imply it’s a more advanced version of OCR but that it still fundamentally does the same thing, which is most of the reasoning behind this wallpaper.

In any case, I hope you enjoy it.

OCR 2 Wallpaper
OCR 2 Wallpaper

If you’d like the wallpaper with the feature image text here’s that version.

OCR 2 Wallpaper (with text)
OCR 2 Wallpaper (with text)

So I guess having shared a few of the recent tragedies in my personal life and a couple of wallpapers, we should probably get mogating and talk about the point of today’s post!

We’re going to look at doing hand-written number (0-9) Optical Character Recognition using the MNIST database.

OCR 2 – The MNIST Dataset with PHP and FANN

I was recently contacted by a full-stack developer who wanted advice on creating his own OCR system for “stickers on internal vehicles”.

I think he means, some kind of warehouse robots?

He had seen my OCR ANN and seemingly preferred to work with PHP over Python, which if I’m being honest… I can’t exactly argue with!

PHP is C++ for the web and powers like almost 80-90% of the internet so it should come as no surprise to anyone (even though it does) that there are people who want to use it to build bots! 😛

But, if you would rather work with a different language there is a better than decent chance FANN has bindings for it so you should be able to use the ANN’s even if you are not using PHP.

So anyway, he gave me a dollar for my advice through Patreon and we had a brief conversation over messaging where I offered him a few suggestions and walked him through getting started.

Ultimately, because he lacks an AI/ML background and/or a sufficient familiarity with an AI/ML workflow he wasn’t very confident about proceeding so I recommended he follow my existing tutorials which should help him learn the basics of how to proceed.

Now here’s the thing, even among people who like my content and value my efforts, few people are generous enough to give me money for my advice and when they do, I genuinely appreciate it! 🙂

So, as a thank you I want to offer another (more complete) example of how to use a neural network to do OCR.

If he followed my advice, he should be fairly close to being ready for a more complete real world OCR ANN example (assuming he is still reading 😛 ) but if not, his loss is still your gain!

Today’s code implements OCR using the MNIST dataset and I demonstrate a basic form of pooling (though the stride is not adjustable as is) and I show convolutions using the GD image library, image convolution function and include 17 demonstration kernel matrices that you can experiment with, though not all are relevant or necessary for this project.

This is still very basic but everything you need to get started experimenting with OCR is here.

Having said that, in all honesty, to accomplish your goal requires building your own dataset and modifying the code I present here to meet your needs.

Neither are exactly hard but will require significant time and dedication to testing and refining your processes.

Obviously that’s not something I can cover in a single post or even assist you with for only a dollar, but since so few people show me the kindness and consideration you have, at a time of shrinking economies no less, I wanted to offer you this working OCR prototype to help you along your way.

Our Method

1. Download the MNIST dataset (link below, but it’s in the GitHub repo too).

2. Unpack/Export the data from the files to images and labels.

(technically we could even skip the images and go directly to a training file but I think it’s nice to have the images and labels in a human viewable format)

3. Create training and test data from images and labels.

4. Train the network.

5. Test the network.

The MNIST Dataset

MNIST stands for Modified National Institute of Standards and Technology database.

And since I’m still recovering from last nights food poisoning due to the Chicken à la Nauseam we’re just going to use Wikipedia’s introduction to MNIST.

It’s easily as good as anything I could write and doesn’t require me actually write it so…

Wikipedia says:

“It’s a large database of handwritten digits that is commonly used for training various image processing systems.[1][2]”

It also says:

“It was created by “re-mixing” the samples from NIST’s original datasets. The creators felt that since NIST’s training dataset was taken from American Census Bureau employees, while the testing dataset was taken from American high school students, it was not well-suited for machine learning experiments.[5] Furthermore, the black and white images from NIST were normalized to fit into a 28×28 pixel bounding box and anti-aliased, which introduced grayscale levels.[5]”

Here’s 500 pseudo-random MNIST sample images:

I randomly selected 500 1’s, 3’s and 7’s and composited them into this 1337 animation. 😛

500 random 1337 MNIST images.
500 random 1337 MNIST images

Seriously though,  today we will be training a bot to identify which hand-written number (0-9) each 28×28 px image contains and then test the bot using images it hasn’t previously seen.

Our bot will learn using all 60K labeled training images and we’ll test it using the 10,000 labeled test images.

Here’s the wiki article if you would like to learn more about the database.

MNIST WIKI: https://en.wikipedia.org/wiki/MNIST_database

And as I said above, I’ve included the database in the GitHub repo but you can download it again from the original source if you prefer.

Original MNIST Download: http://yann.lecun.com/exdb/mnist/

Continue reading “OCR 2 – The MNIST Database”

Mystery Blogger Award

I tried in vain to get my last case out of my head!

I put down the paper and stared at the rain drops collecting on my window and the lights behind them.

I was just about to close up the agency for the day when the pinkest dame you ever saw walked through my door.

She was truly vibrant!

Which was odd because this classic sifi-noir pulp comic-book mystery is written in black and white! 😉

She told me her name was Pinkie Fuchsia.

Miss Fuchsia told me she had recently inherited her long lost rich aunt’s island resort & nightclub for exotic wild pocket monsters… then the chain-letter blogging requests started.

At first she complied with their demands for more information but as their demands grew it became obvious that she needed help.

The cops told her there was nothing they could do, which is when she walked through my door.

The natural solution was for Pinkie to nominate me as the next “hop” in the chain so that my investigation wouldn’t arouse suspicion.

My Award / Nomination

Mystery Blogger Award
Mystery Blogger Award

I was more than a bit skeptical that the award wasn’t just floated around by some partially corrupt marketing department looking to data-mine a free model and pocket some dough off the sins of a few bloggers!

I mean, if these chain awards were diseases most would easily have an “R naught” in the hundreds and should be fairly easy to track by “ping-back” or filtering for posts containing “Mystery Blogger Award” (or whatever the name happens to be) and having the appropriate uh… inappropriate hashed tags.

Maybe they just want to map the spread of information and or establish the web of social connections… I just don’t know how deep the lies go!

In any case, Pinkie did some sleuthing on her own and discovered that there are several different versions of the award floating around.

It could just be evolution of a symbol over time or… it could be something more sinister!

If I were phishing for delicious details to fill my database I could use a different award logo image to differentiate different versions or iterations of each campaign to help track which variant propagated through which people and networks and then correlate all that back to their names!

What I mean to say is… this can surely not be that because… well, (allegedly) this chain-letter post was started by someone with the confidence boosting moniker Okoto Enigma!

Now… this could be coincidence and I could simply be seeing things that aren’t there but… ‘Okoto Enigma’ happens to be a mix of Bulgarian and English words which roughly translates to ‘The Eye of Enigma’ or perhaps less menacingly it should probably be translated colloquially to mean ‘Enigma Eye’ or ‘Mystery Watcher’.

I’ll say this… you may be watching us, but just like Homolka (not that one) said, “We are watching you” too!

Stop eating my sesame cake!

The Rules

So… there are some rules that come along with this award:

  • Display the award logo on your blog.
  • Thank the blogger who nominated you and provide a link to their blog.
  • Mention the creator of the award and provide a link.
  • Tell your readers 3 things about yourself.
  • Answer 5 questions from the nominee.
  • Nominate 10 – 20 bloggers.
  • Notify your nominees by leaving a comment on their blog.
  • Ask your nominees 5 questions of your choice, including 1 weird or funny question.
  • Share the link to your best post.

Three Things About Me

I’m supposed to tell you three things about myself so here goes…

  1. I’m a parent.
  2. I’ve experienced chromesthesia.
  3. I am more paranoid than… Black Sabbath singing ‘Paranoid’ followed by Rockwell’s ‘Somebody’s Watching Me’!

The Questions

With everything that came before us in the past, let’s answer some questions!

1. What is your favorite board game/tabletop game.

Well, I mean dominoes is kinda fun… but I have some fond memories of playing these games with friends (in no order):

  • Settlers of Catan
  • Eldersign
  • Last Night on Earth
  • Star Frontiers
  • Cards Against Humanity
  • Gloom
  • Zombie Dice

2. What is your favorite (anime) companion “creature” or general mascotte. (Examples Happy, Pikachu but also BB8 from Star Wars)

Does BB8 classify as anime? Turns out yes because Star Wars did an anime version! 😛

Would the Spaceship extraterrestrials from the 1987 film *batteries not included count? Nope, no anime version… hmmm… that means Johnny 5 and Bender Rodriguez are out too! 😦

I am aware of the Bender fandom anime but those are not canon and don’t count!

It did occur to me that I could “Rotoscope” them in using an anime style.

What is Rotoscoping?

Here’s another video and it’s pretty thorough but it spends less time covering rotoscoping anime.

With an inflated sense of my artistic abilities I decided to test if I could turn a few of my options into a passable anime and have my cake and eat it too…

I started from the Elon gif I used in my Emote-a-tron post and then Rotoscoped it into two different cartoon versions:

First Rotoscoped Version

Second Rotoscoped Version

Sadly, neither is really close to looking anything like an anime IMHO so decided that even if I had succeed it wouldn’t count because I’m not Japanese and my simulated anime style would only be fan art.

With all my attempts to cheat the Kobayashi Maru having failed I return to your question.

I choose Kenshiro from Fist of the North Star as my champion, yes… I know that’s manga!

Clearly I mean the anime TV series version!

Because… he seems like he would make a great mascot & bodyguard and need I remind you I am paranoid? 😛

3. What is an overused trope in fiction you still like no matter how often it is used? If you don’t have any.. pick the one you mind the least.

It’s a cliche at this point but a “Logic Bomb” destroying super computers and AI is probably top of my list.

Here’s a more thorough discussion of the topic if you are interested: https://allthetropes.fandom.com/wiki/Logic_Bomb

It includes a fairly comprehensive list of relevant pop culture examples and by virtue of starting with ‘A’ in English, anime references are top of the list. 😛

Below are a couple of examples I enjoy from the TOS episode I Mudd.

Here you see Spock at his purely logical best deploying a minimalist bunker buster against two androids though sadly this clip doesn’t include the result which is their necklaces start wildly beeping and flashing (like androids tend to do) and it’s so effective they are completely frozen in place in the face of Spock’s mighty logician skills! 😛

In the same episode of TOS (I Mudd) we see a less elegant and more complicated (theatrically drawn out) example though still effective using the “Liars Paradox” logic bomb to figuratively and literally blow the the remaining androids minds!

Now, just in case you are thinking the “smart-bomb” scene in the 1974 John Carpenter film Dark Star includes a “logic bomb”, you would be mistaken.

That instance actually involved a conversation on phenomenology and Cartesian doubt which is arguably the more intellectual approach to dealing with rogue AI but as demonstrated, unless you get it just right you are almost always better off with a simple logic bomb!

If anything, the scene is worth a view on the basis that it could save your life if you are ever in a similar situation! 😛

4. Zombie Apocalypse, Alien invasion or A.I. revolting against man which one will happen and whose side will you be on? Doing what?

Why not all three simultaneous (not the chef song)?

Attack of the Robotic Zombie Aliens!!!!!

Look, with your ducks and bad luck and my obscenely colorful paranoia as the well established fact that I’m traveling with Kenshiro… rolling a snake eyes apocalypse seems highly probable!

Of course the DM would have to breakout the expanded rule set and roll tables to handle that epic adventure!

As far as sides go… I tend to think I would definitely be on my side and tangentially humanities side because participating in the destruction or subjugation of my species seems contrary to my best interest.

Beyond that though, I don’t think we should build conscious slave AI when artificially intelligent machines are good enough.

If we build a machine that is “alive” then by definition it must be “a person” so it should naturally possess the same inalienable rights and obligations as any other person.

Person or not though… zombie, alien or AI… alien-zombie-ai… no matter the variant I’d let Kenshiro do what he does best and shuffle their domino bones!

I’d probably spend a lot of time looking for a G.E.C.K. or Platinum Chip, solving quests for local NPC settlements and trying to convince all factions to end the fighting.

This question inspired today’s featured image and wallpaper:

An alien robot zombie attacking.

Mystery Blogger Award Wallpaper
Mystery Blogger Award Wallpaper

5. The weird question, this one had to be at least a bit tricky to answer so this is a TAG question.

Step 1: You have to set up a date for Pinkie, which blogger do you set her up with? (tag the blogger you )

Step 2: Pinkie will set you up for a date in return which blogger would you like to be set up with. (tag the suggestion)

This is going to come off as completely conceited and it totally is… can I tag myself?

My Questions and Nominations

As far as nominations go… anyone who wants to should feel nominated now.

As for questions: “5 questions of your choice, including 1 weird or funny question”

  1. Favorite food?
  2. Favorite TV show?
  3. Favorite time of the day? Why?
  4. What made you decide to self nominate for this award?
  5. Most people don’t know that before becoming rich and famous, actors Adam Sandler, Brendan Fraser and Steve Buscemi were all in an obscure and failing band together called ‘The Lone Ranges’, there is a documentary about it called Airheads. Anyway, after they got out of prison their band broke up and they all started acting. Their only hit single was called ‘Degenerated’. The opening lyrics go:

“What’s Johnny doing out on a Tuesday night?
Johnny can’t read, Johnny can’t write.
Kids just don’t understand!
Johnny don’t care about the world”

So the question is… Why was Johnny out on a Tuesday night and what was he up to?

Best Post

It’s subjective at best and even then I don’t have any clue. Here’s a link to my Topics and Posts page that has most of my post series and although there are a few missing I’m sure most of the good ones are there… so maybe leave a comment with whatever post you think is my best?

And with that, I’m going to call it a day.


If you enjoy… whatever this was, I have a Patreon where you can give me as little as $1 a month, $12 a year and you can cancel anytime! 😛

But, as always, if all you can do is LikeShareComment and Subscribe… That’s cool too! 🙂

Much Love,

~Joy

Ancestor Simulations Adding Elements & Solar Nebulae

It’s Friday so that means your probably planning to pick up a 6..er 24 pack of beer and holding up in front of your computer all weekend and reviewing and modifying all my recent changes to the solar systems generator prototype. Frankly I can’t say that I blame you because there is quite a bit to go over! 😛

Before we proceed I want to welcome and thank directly Erich Weidtmann over on Patreon for becoming my supporter! With your help I will be able to continue to bring you these great posts! The funds you contribute will go towards the fund to improve our hosting and computational capacity!

I have already added him over on my Sponsors page as a public and on going thank you for continuing to sponsor my posts and projects. If you would also like to add your name to my sponsors list then support me over on Patreon for as little as $12 a year!

 

Solar Nebulae

I know in my last post Monday Mini Makeup I didn’t think we were going to add Solar Nebulae  due to the large number of computations required (SO MANY) which results in a simulation that takes hours or days to complete. I did however say that I would attempt it and get back to you and well, I am pleased to say that it bugged me enough that I went ahead and added it anyway!

I conducted my first long simulation (15,000 epochs) after adding solar nebula and took 19 hours (roughly 1 epoch (cycle or frame of the simulation) every 13 Minutes & 12 Seconds) to complete the run and it had over 100 thousand orbital bodies ranging in size from ~marble or “ball bearing” size up to several hundred kilometers in diameter.

Before we look at the code let’s talk about what a solar Nebula is and look at some pretty pictures while we’re at it! 😛

Protoplanetary-diskAn artist’s concept of a protoplanetary disk, where particles of dust and grit collide and accrete forming planets or asteroids

 

SolarnebulaShock waves through icy parts of the solar nebula may be the mechanism that enriched ancient meteorites (called chondrites) with water — water that some believe provided an otherwise dry Earth with oceans.

Basically a solar nebula (protoplanetary disk) is all the stuff (rocks, minerals and elements) that make up a solar system just spread out and not congealed into large bodies like planets and moons because the system is still “young” and forming.

In practice this means that the main difference between the nebula and the protoplanets is size and by extension due to the additional mass and volume a larger chemical element diversity.

In our simulation, the orbital bodies that comprise the solar nebula are much smaller than protoplanets and we also don’t compute their orbits (movement). Further still, we do not enable collision detection from the perspective of the nebula.What this means is that although the objects will accrete if a planet passes close enough to them, they do not accrete with each other, which sucks but since they are not moving anyway this significantly reduces the computation required per frame but at the cost of a stationary cloud that would in reality orbit the star like the protoplanets.

I feel like this is a fair tradeoff however as it still enables the planets to grow and this even approximates the planets “clearing their neighborhood” as can be seen in this frame from one of the simulation I recently ran. Notice the empty areas that look like striations in the laminar flow of the orbits through the nebula.

Here is the code that creates the nebula, notice 3 things.

  1. The sizes are listed in both metric and imperial for your convenience! 😉
  2. The code is not much different from the code that creates the planets. We do this separately for simplicity however we could wrap this up into a single step if and when we clean up the code (remember this is a prototype).
  3. The code that positions the cloud objects is the same logarithmic spiral algorithm that we implemented when we were creating galaxies.

 if(isset($_POST['enable-solar-nebula'])){ 

	$a = 0.9759 + RandomFloat(0);
	$b = 0.1759;
	$steps = 7; 
	$radius = 0.8 * pi()* $steps;
	$max_spread = 0.7;
	$lower_disk_radius = -6;
	$higher_disk_radius = 6;
    
	
	for($i = 0; $i < 200000; $i++){

		// Nebula
		
		// Debris size
		$size = mt_rand(0,6);
		if($size == 0){
			$size = "0.0" . mt_rand(1,9); // 31.855 Kilometers - 286.695 Kilometers in Diameter
		}                                 // 19.7937793 Miles - 178.144014 Miles in Diameter
		
		elseif($size == 1){
			$size = "0.00" . mt_rand(1,9); // 3.1855 Kilometers - 28.6695 Kilometers in Diameter
		}                                  // 1.97937793 Miles - 17.8144014 Miles in Diameter
		
		elseif($size == 2){ 
			$size = "0.000" . mt_rand(1,9); // 318.55 Meters - 2.86695 Kilometers in Diameter
		}                                   // 348.370516208 Yards - 1.78144014 Miles in Diameter
		
		elseif($size == 3){
			$size = "0.0000" . mt_rand(1,9); // 31.855 Meters - 286.695 Meters in Diameter
		}                                    // 34.837051619 Yards - 313.53346457 Yards in Diameter
		
		elseif($size == 4){
			$size = "0.00000" . mt_rand(1,9); // 3.1855 Meters - 28.6695 Meters in Diameter
		}                                     // 3.48370516185 Yards - 31.3533464567 Yards in Diameter
		
		elseif($size == 5){
			$size = "0.000000" . mt_rand(1,9); // 0.00031855 - 0.00286695 Kilometers in Diameter
		}                                      // 1.04511155 Feet - 9.406003937008 Feet in Diameter

		elseif($size == 6){
			$size = "0.0000000" . mt_rand(1,9); // 3.1855 Centimeters - 28.6695 Centimeters in Diameter
		}                                       // 1.25413386 Inches - 11.28720472 Inches in Diameter
		

		
		
		
		  $angle = $radius * RandomFloat(3); // Pick a random point in the Spiral
		  $row = $a * exp($b * $angle) * cos($angle);
		  $row = $row + ($max_spread * $row * RandomFloat(0)) - ($max_spread * $row * RandomFloat(0));
		  $col = $a * exp($b * $angle) * sin($angle); 
		  $col = $col + ($max_spread * $col * RandomFloat(0)) - ($max_spread * $col * RandomFloat(0));

		  // Flip a coin to determine which arm 
		  // the star should be on.
		  if (mt_rand(0, 1) == 1){
			  // if heads put it on the second arm
			  // by inverting the values
			  $row = ($row/-1);
			  $col = ($col/-1);
		  } 

		  // Normalize positions to be within the image bounds
		  $row = MinMax($row, $lower_disk_radius, $higher_disk_radius, $img_size);
		  $col = MinMax($col, $lower_disk_radius, $higher_disk_radius, $img_size);

			
		$color = imagecolorallocate($system, mt_rand(10, 50), mt_rand(10, 50), mt_rand(10, 50));
		@imagefilledellipse ( $system, round($row), round($col), (float)$size, (float)$size, $color);
		
		
		array_push($planets, array(
	   'au'=>$row+$col,
	   'size'=>$size,
	   'color'=>$color,
	   'vy'=>0,
	   'vx'=>0,
	   'x'=>$col,
	   'y'=>$row,
	   'r'=>$radius,
	   'a'=>$angle,
	   'ax'=>0,
	   'ay'=>0,
	   'row'=>$row,
	   'col'=>$col,
	   'plot'=>true,
	   'motion'=>false
	   ));

	}
 }

I wish we had the computation capacity available to include motion on the nebula as well but we really have hit a brick wall in this regard. I may attempt to improve this by using the few remaining tricks up my sleeves but I highly doubt I will get enough improvement what would allow the sim to speed up enough for modeling the orbital dynamics of the nebula, but I’ll try and see what comes out the other side. 😛

Elements

Now lets talk about our burgeoning chemical system for a minute. It gets a few things right and a lot wrong or rather it simply omits quite a bit of whats makes elements, “elements” (namely subatomic particles).

The main thing to keep in mind is that it’s still an early implementation and treats all volumes of each element equally. Obviously this is nonsensical and I intend to improve this by accounting for the size of the orbital bodies so that we get a more accurate simulation.

Currently what is occurring is we track the correct distribution, transfer and spread of the elements but not their correct volumes. I intend to fix this issue and discus elements in more detail in my next post (I wasn’t actually planing to be implementing the solar nebula) so although a basic implementation is in place it requires a lot of work before we can consider the elements even remotely “done”. Having said that here is the code that initializes the elements:

 

if(isset($_POST['enable-elemental-simulation'])){
	////
	// Meet the elements
	////
	$chemical_elements = array('Hydrogen', 'Helium', 'Lithium', 'Beryllium', 'Boron', 'Carbon', 'Nitrogen', 'Oxygen', 'Fluorine', 'Neon', 'Sodium', 'Magnesium', 'Aluminium', 'Silicon', 'Phosphorus', 'Sulfur', 'Chlorine', 'Argon', 'Potassium', 'Calcium', 'Scandium', 'Titanium', 'Vanadium', 'Chromium', 'Manganese', 'Iron', 'Cobalt', 'Nickel', 'Copper', 'Zinc', 'Gallium', 'Germanium', 'Arsenic', 'Selenium', 'Bromine', 'Krypton', 'Rubidium', 'Strontium', 'Yttrium', 'Zirconium', 'Niobium', 'Molybdenum', 'Technetium', 'Ruthenium', 'Rhodium', 'Palladium', 'Silver', 'Cadmium', 'Indium', 'Tin', 'Antimony', 'Tellurium', 'Iodine', 'Xenon', 'Caesium', 'Barium', 'Lanthanum', 'Cerium', 'Praseodymium', 'Neodymium', 'Promethium', 'Samarium', 'Europium', 'Gadolinium', 'Terbium', 'Dysprosium', 'Holmium', 'Erbium', 'Thulium', 'Ytterbium', 'Lutetium', 'Hafnium', 'Tantalum', 'Tungsten', 'Rhenium', 'Osmium', 'Iridium', 'Platinum', 'Gold', 'Mercury', 'Thallium', 'Lead', 'Bismuth', 'Polonium', 'Astatine', 'Radon', 'Francium', 'Radium', 'Actinium', 'Thorium', 'Protactinium', 'Uranium', 'Neptunium', 'Plutonium', 'Americium', 'Curium', 'Berkelium', 'Californium', 'Einsteinium', 'Fermium', 'Mendelevium', 'Nobelium', 'Lawrencium', 'Rutherfordium', 'Dubnium', 'Seaborgium', 'Bohrium', 'Hassium', 'Meitnerium', 'Darmstadtium', 'Roentgenium', 'Copernicium', 'Nihonium', 'Flerovium', 'Moscovium', 'Livermorium', 'Tennessine', 'Oganesson');

	// initialize unique element spawn probability "weights" for this solar system
	$element_weights = array();
	$number_of_elements = count($chemical_elements); // count the elements
	for($i = 0; $i < $number_of_elements; $i++){
		array_push($element_weights, mt_rand(0, $number_of_elements));
	}
	// combine the element names as keys and the weights as values
	$chemical_elements = array_combine($chemical_elements, $element_weights);
}

 

This code generates the elements for a protoplanet based on the probability distribution (weights) for this unique solar system (not all systems will have the same amount of elements):



$body_elements = array();
	if(isset($_POST['enable-elemental-simulation']) && $_POST['enable-elemental-simulation'] == true){
		// Add Elements
		$number_of_elements_to_spawn = mt_rand(10,15);
		for($elem = 0; $elem < $number_of_elements_to_spawn; $elem++){

			//select an element
			$select_element = mt_rand(1,array_sum($chemical_elements));

			// Find the selected element
			$num = 0;
			foreach($chemical_elements as $value=>$weight){
				if(($num += $weight) >= $select_element){
					//echo "$weight $value" . PHP_EOL;
					
					// push element onto the orbital body
					array_push($body_elements, $value);
					break;
				}
			}
		}
	}

And that’s it for today!

You can find the updated code for this project over on my GitHub profile.

Please Like, Comment below & Share this post with your friends and followers on social media.

This post was made possible by the generous contributions of my sponsors on Patreon.

As always, have a great weekend and I will see you all in my next post!

Much Love,

~Joy

 

Ancestor Simulations The Sol System Friday Fun Fix

Hello again and happy Friday! I can’t tell you how much I’ve been looking forward to this weekend! I’ve been having a pretty bad week in case you missed my post: Are You Prepared For Disaster? However today we’re going to have some fun with another Friday Fun Fix!

We’ll be “fixing” or expanding on this past Monday’s post Ancestor Simulations The Sol System.

If you’ve missed any of this series you can find my past Ancestor Simulations articles Here:

Ancestor Simulations and Drakes Equation

Ancestor Simulations Generating Planet Terrain

Ancestor Simulations Generating Planet Terrain Friday Fun Fix

Ancestor Simulations Generating Galaxies

Ancestor Simulations Generating Galaxies Friday Fun Fix

Comparing Sizes

So to get started off right, how about a size comparison of our sun and all the planets?

Most of the time we miss out on the fact that the planets are not all the same size and even the gas giants & ice giants look rather small when compared to the actual size of the sun!

Checkout how tiny Mercury is!  The main reason why I had to make this image as large as it is was simply that any smaller and Mercury becomes impossible to render at it’s real size ratio! I’m talking “sub pixel” here folks!

Click for full size image.

Here is the code that generates this image:



////
// Create Solar System
////
$size = 4096;
$system = imagecreatetruecolor(2500, 2000);
$space_black = imagecolorallocate($system, 0, 0, 0);

////
// Define Sun
////
$sun_size = 10 * 109; // Size
$sun_x = $sun_size; // center the sun on x
$sun_y = $sun_size; // center the sun on y
$sun_yellow = imagecolorallocate($system, 255, 255, 0); // Color
// plot sun
@imagefilledellipse ( $system, $sun_y, $sun_x, $sun_size, $sun_size, $sun_yellow);

////
// Define Mercury
////
$mercury_size = 10 * 0.38; // Size
$mercury_grey = imagecolorallocate($system, 100, 100, 100); // Color
$mercury_x = $sun_size + $sun_size/2 + 50; // Initial x position
$mercury_y = $sun_size; // Initial y position

////
// Define Venus
////
$venus_size= 10 * 0.95; // Size
$venus_brown = imagecolorallocate($system, 150, 100, 0); // Color
$venus_x = $sun_size + $sun_size/2 + 150; // Initial x position
$venus_y = $sun_size; // Initial y position

////
// Define Earth
////
$earth_size = 10; // Size
$earth_blue = imagecolorallocate($system, 0, 0, 255); // Color
$earth_x = $sun_size + $sun_size/2 + 250; // Initial x position
$earth_y = $sun_size; // Initial y position

////
// Define Mars
////
$mars_size = 10 * 0.93; // Size
$mars_red = imagecolorallocate($system, 255, 0, 0); // Color
$mars_x = $sun_size + $sun_size/2 + 350; // Initial x position
$mars_y = $sun_size; // Initial y position

////
// Define Jupiter
////
$jupiter_size = 10 * 11.19; // Size
$jupiter_red = imagecolorallocate($system, 255, 0, 0); // Color
$jupiter_x = $sun_size + $sun_size/2 + 80; // Initial x position
$jupiter_y = $sun_size + 150; // Initial y position

////
// Define Saturn
////
$saturn_size = 10 *9.40; // Size
$saturn_tan = imagecolorallocate($system, 210,180,140); // Color
$saturn_x = $sun_size + $sun_size/2 + 200; // Initial x position
$saturn_y = $sun_size + 150; // Initial y position

////
// Define Uranus
////
$uranus_size = 10 * 4.04; // Size
$uranus_blue = imagecolorallocate($system, 173,216,230); // Color
$uranus_x = $sun_size + $sun_size/2 + 310; // Initial x position
$uranus_y =  $sun_size + 150; // Initial y position

////
// Define Neptune
////
$neptune_size = 10 * 3.88 ; // Size
$neptune_blue = imagecolorallocate($system, 100,200,255); // Color
$neptune_x = $sun_size + $sun_size/2 + 390; // Initial x position
$neptune_y = $sun_size + 150; // Initial y position

@imagefilledellipse ( $system, $mercury_x, $mercury_y , $mercury_size, $mercury_size, $mercury_grey);
@imagefilledellipse ( $system, $venus_x, $venus_y, $venus_size, $venus_size, $venus_brown );
@imagefilledellipse ( $system, $earth_x, $earth_y, $earth_size, $earth_size, $earth_blue );
@imagefilledellipse ( $system, $mars_x, $mars_y, $mars_size, $mars_size, $mars_red);
@imagefilledellipse ($system, $jupiter_x, $jupiter_y, $jupiter_size, $jupiter_size, $jupiter_red);
@imagefilledellipse ($system, $saturn_x, $saturn_y, $saturn_size, $saturn_size, $saturn_tan);
@imagefilledellipse ($system, $uranus_x, $uranus_y, $uranus_size, $uranus_size, $uranus_blue);
@imagefilledellipse ($system, $neptune_x, $neptune_y, $neptune_size, $neptune_size, $neptune_blue);

@imagestring ( $system, 5, $sun_x , $sun_y , "Sun" , $space_black );
@imagestring ( $system, 5, $mercury_x, $mercury_y + 10, "Mercury", $mercury_grey);
@imagestring ( $system, 5, $venus_x, $venus_y + 10, "Venus" , $venus_brown );
@imagestring ( $system, 5, $earth_x, $earth_y + 10, "Earth" , $earth_blue );
@imagestring ( $system, 5, $mars_x, $mars_y + 10, "Mars" , $mars_red );
@imagestring ($system, 5, $jupiter_x, $jupiter_y + 60, "Jupiter", $jupiter_red);
@imagestring ($system, 5, $saturn_x, $saturn_y + 50, "Saturn", $saturn_tan);
@imagestring ($system, 5, $uranus_x, $uranus_y + 25, "Uranus", $uranus_blue);
@imagestring ($system, 5, $neptune_x, $neptune_y + 25, "Neptune", $neptune_blue);

$interface_green = imagecolorallocate($system, 0,255,0); // Color
@imagestring ($system, 5, $sun_size + $sun_size/2 + 90,  $sun_size - 100, "Solar System Size Comparison" , $interface_green);
@imagestring ($system, 5, $sun_size + $sun_size/2 + 125,  $sun_size - 30, "Inner Rocky Planets" , $interface_green);
@imagestring ($system, 5, $sun_size + $sun_size/2 + 75,  $sun_size + 65, "Outer Gas Giants" , $interface_green);
@imagestring ($system, 5, $sun_size + $sun_size/2 + 280,  $sun_size + 100, "Outer Ice Giants" , $interface_green);

// Output image
imagepng($system, "planetsizes.png");

// free memory
imagedestroy($system);

Adding the Missing Giants

On Monday we animated approximately 1 year of the 4 inner rocky planets.

So for my next trick 😛 lets add the missing outer gas & ice giants to our solar system animation! Also, lets add the solar bodies names so that we can see everything a little easier and while we’re at it, lets add a counter to show how much time has passed. 😎

Click for full size animation.

Here is the code that generates this animation:


//////////////////////////////////////////////
// Begin Functions
////
// Normalize data range
function MinMax($value, $min, $max, $size){
    return abs(($value - $min) / ($max - $min) * $size);
}
// Get the file extension 
function GetFileExtension($image){
	$path_data = pathinfo('images/' . $image);
	return strtolower($path_data['extension']);
}
// Load an image resource
function LoadImage($image){
	$ext = GetFileExtension($image);
	if($ext == 'jpg' || $ext == 'jpeg'){$image = imageCreateFromJpeg('images/' . $image);}
	elseif($ext == 'png'){$image = imageCreateFromPng('images/' . $image);}
	elseif($ext == 'bmp'){$image = imageCreateFromBmp('images/' . $image);}
	else{return null;}
	return $image;
}
// Buffer Images
function EncodeImage($image){
	
	global $images, $buffered;
	ob_start(); // Start the buffer
	imagegif($image); // Output image buffer as a gif encoded still
	$images[]=ob_get_contents(); // add the gif still to the images array
	//$buffered[]=$delay; // Delay in the animation.
	$buffered[]= (100 * $_SESSION['delay']); // Delay in the animation (ms * delay in seconds)
	ob_end_clean(); // Stop the buffer
}
 
// Create Gif
function CreateGif($num_images){
	global $images, $buffered;
	
	// Do something with each image
	for($i = 1; $i < $num_images; $i++) { $image = LoadImage("$i.png"); EncodeImage($image); // Buffer image imagedestroy($image); // Free memory } // Generate the animation $gif = new GIFEncoder($images,$buffered,0,0,0,0,0,'bin'); // Save the gif $animation_file = fopen('all-planets-sol-system-orbit.gif', 'w'); fwrite($animation_file, $gif->GetAnimation());
	fclose($animation_file);
}
////
// End Functions
/////////////////////////////////////////


////
// Define Simulation
////
$delta_time = 0.03; // 0.1 // 0.03
$low = -40;
$high = 40;
$simulations = 211;// 120 // 210
$frames_per_earth_year = 210;
$display_names = true;
if (php_sapi_name() == "cli") {
	$line_ending = PHP_EOL;
}else{
	$line_ending = '
' . PHP_EOL;
}
echo 'Simulation settings initialized.' . $line_ending;


////
// Create Solar System
////
$size = 1024;
$system = imagecreatetruecolor($size, $size);
$space_black = imagecolorallocate($system, 0, 0, 0);
echo 'Solar system initialized.' . $line_ending;


////
// Define Sun
////
$sun_size=1; // Size
$sun_x = $size/2; // center the sun on x
$sun_y = $size/2; // center the sun on y
$sun_yellow = imagecolorallocate($system, 255, 255, 0); // Color
// plot sun
@imagefilledellipse ( $system, $sun_y, $sun_x, $sun_size, $sun_size, $sun_yellow);
if($display_names == true){
	@imagestring ( $system, 5, $sun_x-12 , $sun_y-7 , "Sun" , $space_black );
}
echo 'Sun initialized.' . $line_ending;


////
// Define Mercury
////
$mercury_au_from_sun=0.39; // AU from Sun
$mercury_size=round(4*0.39); // Size
$mercury_grey = imagecolorallocate($system, 100, 100, 100); // Color
$mercury_vy = 1.8; // Velocity
$mercury_vx = 0;   // Velocity
$mercury_x = $mercury_au_from_sun; // Initial x position
$mercury_y = 0; // Initial y position
$mercury_r = sqrt(pow($mercury_x,2) + pow($mercury_y,2)); // Orbital radius at this position
$mercury_a =  1.8 / pow($mercury_r, 2); // Acceleration / angle
$mercury_ax = -$mercury_a * $mercury_x / $mercury_r; // Divide the force for the angle between x & y
$mercury_ay = -$mercury_a * $mercury_y / $mercury_r; // Divide the force for the angle between x & y
// Normalize positions to be within the image bounds
$mercury_row = MinMax($mercury_y, $low, $high, $size);
$mercury_col = MinMax($mercury_x, $low, $high, $size);
// plot mercury
@imagefilledellipse ( $system, round($mercury_row), round($mercury_col), $mercury_size, $mercury_size, $mercury_grey);
if($display_names == true){
	@imagestring ( $system, 5, $mercury_row-$mercury_size+5, $mercury_col-$mercury_size+5, "Mercury", $mercury_grey);
}
echo 'Mercury initialized.' . $line_ending;


////
// Define Venus
////
$venus_au_from_sun=0.723; // AU from Sun
$venus_size=round(4*0.95); // Size
$venus_brown = imagecolorallocate($system, 150, 100, 0); // Color
$venus_vy = 1; // Velocity
$venus_vx = 0; // Velocity
$venus_x = $venus_au_from_sun; // Initial x position
$venus_y = 0; // Initial y position
$venus_r = sqrt(pow($venus_x,2) + pow($venus_y,2)); // Orbital radius at this position
$venus_a =  $venus_au_from_sun / pow($venus_r, 2); // Acceleration / angle
$venus_ax = -$venus_a * $venus_x / $venus_r; // Divide the force for the angle between x & y
$venus_ay = -$venus_a * $venus_y / $venus_r; // Divide the force for the angle between x & y
// Normalize positions to be within the image bounds
$venus_row = MinMax($venus_y, $low, $high, $size);
$venus_col = MinMax($venus_x, $low, $high, $size);
// plot venus
@imagefilledellipse ( $system, round($venus_row), round($venus_col), $venus_size+5, $venus_size, $venus_brown );
if($display_names == true){
    @imagestring ( $system, 5, $venus_row-$venus_size , $venus_col-$venus_size+5 , "Venus" , $venus_brown );
}
echo 'Venus initialized.' . $line_ending;


////
// Define Earth
////
$earth_au_from_sun=1;// AU from Sun
$earth_size=4; // Size
$earth_blue = imagecolorallocate($system, 0, 0, 255); // Color
$earth_vy = 1; // Velocity
$earth_vx = 0; // Velocity
$earth_x = $earth_au_from_sun; // Initial x position
$earth_y = 0; // Initial y position
$earth_r = sqrt(pow($earth_x,2) + pow($earth_y,2)); // Orbital radius at this position
$earth_a =  $earth_au_from_sun / pow($earth_r, 2); // Acceleration / angle
$earth_ax = -$earth_a * $earth_x / $earth_r; // Divide the force for the angle between x & y
$earth_ay = -$earth_a * $earth_y / $earth_r; // Divide the force for the angle between x & y
// Normalize positions to be within the image bounds
$earth_row = MinMax($earth_y, $low, $high, $size);
$earth_col = MinMax($earth_x, $low, $high, $size);
// plot earth
@imagefilledellipse ( $system, round($earth_row), round($earth_col), $earth_size, $earth_size, $earth_blue );
if($display_names == true){
    @imagestring ( $system, 5, $earth_row-$earth_size , $earth_col-$earth_size+5 , "Earth" , $earth_blue );
}
echo 'Earth initialized.' . $line_ending;


////
// Define Mars
////
$mars_au_from_sun = 1.524; // AU from Sun
$mars_size = round(4*0.53); // Size
$mars_red = imagecolorallocate($system, 255, 0, 0); // Color
$mars_vy = 0.8; // Velocity
$mars_vx = 0; // Velocity
$mars_x = $mars_au_from_sun; // Initial x position
$mars_y = 0; // Initial y position
$mars_r = sqrt(pow($mars_x,2) + pow($mars_y,2)); // Orbital radius at this position
$mars_a =  $mars_au_from_sun / pow($mars_r, 2); // Acceleration / angle
$mars_ax = -$mars_a * $mars_x / $mars_r; // Divide the force for the angle between x & y
$mars_ay = -$mars_a * $mars_y / $mars_r; // Divide the force for the angle between x & y
// Normalize positions to be within the image bounds
$mars_row = MinMax($mars_y, $low, $high, $size);
$mars_col = MinMax($mars_x, $low, $high, $size);
// plot mars
@imagefilledellipse ( $system, round($mars_row), round($mars_col), $mars_size, $mars_size, $mars_red);
if($display_names == true){
    @imagestring ( $system, 5, $mars_row-$mars_size , $mars_col-$mars_size+5 , "Mars" , $mars_red );
}
echo 'Mars initialized.' . $line_ending;


////
// Define Jupiter
////
$jupiter_au_from_sun = 5.2; // AU from Sun
$jupiter_size = round(4*11.19); // Size
$jupiter_red = imagecolorallocate($system, 255, 0, 0); // Color
$jupiter_vy = 0.8; // Velocity
$jupiter_vx = 0; // Velocity
$jupiter_x = $jupiter_au_from_sun; // Initial x position
$jupiter_y = 0; // Initial y position
$jupiter_r = sqrt(pow($jupiter_x,2) + pow($jupiter_y,2)); // Orbital radius at this position
$jupiter_a =  $jupiter_au_from_sun / pow($jupiter_r, 2); // Acceleration / angle
$jupiter_ax = -$jupiter_a * $jupiter_x / $jupiter_r; // Divide the force for the angle between x & y
$jupiter_ay = -$jupiter_a * $jupiter_y / $jupiter_r; // Divide the force for the angle between x & y
// Normalize positions to be within the image bounds
$jupiter_row = MinMax($jupiter_y, $low, $high, $size);
$jupiter_col = MinMax($jupiter_x, $low, $high, $size);
// Plot Jupiter
@imagefilledellipse ($system, round($jupiter_row), round($jupiter_col), $jupiter_size, $jupiter_size, $jupiter_red);
if($display_names == true){
    @imagestring ($system, 5, $jupiter_row-$jupiter_size/2, $jupiter_col-$jupiter_size+65, "Jupiter", $jupiter_red);
}
echo 'Jupiter initialized.' . $line_ending;


////
// Define Saturn
////
$saturn_au_from_sun = 9.6; // AU from Sun
$saturn_size = round(4*9.40); // Size
$saturn_tan = imagecolorallocate($system, 210,180,140); // Color
$saturn_vy = 0.8; // Velocity
$saturn_vx = 0; // Velocity
$saturn_x = $saturn_au_from_sun; // Initial x position
$saturn_y = 0; // Initial y position
$saturn_r = sqrt(pow($saturn_x,2) + pow($saturn_y,2)); // Orbital radius at this position
$saturn_a =  $saturn_au_from_sun / pow($saturn_r, 2); // Acceleration / angle
$saturn_ax = -$saturn_a * $saturn_x / $saturn_r; // Divide the force for the angle between x & y
$saturn_ay = -$saturn_a * $saturn_y / $saturn_r; // Divide the force for the angle between x & y
// Normalize positions to be within the image bounds
$saturn_row = MinMax($saturn_y, $low, $high, $size);
$saturn_col = MinMax($saturn_x, $low, $high, $size);
// Plot Saturn
@imagefilledellipse ($system, round($saturn_row), round($saturn_col), $saturn_size, $saturn_size, $saturn_tan);
if($display_names == true){
    @imagestring ($system, 5, $saturn_row-$saturn_size/2, $saturn_col-$saturn_size+60, "Saturn", $saturn_tan);
}
echo 'Saturn initialized.' . $line_ending;


////
// Define Uranus
////
$uranus_au_from_sun = 19.2; // AU from Sun
$uranus_size = round(4*4.04); // Size
$uranus_blue = imagecolorallocate($system, 173,216,230); // Color
$uranus_vy = 0.8; // Velocity
$uranus_vx = 0; // Velocity
$uranus_x = $uranus_au_from_sun; // Initial x position
$uranus_y = 0; // Initial y position
$uranus_r = sqrt(pow($uranus_x,2) + pow($uranus_y,2)); // Orbital radius at this position
$uranus_a =  $uranus_au_from_sun / pow($uranus_r, 2); // Acceleration / angle
$uranus_ax = -$uranus_a * $uranus_x / $uranus_r; // Divide the force for the angle between x & y
$uranus_ay = -$uranus_a * $uranus_y / $uranus_r; // Divide the force for the angle between x & y
// Normalize positions to be within the image bounds
$uranus_row = MinMax($uranus_y, $low, $high, $size);
$uranus_col = MinMax($uranus_x, $low, $high, $size);
// Plot Uranus
@imagefilledellipse ($system, round($uranus_row), round($uranus_col), $uranus_size, $uranus_size, $uranus_blue);
if($display_names == true){
    @imagestring ($system, 5, $uranus_row-$uranus_size, $uranus_col-$uranus_size+25, "Uranus", $uranus_blue);
}
echo 'Uranus initialized.' . $line_ending;


////
// Define Neptune
////
$neptune_au_from_sun = 29.8; // AU from Sun
$neptune_size = round($earth_size*3.88); // Size
$neptune_blue = imagecolorallocate($system, 100,200,255); // Color
$neptune_vy = 0.8; // Velocity
$neptune_vx = 0; // Velocity
$neptune_x = $neptune_au_from_sun; // Initial x position
$neptune_y = 0; // Initial y position
$neptune_r = sqrt(pow($neptune_x,2) + pow($neptune_y,2)); // Orbital radius at this position
$neptune_a =  $neptune_au_from_sun / pow($neptune_r, 2); // Acceleration / angle
$neptune_ax = -$neptune_a * $neptune_x / $neptune_r; // Divide the force for the angle between x & y
$neptune_ay = -$neptune_a * $neptune_y / $neptune_r; // Divide the force for the angle between x & y
// Normalize positions to be within the image bounds
$neptune_row = MinMax($neptune_y, $low, $high, $size);
$neptune_col = MinMax($neptune_x, $low, $high, $size);
// Plot Neptune
@imagefilledellipse ($system, round($neptune_row), round($neptune_col), $neptune_size, $neptune_size, $neptune_blue);
if($display_names == true){
    @imagestring ($system, 5, $neptune_row-$neptune_size, $neptune_col-$neptune_size+25, "Neptune", $neptune_blue);
}
echo 'Neptune initialized.' . $line_ending;


$interface_green = imagecolorallocate($system, 0,255,0); // Color
@imagestring ($system, 5, 5, 5, "0.00 Years (0 days)" , $interface_green);


// Output image
imagepng($system, "images/0.png");
// free memory
imagedestroy($system);
echo 'Simulation ready. Running...';
for($i = 0; $i < $simulations; $i++){
	
	////
	// Solar System
	////
    $system = imagecreatetruecolor($size, $size);
	
	
	////
	// Sun
	////
	// Plot Sun
	@imagefilledellipse ( $system, $sun_y, $sun_x, $sun_size, $sun_size, $sun_yellow );
	if($display_names == true){
	    @imagestring ( $system, 5, $sun_x-12 , $sun_y-7 , "Sun" , $space_black );
    }
	
	////
	// Mercury
	////
    $mercury_vx = $mercury_vx + $mercury_ax * $delta_time; // New velocity
	$mercury_vy = $mercury_vy + $mercury_ay * $delta_time; // New velocity
	$mercury_x = $mercury_x + $mercury_vx * $delta_time; // New position
	$mercury_y = $mercury_y + $mercury_vy * $delta_time; // New position
	$mercury_r = sqrt(pow($mercury_x,2) + pow($mercury_y,2)); // Orbital radius at this position
	$mercury_a =  1.8 / pow($mercury_r, 2); // Acceleration / angle
	$mercury_ax = -$mercury_a * $mercury_x / $mercury_r; // Divide the force for the angle between x & y
	$mercury_ay = -$mercury_a * $mercury_y / $mercury_r; // Divide the force for the angle between x & y
	// Normalize positions to be within the image bounds
	$mercury_row = MinMax($mercury_y, $low, $high, $size);
	$mercury_col = MinMax($mercury_x, $low, $high, $size);
	// Plot Mercury
	@imagefilledellipse ( $system, round($mercury_row), round($mercury_col), $mercury_size, $mercury_size, $mercury_grey );
	if($display_names == true){
	    @imagestring ( $system, 5, $mercury_row-$mercury_size+5, $mercury_col-$mercury_size+5, "Mercury", $mercury_grey);
    }
	
	////
	// Venus
	////
    $venus_vx = $venus_vx + $venus_ax * $delta_time; // New velocity
	$venus_vy = $venus_vy + $venus_ay * $delta_time; // New velocity
	$venus_x = $venus_x + $venus_vx * $delta_time; // New position
	$venus_y = $venus_y + $venus_vy * $delta_time; // New position
	$venus_r = sqrt(pow($venus_x,2) + pow($venus_y,2)); // Orbital radius at this position	
	$venus_a =  $venus_au_from_sun / pow($venus_r, 2); // Acceleration / angle
	$venus_ax = -$venus_a * $venus_x / $venus_r; // Divide the force for the angle between x & y
	$venus_ay = -$venus_a * $venus_y / $venus_r; // Divide the force for the angle between x & y
	// Normalize positions to be within the image bounds
	$venus_row = MinMax($venus_y, $low, $high, $size);
	$venus_col = MinMax($venus_x, $low, $high, $size);
	// Plot Venus
	@imagefilledellipse ( $system, round($venus_row), round($venus_col), $venus_size, $venus_size, $venus_brown );
	if($display_names == true){
	    @imagestring ( $system, 5, $venus_row-$venus_size , $venus_col-$venus_size+5 , "Venus" , $venus_brown );
    }
	
	////
	// Earth
	////
    $earth_vx = $earth_vx + $earth_ax * $delta_time; // New velocity
	$earth_vy = $earth_vy + $earth_ay * $delta_time; // New velocity
	$earth_x = $earth_x + $earth_vx * $delta_time; // New position
	$earth_y = $earth_y + $earth_vy * $delta_time; // New position
	$earth_r = sqrt(pow($earth_x,2) + pow($earth_y,2)); // Orbital radius at this position
	$earth_a =  $earth_au_from_sun / pow($earth_r, 2); // Acceleration / angle
	$earth_ax = -$earth_a * $earth_x / $earth_r; // Divide the force for the angle between x & y
	$earth_ay = -$earth_a * $earth_y / $earth_r; // Divide the force for the angle between x & y
	// Normalize positions to be within the image bounds
	$earth_row = MinMax($earth_y, $low, $high, $size);
	$earth_col = MinMax($earth_x, $low, $high, $size);
	// Plot Earth
	@imagefilledellipse ( $system, round($earth_row), round($earth_col), $earth_size, $earth_size, $earth_blue );
	if($display_names == true){
		@imagestring ( $system, 5, $earth_row-$earth_size , $earth_col-$earth_size+5 , "Earth" , $earth_blue );
    }
	
	////
	// Mars
	////
    $mars_vx = $mars_vx + $mars_ax * $delta_time; // New velocity
	$mars_vy = $mars_vy + $mars_ay * $delta_time; // New velocity
	$mars_x = $mars_x + $mars_vx * $delta_time; // New position
	$mars_y = $mars_y + $mars_vy * $delta_time; // New position
	$mars_r = sqrt(pow($mars_x,2) + pow($mars_y,2)); // Orbital radius at this position
	$mars_a =  $mars_au_from_sun / pow($mars_r, 2); // Acceleration / angle
	$mars_ax = -$mars_a * $mars_x / $mars_r; // Divide the force for the angle between x & y
	$mars_ay = -$mars_a * $mars_y / $mars_r; // Divide the force for the angle between x & y
	// Normalize positions to be within the image bounds
	$mars_row = MinMax($mars_y, $low, $high, $size);
	$mars_col = MinMax($mars_x, $low, $high, $size);
	// Plot Mars
	@imagefilledellipse ( $system, round($mars_row), round($mars_col), $mars_size, $mars_size, $mars_red );
	if($display_names == true){
		@imagestring ( $system, 5, $mars_row-$mars_size , $mars_col-$mars_size+5 , "Mars" , $mars_red );
	}
	
	////
	// Jupiter
	////
    $jupiter_vx = $jupiter_vx + $jupiter_ax * $delta_time; // New velocity
	$jupiter_vy = $jupiter_vy + $jupiter_ay * $delta_time; // New velocity
	$jupiter_x = $jupiter_x + $jupiter_vx * $delta_time; // New position
	$jupiter_y = $jupiter_y + $jupiter_vy * $delta_time; // New position
	$jupiter_r = sqrt(pow($jupiter_x,2) + pow($jupiter_y,2)); // Orbital radius at this position
	$jupiter_a =  $jupiter_au_from_sun / pow($jupiter_r, 2); // Acceleration / angle
	$jupiter_ax = -$jupiter_a * $jupiter_x / $jupiter_r; // Divide the force for the angle between x & y
	$jupiter_ay = -$jupiter_a * $jupiter_y / $jupiter_r; // Divide the force for the angle between x & y
	// Normalize positions to be within the image bounds
	$jupiter_row = MinMax($jupiter_y, $low, $high, $size);
	$jupiter_col = MinMax($jupiter_x, $low, $high, $size);
	// Plot Jupiter
	@imagefilledellipse ($system, round($jupiter_row), round($jupiter_col), $jupiter_size, $jupiter_size, $jupiter_red);
	if($display_names == true){
		@imagestring ($system, 5, $jupiter_row-$jupiter_size/2, $jupiter_col-$jupiter_size+65, "Jupiter", $jupiter_red);
	}

	// Saturn
	////
    $saturn_vx = $saturn_vx + $saturn_ax * $delta_time; // New velocity
	$saturn_vy = $saturn_vy + $saturn_ay * $delta_time; // New velocity
	$saturn_x = $saturn_x + $saturn_vx * $delta_time; // New position
	$saturn_y = $saturn_y + $saturn_vy * $delta_time; // New position
	$saturn_r = sqrt(pow($saturn_x,2) + pow($saturn_y,2)); // Orbital radius at this position
	$saturn_a =  $saturn_au_from_sun / pow($saturn_r, 2); // Acceleration / angle
	$saturn_ax = -$saturn_a * $saturn_x / $saturn_r; // Divide the force for the angle between x & y
	$saturn_ay = -$saturn_a * $saturn_y / $saturn_r; // Divide the force for the angle between x & y
	// Normalize positions to be within the image bounds
	$saturn_row = MinMax($saturn_y, $low, $high, $size);
	$saturn_col = MinMax($saturn_x, $low, $high, $size);
	// Plot Saturn
	@imagefilledellipse ($system, round($saturn_row), round($saturn_col), $saturn_size, $saturn_size, $saturn_tan);
	if($display_names == true){
		@imagestring ($system, 5, $saturn_row-$saturn_size/2, $saturn_col-$saturn_size+60, "Saturn", $saturn_tan);
	}
	
	////
	// Uranus
	////
    $uranus_vx = $uranus_vx + $uranus_ax * $delta_time; // New velocity
	$uranus_vy = $uranus_vy + $uranus_ay * $delta_time; // New velocity
	$uranus_x = $uranus_x + $uranus_vx * $delta_time; // New position
	$uranus_y = $uranus_y + $uranus_vy * $delta_time; // New position
	$uranus_r = sqrt(pow($uranus_x,2) + pow($uranus_y,2)); // Orbital radius at this position
	$uranus_a =  $uranus_au_from_sun / pow($uranus_r, 2); // Acceleration / angle
	$uranus_ax = -$uranus_a * $uranus_x / $uranus_r; // Divide the force for the angle between x & y
	$uranus_ay = -$uranus_a * $uranus_y / $uranus_r; // Divide the force for the angle between x & y
	// Normalize positions to be within the image bounds
	$uranus_row = MinMax($uranus_y, $low, $high, $size);
	$uranus_col = MinMax($uranus_x, $low, $high, $size);
	// Plot Uranus
	@imagefilledellipse ($system, round($uranus_row), round($uranus_col), $uranus_size, $uranus_size, $uranus_blue);
	if($display_names == true){
		@imagestring ($system, 5, $uranus_row-$uranus_size, $uranus_col-$uranus_size+25, "Uranus", $uranus_blue);
	}
	
	////
	// Neptune
	////
    $neptune_vx = $neptune_vx + $neptune_ax * $delta_time; // New velocity
	$neptune_vy = $neptune_vy + $neptune_ay * $delta_time; // New velocity
	$neptune_x = $neptune_x + $neptune_vx * $delta_time; // New position
	$neptune_y = $neptune_y + $neptune_vy * $delta_time; // New position
	$neptune_r = sqrt(pow($neptune_x,2) + pow($neptune_y,2)); // Orbital radius at this position
	$neptune_a =  $neptune_au_from_sun / pow($neptune_r, 2); // Acceleration / angle
	$neptune_ax = -$neptune_a * $neptune_x / $neptune_r; // Divide the force for the angle between x & y
	$neptune_ay = -$neptune_a * $neptune_y / $neptune_r; // Divide the force for the angle between x & y
	// Normalize positions to be within the image bounds
	$neptune_row = MinMax($neptune_y, $low, $high, $size);
	$neptune_col = MinMax($neptune_x, $low, $high, $size);
	// Plot Neptune
	@imagefilledellipse ($system, round($neptune_row), round($neptune_col), $neptune_size, $neptune_size, $neptune_blue);
	if($display_names == true){
		@imagestring ($system, 5, $neptune_row-$neptune_size, $neptune_col-$neptune_size+25, "Neptune", $neptune_blue);
	}

    @imagestring ($system, 5, 5, 5, round($i/$frames_per_earth_year, 2) . " Years (" . round((365/$frames_per_earth_year)*$i, 2) . " days)" , $interface_green);

	// Output Solar System
	imagepng($system, "images/" . ($i + 1) . ".png");
	// Free Memory
	imagedestroy($system);
}
echo 'Complete!' . $line_ending;
echo 'Generating animation...' ;
include('GIFEncoder.class.php'); // GIFEncoder class
$_SESSION['delay'] = 0.1; // 1 second
$images;
$buffered;
@CreateGif($simulations);
echo 'Complete!' .$line_ending ;

 

You can access the complete source for these projects on my GitHub here.

Well, since you came this far how about just a little farther? Did you enjoy this post? Did you hate it? Now I ask you… were you not entertained?

It takes a lot of time, planning and ‘TLC‘ to bring you these posts every week and I’d like to ask for your financial support over on Patreon for as little as $1 a month.

With that, have a great weekend & I will see you all in my next post.

 

Remember to Like, Comment & Share this post with your friends and followers on social media.

If you would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,

~Joy

Are your GIF’s infected?

Have you ever needed to create a GIF and found the available options for doing so less than stellar?

I mean sure, you could try your luck with an option off download.com and risk a virus! However, if you value your electronic devices as well as your data and would like to just skip the absolute hellish nightmare of dealing with the resulting ransomware you might just decide give one of the more reputable cloud build GIF making services a try instead.

However, fail to use one of those more “reputable” build services and you are back to square one, downloading viruses!

Further, even if you are lucky and do find a service that isn’t a front for a black hat syndicate, anyone with an ounce of sense (28.3495 grams to be exact) 😛 will be left with with more questions and concerns than confidence!

Questions like, do I still own my images? or Are the generated GIF’s mine? Have I given away or extended use rights (redistribution or public display) to the site owners? Have they been tampered with, down-scaled or were any watermarks added? Am I compromising my brand or business by using this service? Am I sure I know what I am getting back is safe for myself and my clients?

Right about now a few of you might be thinking “You can’t get a virus from an image since there is no executable code”… but of course you’d be wrong!

So… Let’s take a trip back to 2002 with this article from PC mag. The first jpeg virus had been identified in the wild and while it was benign (both then and certainly now) it demonstrates that even images can be vectors of attack and a means of passive propagation!

The fact is that even if a GIF acts only as a means of delivering a viral payload, a cargo container on which the malware hitches, the GIF (or image in general) is therefore necessarily used in conjunction with a viewer or player application (executable) and therein lies the problem! The image data must be read to be viewed.

The risk posed here is by a so called “zero-day” attack utilizing as yet undocumented vulnerabilities in the viewer app itself, the codec or libraries used to read the media or even potentially the OS, and if you think you are safe because you’d somehow intuit that the image is seemingly “larger than it should be” (in terms of byte size) well, you’d be wrong again!

Remind me to have a talk with you later about this whole doubting me thing… its weird, it’s becoming a problem and it needs to stop! 😛

Appending raw byte data is a real sloppy & amateur way to infect (or store) data in an image!

There are plenty of methods for hiding data in images that will NOT modify the file size!

Further, I have some future stenographic projects planned so I will be brief here but just to prove the point… consider an image that is only 100x100px.

Like this one:

100x100.png

 

Such an image tends to be only a few bytes to kilobytes in size, the image above is only 0.506 KB (damn small) & you could hardly store any data in that right? Well if you are a clever hacker or computer scientist you can come up with quite a few different ways to encode the data directly into the pixel values themselves while at the same time making such slight modifications to the pixels that no perceivable change has occurred!

Additionally, high definition images are common these days so if anything this example is overly critical and in reality you will commonly deal with larger images. The simple fact is you cannot simply look at file size as and indicator for file infection when the file is an image!

Therefore even in a single static JPEG image that is only 100x100px (like above) could store at minimum 10,000 characters (about double all the characters in this entire post)!

Just when you were thinking “WOW TL;DR!” 😛

If you drop fidelity of the image as a concern you can write data to all color channels and that gives you 30,000 (~6X the length of this post) characters to work with! If instead you use a PNG, so that you can play with the alpha channel too, you get 40,000 (~8X the length of this post) characters (assuming that you didn’t use the alpha channel as a checksum ;-))… I can go on for quite some time on this very deep and fascinating subject but as I said I have some stenographic projects planed for you guys in the future and we will cover this stuff in more detail in those posts, so suffice it to say that just because “it’s an image” does not make it safe!

Now, I’m not trying to scare you… okay maybe a little 😛  but I want you to understand that the fact that you upload and download images to cloud build services is in no way a protection and a professional content creator cannot guess that their content is safe to open.

This is where I found myself when I wanted to animate and publish the Sierpinski triangle animations in my post A Chaos Game.

Sierpinski_triangle

That’s why I used the GIFEncoder PHP class released by László Zsid to animate them myself using PHP rather than risk my system with unknown files! The great thing about GIFEncoder is that you don’t have to wonder if it’s safe,  feel free to read the code yourself over on my GitHub and grab a copy while you  are there! 😉

Plus admit it, its just more impressive and satisfying to copy & paste the code I give you and get a GIF rather than images which you then have to go stitch into a GIF yourself! 😛

I also previewed my latest Patreon App called GIFMaker in my last post A Value Proposition. Well today I am pleased to announce that I have made GIFMaker available over on Patreon for my User and Developer level followers!

Here are some screenshots of GIFMaker :

MAIN VIEW

FILE BROWSER

SETTINGS

 

GIFMAKER GALLERY SIGN IN

GIFMAKER GALLERY

The best part is that you can actually see the code that is responsible for creating the GIF as GIFMaker uses a PHP server back-end (either on your local machine or on your web server) so even my User level followers can modify the core functionality of GIFMaker  (and GIFMaker Gallery) to meet their needs!

If you also would like to modify the GIFMaker GUI you can become a Developer level supporter of mine and get access to the C# Source Code and Unity3D IDE Project along with a commercial reuse license should you want or need that!

  • There are no artificial limits in terms of image dimensional size or byte data placed on the application so if you have the memory and storage, feel free to make GIFs as large as you want!

 

  • GIFMaker will not apply any kind of watermarks or other branding or identifiers to the animations so all you will get back is the images you gave it, simply animated!

 

  • Comes with a Web Interface GIFMaker Gallery enabling the Viewing, Downloading and Deletion of your GIFs.

 

GIFMaker is now available over on Patreon and if it looks & sounds like something you need, consider supporting me over on Patreon so I can bring you more great prototypes and tutorials!

Have a great week!

Much Love,

~Joy

A Chaos Game

Hello everyone I hope you had a great week! Mine was too short due to the Independence Day (4th of July) holiday here in the U.S. and to make it worse , FULL of frustrating bug fixes so I am going to keep this weeks tutorial short & simple! 😛

Alright, so this week I have a fun math + animation project for you.

We are going to generate a series of images containing the Sierpinski triangle (a well known fractal) and then animate them using the GIFEncoder class released by László Zsid

The Sierpinski Triangle

Here is a time laps gif of  The Sierpinski Triangle:

Many people (myself included) find fractals incredibly beautiful!

How does this work?

It’s surprisingly simple to create the Sierpinski Triangle and there are many different ways to accomplish our goal however a really simple way is called the “chaos game“, here is the formula :

  1. Select 3 points in the image to form a triangle (ideally it should be an equilateral triangle however based on my experimentation it doesn’t seem to be absolutely required, the triangle will deform (warp) but not entirely disappear).
  2. Randomly select any point inside the points.
  3. Randomly select any one of the 3 vertex points.
  4. Move half the distance from your current position to the selected vertex.
  5. Plot the current position.
  6. Repeat from step 3.

Once we have created all the images and buffered them we create and write the animation to the new gif.

Here is the code for your review:



<?php
set_time_limit(300); // Adjust as needed

include('GIFEncoder.class.php'); // GIFEncoder class


// Buffer Images
// http://php.net/manual/en/function.ob-start.php
// http://php.net/manual/en/function.imagegif.php
// http://php.net/manual/en/function.ob-get-contents.php
// http://php.net/manual/en/function.ob-end-clean.php
function EncodeImage($image, $delay){
	
	global $images, $buffered;

	ob_start(); // Start the buffer
	imagegif($image); // Output image buffer as a gif encoded still
	$images[]=ob_get_contents(); // add the gif still to the images array
	$buffered[]=$delay; // Delay in the animation.
	ob_end_clean(); // Stop the buffer
}


// Build the triangle fractal
// https://en.wikipedia.org/wiki/Sierpinski_triangle
// http://php.net/manual/en/function.imagecolorallocate.php
// http://php.net/manual/en/function.mt-rand.php
// http://php.net/manual/en/function.imagesetpixel.php
function ChaosGame($image, $points){
	global $density,$x, $y;
	
	$counter = 0;
	for ($i = 1; $i < $density; $i++) { // Higher density will plot more points
	
	  $COL = imagecolorallocate($image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); // Random Color
	  imagesetpixel($image, round($x),round($y), $COL); // Plot the current position
	  $a = mt_rand(0, 2); // Randomly select any one of the 3 vertex points for next the iteration
	  
	  // Move half the distance from your current position 
	  // to the selected vertex for next the iteration
	  $x = ($x + $points[$a]['x']) / 2;
	  $y = ($y + $points[$a]['y']) / 2;
	  
	  $counter++;
	  
	  if($counter >= 1000){
		  imagepng($image , "$i.png"); // Save the image 
		  EncodeImage($image, 1); // Buffer image
		  $counter = 0;
	  }
	}

}


$images;
$buffered;

$density = 100000;

$x = 600; // Reset $x
$y = 600; // Reset $y

$inset = 10;
$points[0] = array('x' => $x / 2, 'y' =>  $inset); // Top
$points[1] = array('x' =>   $inset, 'y' => $y - 0); // Left
$points[2] = array('x' => $x - $inset, 'y' => $y - 0); // Right
$image = imagecreatetruecolor($x, $y); // Create the image resource 
ChaosGame($image, $points); // This triangle will rotate
imagedestroy($image); // Free memory


// Generate the animation
$gif = new GIFEncoder($images,$buffered,0,0,0,0,0,'bin');

// Save the gif
$animation_file = fopen('timelaps.gif', 'w');
fwrite($animation_file, $gif->GetAnimation());
fclose($animation_file);

?>

 

 

We can have a little more fun by drawing more than one at a time and animating it like this:

Here is the code:



<?php
set_time_limit(300); // Adjust as needed

include('GIFEncoder.class.php'); // GIFEncoder class


// Buffer Images
// http://php.net/manual/en/function.ob-start.php
// http://php.net/manual/en/function.imagegif.php
// http://php.net/manual/en/function.ob-get-contents.php
// http://php.net/manual/en/function.ob-end-clean.php
function EncodeImage($image, $delay){
	
	global $images, $buffered;

	ob_start(); // Start the buffer
	imagegif($image); // Output image buffer as a gif encoded still
	$images[]=ob_get_contents(); // add the gif still to the images array
	$buffered[]=$delay; // Delay in the animation.
	ob_end_clean(); // Stop the buffer
}


// Build the triangle fractal
// https://en.wikipedia.org/wiki/Sierpinski_triangle
// http://php.net/manual/en/function.imagecolorallocate.php
// http://php.net/manual/en/function.mt-rand.php
// http://php.net/manual/en/function.imagesetpixel.php
function ChaosGame($image, $points){
	global $density,$x, $y;
	
	for ($i = 1; $i < $density; $i++) { // Higher density will plot more points
	  $COL = imagecolorallocate($image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)); // Random Color
	  imagesetpixel($image, round($x),round($y), $COL); // Plot the current position
	  $a = mt_rand(0, 2); // Randomly select any one of the 3 vertex points for next the iteration
	  
	  // Move half the distance from your current position 
	  // to the selected vertex for next the iteration
	  $x = ($x + $points[$a]['x']) / 2;
	  $y = ($y + $points[$a]['y']) / 2;
	}
	
}


$images;
$buffered;

$density = 100000;
$frame_increment = 7; // Set to 1 for 360 still images.
                      // At 7 we get 52.

// Create the still images
for ($k = 1; $k < 360; $k+=$frame_increment) {
	$x = 600; // Reset $x
	$y = 600; // Reset $y
	$points[0] = array('x' => $x / 2, 'y' =>  0); // Top
	$points[1] = array('x' =>   10, 'y' => $y - 0); // Left
	$points[2] = array('x' => $x - 10, 'y' => $y - 0); // Right
	$image = imagecreatetruecolor($x, $y); // Create the image resource 
	ChaosGame($image, $points); // This triangle will rotate
    $image = imagerotate($image, $k, 0); // Perform rotation
	ChaosGame($image, $points); // This triangle will not
	imagepng($image , "$k.png"); // Save the image 
	EncodeImage($image, 1); // Buffer image
	imagedestroy($image); // Free memory
}


// Generate the animation
$gif = new GIFEncoder($images,$buffered,0,0,0,0,0,'bin');

// Save the gif
$animation_file = fopen('Sierpinski_triangle.gif', 'w');
fwrite($animation_file, $gif->GetAnimation());
fclose($animation_file);

?>

 

And as previously mentioned, since this post falls during the week of American Independence I would be remiss by not mixing in a little little Red White and Blue, rendered for your desktop wallpaper pleasure (click to get it fullsize):

Here is the code:



<?php
set_time_limit(300); // 5 Minutes Adjust as needed
ini_set('memory_limit', '2G'); // 2 GB Adjust as needed


$images;
$buffered;

$density = 1000000; // Higher density will plot more points but is costly on large images
$x = 4000; // Reset $x
$y = 4000; // Reset $y

$inset = 10;
$points[0] = array('x' => $x / 2, 'y' =>  $inset); // Top
$points[1] = array('x' =>   $inset, 'y' => $y - 0); // Left
$points[2] = array('x' => $x - $inset, 'y' => $y - 0); // Right
$image = imagecreatetruecolor($x, $y); // Create the image resource 

$red = imagecolorallocate($image, 255, 0, 0);
$white = imagecolorallocate($image, 255, 255, 255);
$blue = imagecolorallocate($image, 0, 0, 255);

for ($i = 1; $i < $density; $i++) { // Higher density will plot more points but is costly on large images

  if($x < 4000 / 3){$color = $red;}
  elseif($x > ((4000 / 3)) && $x < ((4000 / 3)*2) ){$color = $white;}
  else{$color = $blue;}

  imagesetpixel($image, round($x),round($y), $color); // Plot the current position
  $a = mt_rand(0, 2); // Randomly select any one of the 3 vertex points for next the iteration
  
  // Move half the distance from your current position 
  // to the selected vertex for next the iteration
  $x = ($x + $points[$a]['x']) / 2;
  $y = ($y + $points[$a]['y']) / 2;
}

imagejpeg($image , "redgreenblue.jpg"); // Save the image 

imagedestroy($image); // Free memory

?>

 

If you would like to obtain a copy of this code from GitHub you can find it here: SierpinskiTriangle Project on GitHub

 

Please support me on Patreon so I can continue to bring you more great tutorials like this!

As always I hope you found this both interesting and informative. Please Like, Comment & Share this post with your friends and followers on your social media platforms and don’t forget to click the follow button over on the top right of this page to get notified when I post something new.

If would like to suggest a topic or project for an upcoming post feel free to contact me.

Much Love,
~Joy

 

 

Create a free website or blog at WordPress.com.

Up ↑

%d bloggers like this: