Optimal width and height after image rotation

A while ago, a blog reader Fabien sent me some code (you can read it here. Thanks Fabien!). The PHP code is a modification of my image rotation code with some upgrades.

I was looking through his code (French variable names!) and was puzzled by the initial section. I believe he based his code on my code where the resulting image wasn’t clipped after rotation, meaning the whole image was still in the picture/bitmap (though rotated).

In that piece of code, I just used the diagonal length of the image (from top-left corner to bottom-right corner) as the final length and breadth of the resulting image. This gave the simplest resulting image dimension without doing complicated maths calculations (a square in this case).

However, what if you want to know the optimal width and height of the resulting image after rotation? Meaning the best-fit width and height that just manages to contain the resulting rotated image. For that, I need to tell you some basic trigonometry and geometry.

Image rotation, optimal width and height

Suppose you have a rectangle with L as the length and H as the height. It is rotated t angles. I’m not going to explain the maths behind it. It involves complementary angles, supplementary angles, rotation symmetry and trigonometry with sines and cosines. Convince yourself that the diagram is true.

So after rotating t angles, the optimal width is L * cos(t) + H * cos(90 – t)

The optimal height is L * sin(t) + H * sin(90 – t)

Short digression: You might notice that any lengths that lie parallel to the x-axis usually involve cosines, and lengths that lie parallel to the y-axis usually involve sines. It’s just the way trigonometry works.

Now, although the image rotation is carried out with respect to the image’s centre, rotating by the top-left corner will result in the same optimal width and height. Again, this is basic maths so you’ll just have to convince yourself it’s true (and that I don’t really want to explain it…).

But that’s if t is an acute angle. What about other angles?

Image rotation, optimal width and height

For those angles, we just need to calculate the acute angle based on the initial rotation angle. After that, just substitute that calculated acute angle into our formula above. I have absolute confidence in your ability to check which quadrant in the Cartesian coordinate system does your rotation angle lie in.

UPDATE: In case you are unable to view images, if your rotation angle is in the 2nd quadrant, the calculated angle is (180 – t). If in the 3rd quadrant, it’s (t – 180). And if in the 4th quadrant, it’s (360 – t).

In practice, you might still want to pad a couple of pixels around. But that should give you the smallest image dimension which can still contain your rotated image.

Announcing SpreadsheetLight version 1.1

After much researching and programming and suffering (and tea), I’m happy to announce that version 1.1 of SpreadsheetLight is up! SpreadsheetLight is a spreadsheet manipulation library based on Open XML.

I added some functionality for defined names and clearing out data from rows/columns/cells. You can also split worksheet panes now. Version 1 didn’t have split pane functionality because I couldn’t find a way to make it easy for the programmer. Well, I wrote a function that allows you to do it with a minimum of fuss.

But the main bulk of version 1.1 updates is the insert/delete rows/columns part. Say you want to insert 4 rows at the 3rd row. This means all the rows from the 3rd row (including the 3rd row) must be shifted downwards 4 rows. Every merged cell, cell formula, table and defined name must be accounted for.

Merged cells need to be enlarged or trimmed off as needed. Or just simply deleted if it’s entirely within the delete range.

Tables need to be updated so the cell references within are correctly adjusted. If it used to contain C3:F6, after inserting 4 rows, it has to be C7:F10.

Cell formulas and defined names are sort of related, with the former typically of a more complex form than the latter. Consider taking on something like this:

= A1 +LOG10 +”BCD32″ -SUM($H6:Sheet1!K$9) *LOG10($F$5) + BCD32 – SUM(F2:G3)

That has to become this:

= A1 +LOG14 +”BCD32″ -SUM($H10:Sheet1!K$13) *LOG10($F$9) + BCD36 – SUM(F2:G7)

Note the LOG10 part. The first instance is a cell reference. The second is the logarithm function, base 10, of the cell originally $F$5. Note also that the first instance of BCD32 is a literal string. Literal strings should not be changed, even if they contain a valid cell reference.

That part took me quite a while. Let’s just say I’m glad I’m fairly proficient in regular expressions…

The only thing I left out was pictures (aka worksheet drawings) for insert/delete rows/columns. To create similar behaviour to when you’re doing it in Excel requires more arcane coding…

So if you’re looking for a spreadsheet library that’s light-weight yet capable of heavy-weight functionality, with simple-to-use functions, then consider SpreadsheetLight. Or tell your boss.

I’ve also included a Platinum version, which includes the source code of SpreadsheetLight (licensed with the MIT license). So if you want to know how I accomplished all that magic, consider the Platinum version then. Lots of comments to make the hairy parts less hairy…

Special drawing rights

No, it has nothing to do with paintings. And it’s “special” in the sense of “unique” as in “His appearance? Let’s just say he has a … unique look.”, or “different” as in “Oh no we didn’t unfriend each other. We just had … different opinions.”.

It’s actually a form of currency. Ok, no, a claim to currency. For example, an American dollar is USD 1, and a Singapore dollar is SGD 1. In this case, it’s SDR 1.

At first, I thought it’s a special case of Singapore dollar. You know, Singapore DollaR (I really thought some marketing staff or programmer made a mistake of currency abbreviations). I encountered it when I maintained an accounting software back when I was at a telecommunications company. The currencies supported were USD, SGD, AUD (the company had a wholly owned subsidiary in Australia) and SDR.

I remembered asking my supervisor why we had accounts with outstanding amounts in SDR. The amounts hadn’t been paid in years. You’d think the billing department would’ve wanted to settle accounts so we could all move on with our lives. It seemed obvious the account owners had no intention of ever paying the company in SDR (or whatever value of SDR in appropriate currencies then. Or ever).

So SDRs are a basket of currencies, currently of euros, Japanese yen, pound sterlings and the US dollar. It works something like a world currency, but not quite. It’s not widely used because (from Wikipedia):

One reason SDRs may not see much use as foreign exchange reserve assets is that they must be exchanged into a currency before use.

Meaning something like you’ve got to exchange 50000 Starbuck points to $5 before you can use it to buy a cappuccino.

This is due in part to the fact private parties do not hold SDRs, they are only used and held by IMF member countries, the IMF itself, and a select few organizations licensed to do so by the IMF.

Meaning normal people like you and I don’t even know about SDRs in the first place.

While all that is very interesting, I have a more important question. Why did the people who wanted the accounting software allow SDR in the first place? Didn’t they know SDRs are very illiquid (you can’t just use it as cash)? Few people, ok, scratch that, since individuals probably don’t have access to SDRs. Few organisations and companies would be using SDR as a form of currency. Why was SDR supported in the first place?

The people who wanted the software might be at fault. They might just have wanted to support that one customer who wanted the option to pay in SDR. The software developers were also at fault. They should have advised the software commissioners (that’s a new term) to remove SDR as a support option.

An accounting software used for tens of thousands of customers, and an option was built into the software to support a few of those customers. This kind of decision makes for all sorts of bugs and maintenance problems, so I really hope a lot of thought went into this.

If we programmers simply create software according to the specs laid down by users, then you can see why users don’t think we’re important. They can just outsource to some exotic place in Asia where programmers are hired on the dime.

We need to think. We need to analyse. We need to question. That’s the value we add as creative professionals, software developers, programmers and what-have-you.

Prepaid Postpaid Convergence

What’s one of the most important concerns of any business? Getting paid.

What’s the next most important concern of any business? Getting paid on time.

There’s this concept called the “prepaid postpaid convergence”, which hailed from the telecommunications industry (where I spent the majority of my professional life in). You’re probably on a postpaid mobile phone plan, where you’re charged for what you used in the previous month. Or you might be on a prepaid plan, where you dump a bunch of cash into your plan/phone/card/thingy and you can text and call until your money runs out.

This is a particular problem in the telecommunications industry because billing customers is challenging. It’s difficult to bill in one generic way to handle both prepaid and postpaid charges.

Think of it this way. I could dump $50 into my prepaid card and not use my phone for 6 months. But for 6 months, the company has to keep track of that $50. The worst thing is, depending on the billing requirements and laws in the country, the company may not include that $50 as “revenue earned”. The company can only include any monetary amount after I used some of that prepaid cash. Say I used $11.25, then the company “earned” $11.25 (even though I’ve paid $50 upfront).

Prepaid billed amounts are “future money”. Postpaid billed amounts are “past money”.

There are 3 general payment modes:

  • You used a product/service but haven’t paid yet.
  • You pay at the point of usage.
  • You pay first, but haven’t used the product/service.

The timing is important. For the purposes of this article, we won’t be strict about the point of usage and point of payment. In some restaurants, you get to eat first before you pay. I will consider that as “payment at the point of usage”, unless you intend to get a free meal and bolt the moment you get a chance to.

So why is this important to you?

The business models are different

Let’s consider the Apple App Store. You find an app you like. You purchase it. 2 business models come into play.

First, Apple charges you immediately on your credit card. You pay immediately upon purchasing the app. Apple gets the $0.99 from the credit card company, and can report that $0.99 on their profit/revenue report.

Second, the credit card company bills you the next month, including that $0.99 app you bought. You’ve enjoyed using the app first, before actually paying for it.

Apple and the credit card company have 2 different business models, even though the “product” is the same. (technically, the credit card company isn’t selling the app, they’re selling you the service of having a credit card, but to you it’s the same thing)

Web hosting companies use the prepaid model (that I know of). They may charge you for 3 years worth of hosting your website. You pay for 3 years first, then you get to have your website hosted. Even if you decide to cancel after 6 months, and you might get a 2.5 year refund back (depending on whether the web hosting company has this policy. Please check), but you still had to have paid for 3 years upfront.

I’m assuming you’re a developer. The trend is that the Internet is going to be a big thing. Let’s say you’re a startup founder. Choose your business model wisely, because it’s going to be hard to change it.

The Amazon S3 service lets you store stuff. You pay for what you use (the more data transfers made, the more you pay). This is postpaid.

iStockphoto lets you buy credits which you can then use to buy images. You pay first (in a large lump sum) then you buy images with the credits (that were bought with cash). This is prepaid.

Prepaid has this annoying thing…

It’s called “keeping track”.

Let’s say a text message costs $0.10, and you bought a prepaid card for $10. That means you can make 100 text messages.

A postpaid customer will be billed $0.70 for the 7 messages she sent in the last month. She will also be billed $1.00 for the 10 messages she sent this month (in the next month).

You on the other hand, won’t be billed. Because you already paid $10. Theoretically, you could hold onto that $10 value in your phone card for eternity. Depending on the billing requirements, the telecommunications company might include that $10 as revenue. But since you haven’t actually sent any text messages (or phone calls), it’s kinda shady since the company hasn’t rendered any services to you yet they “earned” $10 for nothing. In any case, you’ve paid $10 for nothing (since you didn’t use it).

The worst part is the telecommunications company has to store that $10 as a line entry in a database somewhere. And without any corresponding entries to “deduct” that amount. That database entry will stay there forever without resolution. The telecommunications company now officially hates you.

This is why most prepaid items have an expiry date, even if they’re virtual products and won’t decay over time. For example, iStockphoto credits last 1 year. Vouchers from movie theatres, supermarkets, restaurants also typically have a 1 year expiry date. They’re vouchers, it’s not like they’re going to wither away. But companies need to keep track of them.

When the prepaid items expire, the companies can then include the value of the items into revenue, because the customer at that point can no longer use the item, hence it’s taken as the customer had already used it.

Imagine you have to write a program and design a database to support the prepaid billing structure. Your program has to keep track of anything the prepaid customer does, and deduct the corresponding amount from the stored value in a database. Every single text message and phone call the customer makes, the program has to go check if there’s enough in customer’s stored value. Technically, there’s a switchboard that bars the customer from making a text message or phone call before the text message or phone call can be made (that’s the hardware check). Then your program breathes a sigh of relief when the stored value is gone or expired… And then the customer tops up his stored value with $50. Your program grows an unreasonable hatred for this customer.

Final thoughts

A postpaid model requires you to trust that the customer will pay you. A prepaid model lets you get money first, but keeping track might pose a small challenge.

With the Internet being real-time, the better model for online products and services is the “pay immediately” model. You don’t have to keep track of inventory (if at all) and you get the money immediately to your bottom line.

I know there’s also the subscription model. But do you charge customers for the month they haven’t yet used, or for the month they’ve already used?

I’m pretty sure I left something out, or haven’t explained something properly, so leave a comment or send me an email.

Image rotation with bilinear interpolation and alpha progressive borders

So a blog reader, Fabien Auréjac, emailed me an improvement over the code I posted on image rotation. Here’s the one with bilinear interpolation, and here’s the one with bilinear interpolation and no clipping.

Fabien translated the core of my code into PHP. The improvement was on assigning alpha values to the edge pixels after rotation. Edge pixels are pixels beside the “blank” pixels (I used black in my code, for instance). The alpha values mean the edge pixels are “softer” and thus the resulting image looks smoother.

I suppose if you really want to, you could also “dumb down” the values of the red, green and blue colour components for more softening (in addition to the alpha component). I say “dumb down” because the blank pixels I used are black (meaning zero for the RGB values). You’re free to go ahead and do more interpolation.

Fabien has given permission for me to post the code here. I’ll leave it as an exercise for you to translate to your programming language.

$distOmbre=3;
$flouOmbre=4;
$angleRot=60;
$img=imagecreatefromjpeg("media/diapo-Chinon.jpg");
$size=getimagesize("media/diapo-Chinon.jpg");
$LsupH=($size[0]>$size[1])?1:0;
$angleBool=(int)($angleRot/90)%2==0?0:1;
if (($angleBool+$LsupH)%2==0) {
	$largeur=round(abs($size[0]*sin($angleRot%90*pi()/180))+abs($size[1]*sin((90-$angleRot%90)*pi()/180)));
	$hauteur=round(abs($size[0]*cos($angleRot%90*pi()/180))+abs($size[1]*cos((90-$angleRot%90)*pi()/180)));
} else {
	$largeur=round(abs($size[0]*cos($angleRot%90*pi()/180))+abs($size[1]*cos((90-$angleRot%90)*pi()/180)));
	$hauteur=round(abs($size[0]*sin($angleRot%90*pi()/180))+abs($size[1]*sin((90-$angleRot%90)*pi()/180)));
}
$largeur+=$distOmbre+$flouOmbre*2;
$hauteur+=$distOmbre+$flouOmbre*2;
$angleRot*=pi()/180;
$imgRot=imagecreatetruecolor($largeur, $hauteur);
imagealphablending($imgRot, true);
imageantialias($imgRot, true);
for ($i=0; $i<$hauteur; $i++) {
	for ($j=0; $j<$largeur; $j++) {
		// convert raster to Cartesian
        $x = $j - $largeur*0.5;
        $y = $hauteur*0.5 - $i;

        // convert Cartesian to polar
        $fDistance = sqrt($x * $x + $y * $y);
   	 	$fPolarAngle = atan2($y, $x);

        // the crucial rotation part
        // "reverse" rotate, so minus instead of plus
        $fPolarAngle -= $angleRot;
		 // convert polar to Cartesian
        $fTrueX = $fDistance * cos($fPolarAngle);
        $fTrueY = $fDistance * sin($fPolarAngle);

        // convert Cartesian to raster
        $fTrueX = $fTrueX + $size[0]*0.5;
        $fTrueY = $size[1]*0.5 - $fTrueY;

        $iFloorX = (int)(floor($fTrueX));
        $iFloorY = (int)(floor($fTrueY));
        $iCeilingX = (int)(ceil($fTrueX));
        $iCeilingY = (int)(ceil($fTrueY));
        //echo $fTrueX." ".$fTrueY." ".$iFloorX." ".$iCeilingX." ".$iFloorY." ".$iCeilingY."<br>";
		if ($iFloorX >= 0 && $iCeilingX >= 0 && $iFloorX < $size[0] && $iCeilingX < $size[0] && $iFloorY >= 0 && $iCeilingY >= 0 && $iFloorY < $size[1] && $iCeilingY < $size[1]) {
			$fDeltaX = $fTrueX - $iFloorX;
			$fDeltaY = $fTrueY - $iFloorY;
			$clrTopLeft = imagecolorat($img, $iFloorX, $iFloorY);
			$colorsTopLeft = imagecolorsforindex($img, $clrTopLeft);
			$clrTopRight = imagecolorat($img, $iCeilingX, $iFloorY);
			$colorsTopRight = imagecolorsforindex($img, $clrTopRight);
			$clrBottomLeft = imagecolorat($img, $iFloorX, $iCeilingY);
			$colorsBottomLeft = imagecolorsforindex($img, $clrBottomLeft);
			$clrBottomRight = imagecolorat($img, $iCeilingX, $iCeilingY);
			$colorsBottomRight = imagecolorsforindex($img, $clrBottomRight);
			// linearly interpolate horizontally between top neighbours
			$fTopRed = (1 - $fDeltaX) * $colorsTopLeft['red'] + $fDeltaX * $colorsTopRight['red'];
			$fTopGreen = (1 - $fDeltaX) * $colorsTopLeft['green'] + $fDeltaX * $colorsTopRight['green'];
			$fTopBlue = (1 - $fDeltaX) * $colorsTopLeft['blue'] + $fDeltaX * $colorsTopRight['blue'];
			// linearly interpolate horizontally between bottom neighbours
			$fBottomRed = (1 - $fDeltaX) * $colorsBottomLeft['red'] + $fDeltaX * $colorsBottomRight['red'];
			$fBottomGreen = (1 - $fDeltaX) * $colorsBottomLeft['green'] + $fDeltaX * $colorsBottomRight['green'];
			$fBottomBlue = (1 - $fDeltaX) * $colorsBottomLeft['blue'] + $fDeltaX * $colorsBottomRight['blue'];
			// linearly interpolate vertically between top and bottom interpolated results
			$iRed = (int)(round((1 - $fDeltaY) * $fTopRed + $fDeltaY * $fBottomRed));
			$iGreen = (int)(round((1 - $fDeltaY) * $fTopGreen + $fDeltaY * $fBottomGreen));
			$iBlue = (int)(round((1 - $fDeltaY) * $fTopBlue + $fDeltaY * $fBottomBlue));
			// make sure colour values are valid
			if ($iRed < 0) $iRed = 0;
			if ($iRed > 255) $iRed = 255;
			if ($iGreen < 0) $iGreen = 0;
			if ($iGreen > 255) $iGreen = 255;
			if ($iBlue < 0) $iBlue = 0;
			if ($iBlue > 255) $iBlue = 255;
			if ($iFloorX > 0 && $iCeilingX > 0 && $iFloorX < $size[0]-1 && $iCeilingX < $size[0]-1 && $iFloorY > 0 && $iCeilingY > 0 && $iFloorY < $size[1]-1 && $iCeilingY < $size[1]-1) {
				$colorallocation=imagecolorallocate($imgRot, $iRed, $iGreen, $iBlue);
				imagesetpixel($imgRot, $j, $i, $colorallocation);
			} else if ($iFloorX == 0 && $iFloorY >= 0 && $iCeilingY >= 0 && $iFloorY < $size[1] && $iCeilingY < $size[1]) {//left
				$alpha=round((1-abs($fDeltaX))*127);
				$colorallocation=imagecolorallocatealpha($imgRot, $iRed, $iGreen, $iBlue, $alpha);
				imagesetpixel($imgRot, $j, $i, $colorallocation);
			} else if ($iFloorX >= 0 && $iCeilingX >= 0 && $iFloorX < $size[0] && $iCeilingX < $size[0] && $iFloorY == 0) {//top
				$alpha=round((1-abs($fDeltaY))*127);
				$colorallocation=imagecolorallocatealpha($imgRot, $iRed, $iGreen, $iBlue, $alpha);
				imagesetpixel($imgRot, $j, $i, $colorallocation);
			} else if ($iCeilingX == $size[0]-1 && $iFloorY >= 0 && $iCeilingY >= 0 && $iFloorY < $size[1] && $iCeilingY < $size[1]) {//right
				$alpha=round(abs($fDeltaX)*127);
				$colorallocation=imagecolorallocatealpha($imgRot, $iRed, $iGreen, $iBlue, $alpha);
				imagesetpixel($imgRot, $j, $i, $colorallocation);
			} else if ($iFloorX >= 0 && $iCeilingX >= 0 && $iFloorX < $size[0] && $iCeilingX < $size[0] && $iCeilingY == $size[1]-1) {//bottom
				$alpha=round(abs($fDeltaY)*127);
				$colorallocation=imagecolorallocatealpha($imgRot, $iRed, $iGreen, $iBlue, $alpha);
				imagesetpixel($imgRot, $j, $i, $colorallocation);
			}
		}
	}
}

Fabien is French (I think), which is why you get variable names such as distOmbre (shadow distance?), flouOmbre (fuzzy shadow?), largeur (width), hauteur (height). And this one took me a bit more time to translate… LsupH is probably “width greater than height?”. The “L” probably refers to “largeur”, and “H” refers to “hauteur”.

Reading international programming code is fun. *smile*

There’s also an interesting piece of code:

$size=getimagesize("media/diapo-Chinon.jpg");
$LsupH=($size[0]>$size[1])?1:0;
$angleBool=(int)($angleRot/90)%2==0?0:1;
if (($angleBool+$LsupH)%2==0) {
	$largeur=round(abs($size[0]*sin($angleRot%90*pi()/180))+abs($size[1]*sin((90-$angleRot%90)*pi()/180)));
	$hauteur=round(abs($size[0]*cos($angleRot%90*pi()/180))+abs($size[1]*cos((90-$angleRot%90)*pi()/180)));
} else {
	$largeur=round(abs($size[0]*cos($angleRot%90*pi()/180))+abs($size[1]*cos((90-$angleRot%90)*pi()/180)));
	$hauteur=round(abs($size[0]*sin($angleRot%90*pi()/180))+abs($size[1]*sin((90-$angleRot%90)*pi()/180)));
}

So here’s your mission, should you choose to accept it (I recently watched Mission Impossible…). What is Fabien trying to accomplish in that section of code? Hint: it has something to do with getting a “nice” resulting image width and height.

I’ll tell you a more “elegant” alternative to that code section. But it’ll involve some mathematics. And drawings. Prepare for poorly drawn diagrams…

Singularity Magazine February 2012

Singularity Magazine February 2012

In this issue, we talk about what it means to be an artist. Hint: it has to do with emotional labour.

Download the February issue (about 1.8 MB).

Subscribe to the magazine for free.

Follow me on Twitter or on YouTube.

Students don’t graduate because…

… because they’ve lost hope.

They’ve lost hope that:

  • they can fulfill degree requirements (some subjects are tough!)
  • they can actually graduate
  • (more importantly) they can graduate in a shorter time so they pay less tuition fees
  • they can get a good job with that degree

And so they give up. They’ve lost hope. They don’t believe anymore.

A degree can still be useful. But the current educational and economic outlook doesn’t exactly inspire a lot of confidence in the immediate use of a degree.

Educational institutes mostly teach students towards knowledge that’s known. I mean, your professor won’t set a question that he can’t answer, right? The world we now live in rewards those who solve the unknown, possibly even seeking questions that weren’t ever asked.

Teachers need to start teaching students to face the unknowable. They need to instill hope in the next generation.

Congratulations on becoming rich!

In which I teach you 3 Chinese New Year greetings. Also, this was unscripted (mostly). I also can’t do one-take videos…

Belief is everything

You might be surprised that I’ve learnt many life lessons from books. Specifically, fantasy fiction. Today, I’m going to tell you one of them.

Warning: There will be spoilers, even though I’ve summarised a fair chunk of the book. The following comes from the book Sword of Shannara by Terry Brooks. If you don’t want spoilers, you should stop reading… now.

Gifted wrongly

I will be summarising extensively. There was this great druid. There was also this great evil (isn’t there always…). With some thought, the druid figured out how to defeat the great evil, and he forged a sword with which to do battle.

The druid decided to give the sword to another. I can’t remember why, whether out of sacrifice (didn’t want to get all the credit), or that he couldn’t fight anymore (old age). I’m sure a Shannara fan will happily correct me in the comments…

But the druid made a fatal mistake. He gifted the magic sword to the king of the elven people.

The king himself wasn’t the mistake. The position of kingship was.

The king went to do battle with the great evil and won. But a quiet cloak of belief had already settled onto the elven people. That the magic sword will only work for the king.

As a consequence of that belief, the elven people also believed that only the heirs of the king could successfully wield the great magic sword. This was wrong. The magic sword would work for any elf with the right purpose of heart. The druid had not forged any special condition into the sword.

But with mass belief, the unintended condition wrapped itself together with the magic. And eventually, it became true. Only heirs from the line of the original king could wield the magic sword.

Belief is everything

And that was one of my first life lessons. Belief is everything. Beliefs are powerful.

If you don’t believe that something will work, then it probably won’t.

If you believe you can fashion a database to support the technical aspects of your program, then yes, you probably will come up with a design to suit your needs.

Disbelief closes off possibilities.

A corollary of that is about mass belief. If many people believe in something, then that something has a lot of power. Religion, superstitions, doomsday announcements, electromagnetic waves. I’m not talking about proofs and so on, particularly with science. I’m talking purely about beliefs. Say some scientific experiment can be replicated with the same results. That convinces people of the validity of the theory behind the experiment, and thus belief in that theory. It’s still belief.

This gave me confidence and understanding of certain human endeavors. Why do some people succeed at businesses? Many people believe that starting your own business is risky. And they’d be right. And those people who succeed? Those people believe they can succeed in making their business work, overriding the disbelief from the people around them.

Belief is everything.

It’s how I’ve upheld my own beliefs in the face of every belief thrown at me from everyone around me. My family. My friends. Even strangers.

Of course, you don’t have to listen to me. “Everything” is an absolute term. But that means you do believe in something, just not my version.

Just in case you’re interested in what the magic sword can do, it does one thing only. It reveals the truth. That great evil grew powerful because of the fear from the people. Yes, the belief that the great evil is indeed very powerful and can do great harm, made the evil even more powerful. The magic sword unveiled the truth, that the great evil was simply a malevolent shadow of a man.

Politicians, scammers and liars of all sorts would fear the Sword of Shannara indeed.

Quadratic Bezier curve control point calculation demo

MacGile made a video to demonstrate the calculation of control points of a quadratic Bezier curve. The algorithm is based on what I wrote here.

That looks awesome! Thanks MacGile!