tag:blogger.com,1999:blog-39441748270640122982024-03-05T23:18:10.153+01:00The Bugfree Blog ;-)A blog about anything related to engineering.Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.comBlogger86125tag:blogger.com,1999:blog-3944174827064012298.post-48068910462999500812021-12-08T16:37:00.001+01:002021-12-08T16:37:13.620+01:00Raspberry OS Bullseye and Cross Toolchain for Linux and Mac OS 10.2.1<p>Raspberry OS based on Debian bullseye was recently published. The compiler provided with this new version was updated to 10.2.1. As usual, I need to cross build many large projects for the platform, and I had problems in the past with cross toolchains not precisely matching the versions in the target sysroot. I therefore typically prefer to build my own toolchains based on the precise versions of the packages provided with the OS. These are the toolchains I’m using for the past Raspberry Pi systems:</p><p></p><ul style="text-align: left;"><li>Cross toolchain GCC 6.3.0 for <b>Stretch</b>: <a href="https://bugfreeblog.duckdns.org/2017/11/raspbian-stretch-and-cross-toolchain.html" target="_blank">here</a>.</li><li>Cross toolchain GCC 8.3.0 for <b>Buster</b>: <a href="https://bugfreeblog.duckdns.org/2019/09/raspbian-buster-gcc.html" target="_blank">here</a>.</li></ul><p></p><p>For Bullseye, these are the new toolchains I’m currently using:</p><p></p><ul style="text-align: left;"><li>Cross toolchain GCC 10.2.1 for Linux hosts for <b>Bullseye</b>: <a href="https://polr.luc4.duckdns.org/rpi-gcc-10_2_1" target="_blank">here</a>.</li><li>Cross toolchain GCC 10.2.1 for Mac OS hosts for <b>Bullseye</b>: <a href="https://polr.luc4.duckdns.org/rpi-gcc-10_2_1-macos" target="_blank">here</a>.</li></ul><p></p><p>As usual, place the toolchain in /opt/rpi, and the sysroot in /opt/rpi/sysroot. I tested these toolchains to build Qt 6.2.1 and everything seems to be fine so far.</p><p>Have fun! Bye 😉 </p>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-60639345079836668252021-10-20T19:29:00.005+02:002021-10-20T19:29:31.788+02:00Hardware Accelerated Video with Qt 6 on the Raspberry Pi<p style="text-align: left;">Getting hardware acceleration into Qt eglfs is tricky. Doing so on a Raspberry Pi is, unfortunately, still tricky after many years. Qt claimed to have reimplemented the Qt Multimedia module entirely, and one of their target was getting hardware acceleration where possibile. So, I thought I could start with a quick look.</p><h3 style="text-align: left;">Qt 5</h3><p style="text-align: left;">Since Raspberry Pi was born, I had to solve the problem of hardware accelerated video in Qt. At the beginning, I wrote POT (PiOmxTextures) to solve this problem: <a href="https://github.com/carlonluca/pot">https://github.com/carlonluca/pot</a>. It used OpenMAX to stream decoded video into an OpenGL texture, which was then showed through a custom backend of Qt Multimedia in Qt 5. This approach worked fine, but won’t work on Pi 4/Qt 6. On the other hand, there is another component in the same repo, that includes a custom Qt Quick item to render video through omxplayer. This is the most performant approach, but has its limitations.</p><h3 style="text-align: left;">Qt Multimedia</h3><p style="text-align: left;">I quickly tested Qt Multimedia in Qt 6 on the rpi. My build from <a href="/2021/09/qt-6-on-raspberry-pi-on-eglfs.html" target="_blank">this article</a> should support gstreamer. All I got was a a warning on the console. I didn’t investigate further. Maybe I’ll spend more time on this in the future.</p><h3 style="text-align: left;">POTVL</h3><p style="text-align: left;">As the classical POT is no more usable on Raspberry Pi 4, I started to have a look at POTVL, which is very simple to port to Qt 6. With a small patch, it is possible to build it. You’ll find updates on the repo.</p><h3 style="text-align: left;">Demo</h3><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/cvlTDX3V54w" width="320" youtube-src-id="cvlTDX3V54w"></iframe></div><p style="clear: both; text-align: left;">The video is a 1080p video. As you can see, the framerate is acceptable up to a certain weight of the graphics. It seems that Qt 6 OpenGL backend still is a bit less performant than Qt 5 in this specific demo, as you can see from this test from a previous article:</p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/5fPRT4j_VJE" width="320" youtube-src-id="5fPRT4j_VJE"></iframe></div><br /><div class="separator" style="clear: both; text-align: left;"><p style="clear: both;">so the result may even improve in the future.<br />The benchmark app can be found here: <a href="https://github.com/carlonluca/Fall">https://github.com/carlonluca/Fall</a>.<br />Unfortunately POTVL is still not future proof, but it is the simplest and most efficient element to port to Qt 6. I may try something better in the near future.<br />Have fun! Bye 😉</p></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-75393561084258441362021-10-15T19:49:00.003+02:002021-10-15T19:49:52.184+02:00Isogeometric Analysis: Knot Insertion for NURBS<!-- wp:heading -->
<h2>Introduction</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>In the classical Finite Element Method (FEM) the domain of the problem is approximated by defining a mesh and basis functions over its elements. More elements for the mesh means more basis functions and therefore larger space where approximated solutions can be found. The procedure of increasing the number of elements in the mesh is known as <em>h-refinement</em>. In Isogeometric Analysis (IGA), no mesh is required as the basis functions used to define the domain are the same basis functions used to define the approximate solution. Nevertheless, in IGA, the solution is still a combination of basis functions, so increasing the number of basis functions is still needed to implement some kind of h-refinement. A good way to do this is through knot insertion into the NURBS. This post also presents demo written in Octave and TypeScript.</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>You can find the full source code for the algorithms and all the examples in <a href="https://github.com/carlonluca/isogeometric-analysis" target="_blank" rel="noreferrer noopener">this GitHub repo</a>.</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2>Problem of Knot Insertion</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Given the general form of a NURBS curve as described <a href="/2021/07/iga-nurbs.html" target="_blank" rel="noreferrer noopener">here</a>:</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>$$\boldsymbol{C}^{w}\left(\xi\right)=\sum_{i=0}^{n}N^{p}_{i}\left(\xi\right)\boldsymbol{P}_i^w$$</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>on the knot vector:</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>$$\Xi=\left[\xi_0,...,\xi_m\right]$$</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>knot insertion is the problem of adding the knot $\bar{\xi}\in\left[\xi_k,\xi_{k+1}\right)$ in the knot vector $\Xi$, so that the following still stands:</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>$$\bar{\boldsymbol{C}}^w\left(\xi\right)=\sum_{i=0}^{n+1}N_{i}^{p}\left(\xi\right)\bar{\boldsymbol{P}}^{w}_{i}=\boldsymbol{C}^w\left(\xi\right),\forall\xi\in\left[\xi_0,\xi_{m+1}\right]$$</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>on the knot vector:</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>$$\Xi=\left[\xi_0,...,\xi_{m+1}\right]$$</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>where $\bar{\boldsymbol{P}}_i^w$ are the control points of the new curve in the projective space.</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>Knot insertion is supposed to keep the curve unaltered by adding and modifying control points and knots.</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2>Solutions</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>The problem can then be solved by finding the $n+1$ values $\bar{\boldsymbol{P}}^w_i$, which can be done solving the linear system in $n+2$ equations:</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>$$\sum_{i=0}^{n+1}N_{i}^{p}\left(\xi\right)\bar{\boldsymbol{P}}^{w}_{i}=\sum_{i=0}^{n}N^{p}_{i}\left(\xi\right)\boldsymbol{P}^w_{i},\forall\xi\in\left\{\xi_0,...,\xi_{n+1}\right\}$$</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>There is also a simpler way to insert the knots. It can be shown that:</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>$$\displaylines{\bar{\boldsymbol{P}}_{i}^{w}=\alpha_{i}\boldsymbol{P}_{i}^{w}+\left(1-\alpha_{i}\right)\boldsymbol{P}_{i-1}^{w},\\<br>\alpha_{i}=\left\{ \begin{array}{ll} 1, & i\leq k-p\\ \dfrac{\bar{\xi}-\xi_{i}}{\xi_{i+p}-\xi_{i}}, & k-p+1\leq i\leq k\\ 0, & i\geq k+1 \end{array}\right.}$$</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>This is the technique used in all the implementations in the repo.</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2>Octave Implementation</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>The Octave implementation includes the <a href="https://github.com/carlonluca/isogeometric-analysis/blob/master/4.5/computeKnotInsertion.m#L38" target="_blank" rel="noreferrer noopener">computeKnotInsertion</a> script that takes a NURBS as input, together with the knot value to add and returns a new knot vector and control points. This is an example of insertion into a circle:</p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://github.com/carlonluca/isogeometric-analysis/raw/master/4.5/iga_knot_insertion_circle.svg.png" alt="Knot insertion on a circle with related NURBS basis functions."/></figure>
<!-- /wp:image -->
<!-- wp:paragraph -->
<p>The <a href="https://github.com/carlonluca/isogeometric-analysis/blob/master/4.5/computeSurfKnotInsertion.m#L22" target="_blank" rel="noreferrer noopener">computeSurfKnotInsertion</a> script computes knot insertion for NURBS surfaces instead. With the script, knots can be added to both dimensions. An example is shown below:</p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://github.com/carlonluca/isogeometric-analysis/raw/master/4.5/iga_knot_insertion_plate_hole.svg.png" alt="Knot insertion on a plate with a hole computed in Octave."/></figure>
<!-- /wp:image -->
<!-- wp:heading -->
<h2>TypeScript Implementation</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>The TypeScript implementation includes a method named insertKnot in the <a href="https://github.com/carlonluca/isogeometric-analysis/blob/master/ts/src/nurbs/nurbs.ts#L30" target="_blank" rel="noreferrer noopener">NurbsCurve</a> class. That method allows to insert multiple knots into the vector, returning a new NurbsCurve, identical to the first, but with a different knot vector and different control points.</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>With a few lines of code:</p>
<!-- /wp:paragraph -->
<!-- wp:enlighter/codeblock {"language":"typescript"} -->
<pre class="EnlighterJSRAW" data-enlighter-language="typescript" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">let circle = new NurbsCirle()
drawNurbsCurve(circle.controlPoints, circle.knotVector, circle.weights, 2, false, true, plot1, null, true, "Knot Insertion 1")
circle.insertKnot(0.6, 6, 0, 1)
drawNurbsCurve(circle.controlPoints, circle.knotVector, circle.weights, 2, false, true, plot2, null, true, "Knot Insertion 2")
circle.insertKnot(0.3, 4, 0, 1)
drawNurbsCurve(circle.controlPoints, circle.knotVector, circle.weights, 2, false, true, plot3, null, true, "Knot Insertion 3")
circle.insertKnot(0.2, 2, 0, 1)
drawNurbsCurve(circle.controlPoints, circle.knotVector, circle.weights, 2, false, true, plot4, null, true, "Knot Insertion 4")</pre>
<!-- /wp:enlighter/codeblock -->
<!-- wp:paragraph -->
<p>you can draw this result:</p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://github.com/carlonluca/isogeometric-analysis/blob/master/ts/ki_curve.webp?raw=true" alt="Knot insertion on a circle computed in TypeScript."/><figcaption><a href="https://carlonluca.github.io/isogeometric-analysis/nurbs_knot_insertion_curve.html" target="_blank" rel="noreferrer noopener">Live demo</a></figcaption></figure>
<!-- /wp:image -->
<!-- wp:paragraph -->
<p>The NurbsSurf class includes the methods insertKnotXi and insertKnotEta to insert knots in the two dimensions of the parametric space and returns the new object NurbsSurf. This is the result of the algorithm applied to a plate:</p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://github.com/carlonluca/isogeometric-analysis/raw/master/ts/ki_plate.webp" alt="Knot insertion on a plate with a hole computed in TypeScript."/><figcaption><a href="https://carlonluca.github.io/isogeometric-analysis/nurbs_knot_insertion_plate.html" target="_blank" rel="noreferrer noopener">Live demo</a></figcaption></figure>
<!-- /wp:image -->
<!-- wp:paragraph -->
<p>and this is the result on a toroid (in this case knots were not inserted in the entire vector uniformly, but only in a section):</p>
<!-- /wp:paragraph -->
<!-- wp:image {"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://github.com/carlonluca/isogeometric-analysis/raw/master/ts/ki_toroid.webp" alt="Knot insertion on a toroid computed in TypeScript."/><figcaption><a href="https://carlonluca.github.io/isogeometric-analysis/nurbs_knot_insertion_toroid.html" target="_blank" rel="noreferrer noopener">Live demo</a></figcaption></figure>
<!-- /wp:image -->
<!-- wp:paragraph -->
<p>As expected, after each insertion, the NURBS is unaltered. This can also be seen by running the unit tests provided in the repo. For example, one unit test includes this code:</p>
<!-- /wp:paragraph -->
<!-- wp:enlighter/codeblock {"language":"typescript"} -->
<p><font class="sourcecode">
function testNurbs(n1: NurbsSurf, n2: NurbsSurf) {
for (let xi = 0; xi <= 1; xi += 0.01)
for (let eta = 0; eta <= 1; eta += 0.01)
assert(approxEqualPoints(n1.evaluate(xi, eta), n2.evaluate(xi, eta)))
}
[...]
measure("surf_knot_insertion_xi", () => {
let n1 = new NurbsPlateHole()
let n2 = new NurbsPlateHole()
for (let i = 0.1; i <= 1; i += 0.9) {
if (n2.Xi[i] != i) {
let k = BsplineCurve.findSpan(n2.Xi, i, n2.p, n2.controlPoints.length - 1)
testNurbs(n1, n2.insertKnotsXi(i, k, 0, 1))
}
}
})</font></p>
<!-- /wp:enlighter/codeblock -->
<!-- wp:paragraph -->
<p>Bye! ;-)</p>
<!-- /wp:paragraph -->Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-25939909624966581112021-09-25T11:36:00.006+02:002021-10-10T12:18:31.781+02:00Qt 6 on the Raspberry Pi on eglfs<p style="text-align: center;"><a href="https://bugfreeblog.duckdns.org/2021/09/qt-6-on-raspberry-pi-on-eglfs.html">Read this article on WordPress on a Pi! :-)</a></p><p>It has been some time since Qt 6 was released. Now that Qt 6.2 is almost out, I guess it is time to have a look at it.</p><h2 style="text-align: left;">Building Qt 6</h2><p>Qt 6 moved from qmake to <a href="https://cmake.org/" target="_blank">cmake</a>. This makes a difference when trying to build it and cross-build it. Instructions on how to build are already available online from many sources, so I won’t repeat the theory here. I just want to note a few key points.</p><h4 style="text-align: left;">Configuration</h4><p>I configured this build in the simplest form. To start, I want to use eglfs on OpenGL ES.</p><h4 style="text-align: left;">Toolchain</h4><p>Building Qt requires a toolchain for building on the host and a toolchain to build for the target (the Raspberry Pi in this case). The toolchain from the host is typically provided by your distro (I used Manjaro in this case), while the toolchain to cross-build for the Raspberry Pi is officially provided <a href="https://github.com/raspberrypi/tools/tree/master/arm-bcm2708" target="_blank">here</a>. In the past years I had a lot of weird problems building with those toolchains, so I started to create my own. Never had any problem anymore. Here you can find the toolchains:</p><p></p><ul style="text-align: left;"><li>Raspberry OS Stretch: <a href="https://bugfreeblog.duckdns.org/2017/11/23/raspbian-stretch-and-cross-toolchain-for-linux-and-mac-os/" target="_blank">here</a>;</li><li>Raspberry OS Buster: <a href="https://bugfreeblog.duckdns.org/2019/09/09/raspbian-buster-and-cross-toolchain-for-linux-and-mac-os-8-3-0/" target="_blank">here</a>.</li></ul><p></p><p style="text-align: left;">Please note that those toolchains are not always able to target every arch. The one for Buster is the one I used in my build, and the target arch is armv8-a.</p><h4 style="text-align: left;">Dependencies</h4><p style="text-align: left;">Dependencies are already listed elsewhere. I would only like to note one thing here: I had problems linking because of a missing symbol: qt_resourceFeatureZstd. According to the sources, it seems that resources are compiled by the rcc tool. My guess is that the host tools use zstd by default to compress when available, but this is a problem when zstd is available on the host and not available on the target. Therefore, I suspect you have to decide if you want zstd support or not before building Qt 6 for the host, and be coherent with the build for the target. I decided to add zstd.</p><h4 style="text-align: left;">Build Errors</h4><p style="text-align: left;">I had a few build errors building Qt 6.2 beta3. Nothing particularly relevant, but I had to apply a few changes. I did not keep track of those changes, they were all trivial.</p><h3 style="text-align: left;">Build Qt Test App</h3><p style="text-align: left;">Once the Qt builds are ready, it is time to run. For the moment, I only want to do a quick test of QML. In my build, I forgot to set eglfs as the default platform, but it can be set it in the environment. I wrote a simple app to test Qt Quick <a href="https://github.com/carlonluca/Fall" target="_blank">here</a>. The animations are very simple, but I wrote it like this to see how well many items are handled and how well the uniform movement on the y axis is rendered.</p><p style="text-align: left;"><u>NOTE</u>: Unlike Qt5, Qt6 includes host tools and tools built for the target. This means you can build the test app on the target directly or cross-build it from your host. For the package below anyway, you'd need to have a system compatible with those binaries.</p><h3 style="text-align: left;">First App</h3><p style="text-align: left;">This video shows a comparison of this Qt 6 build against Qt 5. It also shows the same benchmark app on Intel UHD and nVidia.</p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/5fPRT4j_VJE" width="320" youtube-src-id="5fPRT4j_VJE"></iframe></div><h3 style="clear: both; text-align: left;">Download</h3><div><div>If you want to test the build of Qt 6 on your rpi, you can download it from here:</div><div><br /></div><div><a href="https://polr.luc4.duckdns.org/qt-rasp3-620-rc1" target="_blank">Download</a> Qt 6.2.0-rc1 for Raspberry OS Buster armv8-a</div><div><br /></div><div>The package does not include the toolchain, that you can download from the other links, but includes the host build. I don’t think it will be of help, as it is built for my Manjaro context, but I placed it there anyway.</div><div><br /></div><div>The positions of the directories are relevant:</div></div><div><ul style="text-align: left;"><li><b>/opt/rpi/rpi-8.6.3</b>: toolchain;</li><li><b>/opt/Qt-x64-6.2.0-beta3</b>: host build;</li><li><b>/usr/local/Qt-rasp-6.2.0-beta3</b>: position in the target;</li><li><b>/opt/rpi/sysroot</b>: sysroot for cross-building.</li></ul><h3 style="text-align: left;">Runtime Context</h3></div><p style="text-align: left;">The is the 3D environment as seen by Qt 6:</p><font class="sourcecode"><div style="text-align: left;">qt.rhi.general: Created OpenGL context QSurfaceFormat(version 2.0, options QFlags<QSurfaceFormat::FormatOption>(), depthBufferSize 24, redBufferSize 8, greenBufferSize 8, blueBufferSize 8, alphaBufferSize 0, stencilBufferSize 8, samples 0, swapBehavior QSurfaceFormat::DefaultSwapBehavior, swapInterval 1, colorSpace QColorSpace(), profile QSurfaceFormat::NoProfile)<br />qt.rhi.general: OpenGL VENDOR: Broadcom RENDERER: VC4 V3D 2.1 VERSION: OpenGL ES 2.0 Mesa 19.3.2<br />qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no.<br />qt.scenegraph.general: rhi texture atlas dimensions: 2048x2048</div></font><p style="text-align: left;">Bye 😉</p>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-40122286079966460682021-09-25T02:43:00.000+02:002021-09-25T02:43:42.576+02:00Experimental Implementation of the Blog on a Raspberry Pi! 😉<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwSM60y7rUKkwT7ONOKDxEAeTJequwfLtUx-TX5Tm72Dq_KqPoxV2bjYP0ebSLXhQZLjlL_E4yjRC9lT49JCqPW1vMtE99uWkCIBmVd8vBC8gccCwW8ibzSrBRWVrLXUKnz-nueUNrGcFe/s1800/rpi.webp" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1013" data-original-width="1800" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwSM60y7rUKkwT7ONOKDxEAeTJequwfLtUx-TX5Tm72Dq_KqPoxV2bjYP0ebSLXhQZLjlL_E4yjRC9lT49JCqPW1vMtE99uWkCIBmVd8vBC8gccCwW8ibzSrBRWVrLXUKnz-nueUNrGcFe/w400-h225/rpi.webp" width="90%" /></a></div><p>I recently started to add many useful open source services to my Raspberry Pi, like Jenkins, GitLab etc… I wrote some articles about running some services on a arm64 device here:</p><p></p><ul style="text-align: left;"><li><a href="https://bugfreeblog.duckdns.org/2021/03/01/versioning-and-ci-cd-on-a-raspberry-pi-or-other-arm-embedded-devices" target="_blank">versioning services</a>;</li><li><a href="https://bugfreeblog.duckdns.org/2021/07/25/dark-theme-for-mediawiki-in-docker/" target="_blank">MediaWiki</a>;</li><li><a href="https://bugfreeblog.duckdns.org/2021/09/23/docker-image-for-the-awesome-mldonkey-service" target="_blank">mldonkey</a>;</li><li><a href="https://bugfreeblog.duckdns.org/2021/08/17/docker-qt" target="_blank">continuous integration with Qt on a Raspberry Pi</a>.</li></ul><p></p><p>After these, I also wanted to try WordPress: it is already available as a <a href="https://hub.docker.com/_/wordpress" target="_blank">comfortable docker image</a> for arm64. How could I put it to work? I thought I could reimplement the Bugfree Blog in WordPress!</p><p>Unfortunately it was a bit harder than I thought: first of all <a href="https://github.com/raspberrypi/linux/issues/3981" target="_blank">this bug</a> was making the system completely unstable. I fortunately found a workaround soon by bisecting the kernel, and now there is also an official fix. The fix is not published yet on Ubuntu, but with <a href="https://bugfreeblog.duckdns.org/2021/08/21/ubuntu-kernel-rpi4/" target="_blank">this docker image</a> I can apply the patches and cross-build the Ubuntu kernel quickly.</p><p>A second problem was related to disconnections of USB devices when USB hubs are connected. This is still unresolved.</p><p>A third problem is related to the SD card: I never had problems with the SD card, but I recently broke a few. The Raspberry Pi 4 is hotter that I thought, even when load is minimum. The SD cards are guaranteed to work properly up to 85°C, and the Raspberry Pi is set to that max temp, but I tried to reduce it by using a proper case and adding a little (and very professional) Lego castle to encourage heat dissipation. Let’s hope SD cards can live longer.</p><h3 style="text-align: left;">New URL</h3><div><div>The new URL for the experimental Bugfree Blog on Raspberry Pi 64 bit is:<br /></div><div><br /></div><div style="text-align: center;"><a href="https://bugfreeblog.duckdns.org"><b>https://bugfreeblog.duckdns.org</b></a></div><div style="text-align: center;"><br /></div><div>We’ll see if the experiment succeeds, what the performance is and how much I’ll keep it active.</div><div>If you are curious, have a look!</div><div>Bye 😉</div></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-19186670348424024732021-09-23T18:42:00.004+02:002021-10-03T01:45:28.653+02:00Docker Image for the Awesome MLDonkey Service<div class="separator" style="clear: both;"><a href="https://github.com/carlonluca/docker-mldonkey/raw/master/shot.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="100%" data-original-height="404" data-original-width="800" src="https://github.com/carlonluca/docker-mldonkey/raw/master/shot.png"/></a></div>
<p>I really like this excellent piece of software. I found some docker images for it for the arm64 architecture, but they seemed not to be very up to date, so I created my own. <a href="https://hub.docker.com/r/carlonluca/mldonkey" target="_blank">Here</a> you can find my version of a dockerized MLDonkey service, built for many archs: armv7, arm64, x86 and x64. The arm versions are perfect for Raspberry Pi variants.</p><p>The latest version of the image is taken from <a href="https://github.com/ygrek/mldonkey/commit/d9394aaf3dd4426d5c5f7b93fad9d77322687234" target="_blank">this commit</a>, which is the latest at the time of writing. It also includes a couple of patches that I sent to add a dark theme.</p><p>The image is built on top of debian:buster. For the moment, it is difficult to use something newer because of <a href="https://github.com/ygrek/mldonkey/issues/46" target="_blank">this known issue</a>.</p><p></p><ul style="text-align: left;"><li>Image on Docker Hub: <a href="https://hub.docker.com/repository/docker/carlonluca/mldonkey" target="_blank">link</a>;</li><li>GitHub repo for the project: <a href="https://github.com/carlonluca/docker-mldonkey" target="_blank">link</a>.</li></ul><p></p><p>To run it, you only need a single command:</p>
<p class="sourcecode">$ docker run -i -t -v "`pwd`/data:/var/lib/mldonkey" carlonluca/mldonkey</p>
<p>For more options read the readme in the repo.</p><p>Bye! 😉</p>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-28704738088467089632021-09-19T19:16:00.006+02:002021-09-19T19:26:07.305+02:00Measuring the Frame Rate in Qt/QML<p>I frequently need to measure the frame rate in a Qt/QML application to have an idea of how heavy the changes I'm making are. In the past, I found two approaches that seemed to answer the question: one is using a simple QML item, measuring the frequency of changes of a property. The other is using a custom QQuickItem, measuring the frequency of the calls received to refresh it. I never used the first approach because it did not feel safe, while I typically used the second.</p><p>Instead of copy/pasting code into my projects repeatedly, I thought I could add it to my collection of simple procedures in <a href="https://github.com/carlonluca/lqtutils">https://github.com/carlonluca/lqtutils</a>, making it simple to integrate when needed. I therefore asked myself which one to include.</p><p>By thinking a bit about it, I thought of a different simpler approach using the signal <a href="https://doc.qt.io/qt-5/qquickwindow.html#frameSwapped" rel="noreferrer noopener" target="_blank">QQuickWindow::frameSwapped</a>(). This is what Qt doc says about it:</p><p><i>This signal is emitted when a frame has been queued for presenting. With vertical synchronization enabled the signal is emitted at most once per vsync interval in a continuously animating scene. This signal will be emitted from the scene graph rendering thread.</i></p><p>This seemed a reasonable approach, simple to implement, very concise and lightweight. The resulting code is in the repo. Doc is in: <a href="https://github.com/carlonluca/lqtutils#lqtutils_uih">https://github.com/carlonluca/lqtutils#lqtutils_uih</a>.</p><h2 style="text-align: left;">Is this Correct?</h2><p>I was wondering if my approach was correct, so I thought I could compare with the other approaches. I took the snippets from <a href="https://stackoverflow.com/questions/35553792/show-fps-in-qml" rel="noreferrer noopener" target="_blank">this SO question</a>. I tried the three techniques separately and also tried to add them together in the same code for a comparison of the values. For the test I used my QML app here: <a href="https://github.com/carlonluca/Fall" rel="noreferrer noopener" target="_blank">https://github.com/carlonluca/Fall</a>. In the branch <a href="https://github.com/carlonluca/Fall/tree/fps_comparison" rel="noreferrer noopener" target="_blank">https://github.com/carlonluca/Fall/tree/fps_comparison</a> I added all the components to compare. This is the result:</p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/p_y_kL85R4A" width="320" youtube-src-id="p_y_kL85R4A"></iframe></div><br /><p>As it can be seen, the method based on the QQuickPaintedItem gives the same result of the one based on the frameSwapped() signal. The other one is very different. The explanation for this is probably based on the fact that the <a href="https://doc.qt.io/qt-5/qtquick-visualcanvas-scenegraph.html" target="_blank">Qt scene graph</a> on Linux renders through the threaded render mode. In fact, forcing a single-threaded render mode makes the three techniques agree on the measurement (second run in the video).</p><p>Compared to a custom QQuickPaintedItem, the frameSwapped() technique seems to be more lightweight, so it is the one I implemented in my repo.</p><p>Bye! ;-)</p>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-85486216858083927492021-09-08T01:34:00.003+02:002021-09-08T01:34:32.239+02:00Using requirejs in WordPress posts<p>While porting this blog to WordPress as an experiment, I came across a pretty frequent problem: using <a href="https://requirejs.org/" target="_blank">requirejs</a> in a WordPress post. In my case, requirejs is needed to use my TypeScript libraries from <a href="https://github.com/carlonluca/isogeometric-analysis">https://github.com/carlonluca/isogeometric-analysis</a> in the post, to create the plots you see in <a href="https://thebugfreeblog.blogspot.com/2021/07/iga-nurbs.html" target="_blank">this post</a>.</p><p>It was not simple at all to use it in Google Blogger, WordPress does not seem to behave very differently in this regard. When the post is rendered, I get errors like:</p><p>Uncaught Error: Mismatched anonymous define() module: […]</p>
<font class="sourcecode"><pre>Uncaught Error: Mismatched anonymous define() module: […]</pre></font>
This may be related to the fact that something in WordPress or its plugins looks for that symbol and gets confused when another one is defined in the post. I found many pages treating this problem, but no solution satisfied me, either because it did not work or because I did not like it. I’d prefer the solution to be entirely contained in the post itself, I won’t probably use requirejs often.<br/>
This is the way I solved the problem: let’s give the time to WordPress and all its plugins to load and settle. Then, start loading requirejs and all the other deps we need in a script. This is an example for my specific use case:<br/>
<font class="sourcecode"><pre><p>
window.addEventListener("load", function() {
$.getScript('https://requirejs.org/docs/release/2.3.6/comments/require.js', function() {
$.getScript('https://carlonluca.github.io/isogeometric-analysis/dist/bundle.js', function() {
require(["nurbs/drawNurbsCurveExample"], function(d) {
d.drawNurbsCurveExample1("nurbsCurve1", true)
d.drawNurbsCurveExample2("nurbsCurve2", true, "nurbsBasis2")
d.drawNurbsCurveExampleCircle("nurbsCurve3", true, "nurbsBasis3")
})
require(["nurbs/drawNurbsSurfExamples"], function(d) {
d.drawNurbsSurfPlateHole("nurbsSurf1", true)
d.drawNurbsSurfToroid("nurbsSurf2", true)
})
})
})
}, false)
</p></pre></font>
To do this, I used jQuery. So, first of all jQuery is loaded. Then, on the onload event, I load requirejs. When requirejs is loaded, I then load my library, which needs requirejs, and then I can freely use it in the post. Note that simply adding script elements was not sufficient, the order must be preserved and the callbacks must be used to ensure the proper chain is respected.<br/>
This approach is a little verbose, but allows me to leave the rest of the theme unchanged and confines the mess to the specific posts needing these structures.Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-24397930350706284002021-08-21T14:34:00.000+02:002021-08-21T14:34:14.095+02:00Cross-building the Ubuntu Kernel for the Raspberry Pi 4 (arm64)<p>I recently had to rebuild the Ubuntu kernel for the Raspberry Pi pretty often to apply some patches. Building on the Pi is simple, but takes A LOT of hours and completely saturates the rpi4. Also, it means installing many dev packages, which I do not typically need. I also tried to do it on a development rpi3: took many hours, failed a few times because of insufficient RAM etc… It is a pain.</p><p>I therefore decided to try to cross-build it from my machine, which is not a Ubuntu machine at the moment. Quickest and simplest way I found is to use Docker. The result seems to work, so I decided to also provide the tools I created for myself here: <a href="https://github.com/carlonluca/docker-rpi-ubuntu-kernel">https://github.com/carlonluca/docker-rpi-ubuntu-kernel</a>.</p><h3 style="text-align: left;">Usage</h3><div>The image only contains the tools and the libs needed to compile. The kernel itself and the script is provided externally. A workspace directory will contain both the kernel code to build and the output debian packages. With the following command the script is executed in the container and you should get your debs:</div>
<font class="sourcecode">
<pre>
docker run --rm -it --name builder -v $PWD/workspace:/workspace \
-v $PWD/build.sh:/workspace/build.sh carlonluca/docker-rpi-ubuntu-kernel:focal \
/workspace/build.sh
</pre>
</font>
The workspace directory must contain a src directory with the kernel, so you’ll have to create it yourself and then patch your kernel:<br/>
<font class="sourcecode">
<pre>
mkdir workspace
cd workspace
git clone https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux-raspi/+git/hirsute src
[apply needed patches]
</pre>
</font>
The resulting packages can then be moved to the pi and installed with:<br/>
<font class="sourcecode">
<pre>
sudo dpkg -i *.deb
</pre>
</font>
Hope this tool can be useful! Bye ;-)Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com1tag:blogger.com,1999:blog-3944174827064012298.post-32728392877235192502021-08-17T13:12:00.005+02:002021-08-22T10:56:04.554+02:00Docker Image for Qt Development and Continuous Integration on x64 and arm64<h2 style="text-align: left;">Intro</h2><div>It happens from time to time that I would benefit from having a simple Docker image with all the deps needed to build and run Qt apps on specific Qt versions. For instance, I may need to build some binary on Mac OS for Linux or I may need to have an image for some continuous integration system.</div><h2 style="text-align: left;">Problem</h2><div>I had a look around and there are quite a few projects: some do not provide an arm build, some rely on the Qt official installer, that is a bit tricky to automate and tends to change often, some rely on distro-provided packages, that do not provide every version etc… I’d prefer to have a solid build procedure to build images for any Qt version I want. Also, my CI system runs on arm64, so I’d need a multiarch image, and therefore two different Qt builds. I thought it could be simpler to just build Qt on-the-fly in a Dockerfile but… turned out it is not exactly simple.</div><h2 style="text-align: left;">Solution</h2><div>At first I created a Dockerfile to:</div><div><ol style="text-align: left;"><li>install all the needed deps on Ubuntu focal;</li><li>download Qt sources;</li><li>configure;</li><li>build;</li><li>install;</li><li>cleanup.</li></ol></div><div>This proved to be a simple solution, but building Qt for arm on qemu or building on arm took way too much. So I though of a different solution. I created two images:</div><div><ul style="text-align: left;"><li><a href="https://hub.docker.com/repository/docker/carlonluca/qt-builder" target="_blank">carlonluca/qt-builder</a> is an image with the proper tools to build Qt for x64 and cross-build Qt for arm64;</li><li><a href="https://hub.docker.com/repository/docker/carlonluca/qt-dev" target="_blank">carlonluca/qt-dev</a> is an image with the proper tools to build and run Qt apps.</li></ul></div><div>With the first image Qt can be built and cross-built in a few hours for both x64 and arm64, directly on x64. The builds are then injected into a second multiarch image. This is way faster than building on qemu.</div><div><br /></div><div>Only one problem left: in Qt 5, crossbuilding Qt results in some Qt tools like qmake to be built for the host arch, which is unacceptable in this case. So, in the second image, a build of the only qtbase module is also needed to build arm64 binaries. Qt 6 works differently instead.</div><h2 style="text-align: left;">Result</h2><div><div>The <b>code</b> to build Qt and all the images are available at: <a href="https://github.com/carlonluca/docker-qt">https://github.com/carlonluca/docker-qt</a>.</div><div>The <b>image</b> to build Qt is available at: <a href="https://hub.docker.com/repository/docker/carlonluca/qt-builder">https://hub.docker.com/repository/docker/carlonluca/qt-builder</a>.</div><div>The <b>image</b> to use for app development is available at: <a href="https://hub.docker.com/repository/docker/carlonluca/qt-dev">https://hub.docker.com/repository/docker/carlonluca/qt-dev</a>.</div></div><div><h2 style="text-align: left;">Continuous Integration on GitLab with Qt</h2><div>An example of usage of the dev image is running continuous integration and unit tests on your code on Jenkins or GitLab. For example, I can now run my unit tests in my GitLab instance running on Raspberry Pi 4 with the following code (taken from my project <a href="https://github.com/carlonluca/lqobjectserializer">https://github.com/carlonluca/lqobjectserializer</a>):</div></div><div><div>variables:</div></div><div>
<pre><font class="sourcecode">
GIT_SUBMODULE_STRATEGY: recursive
stages:
- test_qt5
- test_qt6
Test_qt5:
stage: test_qt5
image:
name: "carlonluca/qt-dev:5.15.2"
entrypoint: [""]
script:
- cd LQObjectSerializerTest
- mkdir build
- cd build
- cmake ../qt5
- make
- ./LQObjectSerializerTest
- ./LGithubTestCase
Test_qt6:
stage: test_qt6
image:
name: "carlonluca/qt-dev:6.1.2"
entrypoint: [""]
script:
- cd LQObjectSerializerTest
- mkdir build
- cd build
- cmake ../qt6
- make
- ./LQObjectSerializerTest
- ./LGithubTestCase
</font><br /></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://github.com/carlonluca/docker-qt/raw/master/shot.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="541" data-original-width="800" src="https://github.com/carlonluca/docker-qt/raw/master/shot.png" width="90%" /></a></div><pre><br /></pre>
<div>These images are still experimental though.</div><div>Have fun 😉</div><div><br /></div><div>Bye!</div></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-56028217845909016632021-07-25T15:11:00.003+02:002021-07-25T15:11:26.831+02:00Dark Theme for MediaWiki in DockerI recently started to use MediaWiki as a way to store personal information, notes, links etc... It is comfortable to have all that info with me, properly structured, immediately editable online regardless of the operating system and versioned. Adding an instance of MediaWiki to an existent setup is straightforward, and I like to do it with docker. The official docker image of MediaWiki is already multiarch, so I could add it to my Raspberry Pi quickly. Default MediaWiki includes a light theme, but does not seem to include a dark theme. This is where this project by Martynov Maxim comes to help: <a href="https://github.com/dolfinus/DarkVector" target="_blank">https://github.com/dolfinus/DarkVector</a>. You'll have to add it to your MediaWiki container and select it for your users.<br/><br/>
Keeping MediaWiki up to date (and only usable through HTTPS) is important for security reasons (<a href="https://www.mediawiki.org/wiki/Manual:Security" target="_blank">https://www.mediawiki.org/wiki/Manual:Security</a>) so I created my own MediaWiki multiarch image including that theme by default. You can freely use it: <a href="https://hub.docker.com/repository/docker/carlonluca/darkmediawiki" target="_blank">https://hub.docker.com/repository/docker/carlonluca/darkmediawiki</a>. I use it successfully on my aarch64 installation. This is the result:<br/>
<div class="separator" style="clear: both;"><a href="https://github.com/carlonluca/darkmediawiki-docker/raw/master/shot.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="600" data-original-height="450" data-original-width="800" src="https://github.com/carlonluca/darkmediawiki-docker/raw/master/shot.png"/></a></div>
Refreshing the image is almost effertless thanks to the CI/CD capabilities of GitLab.<br/>
For more info refer to the GitHub project: <a href="https://github.com/carlonluca/darkmediawiki-docker" target="_blank">https://github.com/carlonluca/darkmediawiki-docker</a>.
Have fun ;-)Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-29473855504461666342021-07-11T12:03:00.035+02:002021-08-19T14:17:06.366+02:00Isogeometric Analysis: NURBS curves and surfaces in Octave and TypeScript<script charset="utf-8" src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://unpkg.com/mathjs@9.3.2/lib/browser/math.js"></script>
<script src="https://requirejs.org/docs/release/2.3.6/comments/require.js"></script>
<script src="https://carlonluca.github.io/isogeometric-analysis/dist/bundle.js"></script>
<script>
window.addEventListener("load", function() {
require(["nurbs/drawNurbsCurveExample"], function(d) {
d.drawNurbsCurveExample1("nurbsCurve1", true)
d.drawNurbsCurveExample2("nurbsCurve2", true, "nurbsBasis2")
d.drawNurbsCurveExampleCircle("nurbsCurve3", true, "nurbsBasis3")
})
require(["nurbs/drawNurbsSurfExamples"], function(d) {
d.drawNurbsSurfPlateHole("nurbsSurf1", true)
d.drawNurbsSurfToroid("nurbsSurf2", true)
})
}, false)
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']], processEscapes: true}});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"> </script>
In <a href="https://thebugfreeblog.blogspot.com/2021/06/iga-bspline.html">this blog post</a> I wrote some notes about B-splines. There are however important classes of curves and surfaces that cannot be represented by piecewise-polynomials like circles, ellipses etc... NURBS come to the rescue.
<h2>NURBS curves</h2>
NURBS is a generalization of B-splines where basis functions are defined with piecewise-rational polynomials. Again the parametric domain is split into multiple ranges by using a knot vector. The general definition is:<br /><br />
$$\boldsymbol{C}\left(\xi\right)=\sum_{i=0}^{n}R_{i}^{p}\left(\xi\right)\boldsymbol{P}_{i},\;a\leq\xi\leq b$$<br />
$\boldsymbol{P}_{i}$ are the control points and the functions $R_{i}^{p}$ are the NURBS basis functions, defined as:<br /><br />
$$R_{i}^{p}\left(\xi\right)=\dfrac{N_{i}^{p}\left(\xi\right)w_{i}}{{\displaystyle\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)w_{i}}},\;a\leq\xi\leq b,$$<br />
where the functions $N_i^{p}$ are the B-spline basis functions (defined <a href="https://thebugfreeblog.blogspot.com/2021/06/iga-bspline.html">here</a>):<br /><br />
$$N_{i}^{0}\left(\xi\right)=\left\{ \begin{array}{ll}1, & \xi_{i}\leq\xi<\xi_{i+1}\\0,&\text{otherwise}\end{array}\right.,a\leq\xi\leq b$$
$$N_{i}^{p}\left(\xi\right)=\frac{\xi-\xi_{i}}{\xi_{i+p}-\xi_{i}}\cdot N_{i}^{p-1}\left(\xi\right)+\frac{\xi_{i+p+1}-\xi}{\xi_{i+p+1}-\xi_{i+1}}\cdot N_{i+1}^{p-1}\left(\xi\right),a\leq\xi\leq b$$<br />
and the values $w_i$'s are known as weights. The knot vector has the same definition given for B-spline curves:<br /><br />
$$\Xi=\left[\underset{p+1}{\underbrace{a,\ldots,a}},\xi_{p+1},\ldots\xi_{n},\underset{p+1}{\underbrace{b,\ldots,b}}\right],\;\left|\Xi\right|=n+p+2,$$
<h2>NURBS surfaces</h2>
By using the tensor product we can obtain definitions for NURBS in spaces of higher dimension. For surfaces, given the knot vectors:<br /><br />
$$\Xi=\left[\underset{p+1}{\underbrace{a_{0},\ldots,a_{0}}},\xi_{p+1},\ldots,\xi_{n},\underset{p+1}{\underbrace{b_{0},\ldots,b_{0}}}\right],\left|\Xi\right|=n+p+2$$
$$H=\left[\underset{q+1}{\underbrace{a_{1},\ldots,a_{1}}},\xi_{q+1},\ldots,\xi_{m},\underset{q+1}{\underbrace{b_{1},\ldots,b_{1}}}\right],\left|H\right|=m+q+2$$<br />
a NURBS surface can be defined as:<br /><br />
$$\boldsymbol{S}\left(\xi,\eta\right)=\sum_{i=0}^{n}\sum_{j=0}^{m}R_{i,j}^{p,q}\left(\xi,\eta\right)\boldsymbol{P}_{i,j},\;\left\{ \begin{array}{c}a_{0}\leq\xi\leq b_{0}\\a_{1}\leq\eta\leq b_{1}\end{array}\right.$$<br />
where:<br /><br />
$$R_{i,j}^{p,q}\left(\xi,\eta\right)=\dfrac{N_{i}^{p}\left(\xi\right)N_{j}^{q}\left(\eta\right)w_{i,j}}{{\displaystyle \sum_{\hat{i}=0}^{n}\sum_{\hat{j}=0}^{m}N_{\hat{i}}^{p}\left(\xi\right)N_{\hat{j}}^{q}\left(\eta\right)w_{\hat{i},\hat{j}}}},\;\left\{ \begin{array}{c}a_{0}\leq\xi\leq b_{0}\\a_{1}\leq\eta\leq b_{1}\end{array}\right.$$<br />
and $w_{i,j}$ is the weight.
<h2>Homogeneous Coordinates</h2>
The implementations found in the repo do not directly implement the summations above, but use instead homogeneous coords to make calculations simpler. Let's consider the general form of a B-spline curve:<br /><br />
$$\boldsymbol{C}\left(\xi\right)=\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)\boldsymbol{P}_{i},\;a\leq\xi\leq b$$<br />
Control points $\boldsymbol{P}_i$ can be written in homogeneous coords like this:<br /><br />
$$\boldsymbol{P}_{i}^{w}=\left[\begin{array}{c}
x_{i}\\
y_{i}\\
z_{i}\\
1
\end{array}\right]$$<br />
We can multiply each control point by a value $w_i\neq 0$, and the result would still represent the same point in the euclidean space. As a result, we can write:<br /><br />
$$\boldsymbol{C}^{w}\left(\xi\right)=\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)\cdot\left[\begin{array}{c}
x_{i}w_{i}\\
y_{i}w_{i}\\
z_{i}w_{i}\\
w_{i}
\end{array}\right]=\left[\begin{array}{c}
\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)x_{i}w_{i}\\
\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)y_{i}w_{i}\\
\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)z_{i}w_{i}\\
\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)w_{i}
\end{array}\right]$$<br />
$\boldsymbol{C}^w(\xi)$ is therefore the original B-spline curve in homogeneous coords. Now we can map back it to the euclidean space:<br /><br />
$$\boldsymbol{C}\left(\xi\right)=\left[\begin{array}{c}
\frac{\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)x_{i}w_{i}}{\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)w_{i}}\\
\frac{\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)y_{i}w_{i}}{\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)w_{i}}\\
\frac{\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)z_{i}w_{i}}{\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)w_{i}}\\
1
\end{array}\right]$$<br />
which yields:<br /><br />
$$\boldsymbol{C}\left(\xi\right)=\frac{\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)w_{i}\boldsymbol{P}_{i}}{\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)w_{i}}$$<br />
This means that, moving to homogeneous coords, we can use a simpler form. Given:<br /><br />
$$\boldsymbol{P}_{i}^{w}=\left[\begin{array}{c}
x_{i}w_{i}\\
y_{i}w_{i}\\
z_{i}w_{i}\\
w_{i}
\end{array}\right]$$
we can write a NURBS curve as:<br /><br />
$$\boldsymbol{C}^{w}\left(\xi\right)=\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)\boldsymbol{P}_{i}^{w}$$<br />
and a NURBS surface as:<br /><br />
$$\boldsymbol{S}^{w}\left(\xi,\eta\right)=\sum_{i=0}^{n}\sum_{j=0}^{m}N_{i}^{p}\left(\xi\right)N_{j}^{q}\left(\eta\right)\boldsymbol{P}_{i}^{w}$$<br />
All the implementations in the repo use these simpler forms.
<h2>Octave Implementation</h2>
The <font class="sourcecode">computeNURBSBasisFun</font> script can be used to compute NURBS basis functions. The <font class="sourcecode">drawNURBSBasisFunsP5</font> draws:<br /><br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_basis_w3.svg.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="100%" data-original-height="800" data-original-width="793" src="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_basis_w3.svg.png"/></a></div>
in the plots the effect of the weight is pretty clear. From top to bottom, the degree of the basis funs is increased over the knot vector $ Xi = [0.25, 0.5, 0.75]$.<br />
The <font class="sourcecode">computeNURBSCurvePoint</font> script uses homogeneous coords to compute a NURBS curve using B-spline basis functions. We can build curves similar to what we could draw with B-splines but we can also draw circles:<br /><br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_curve_example.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="2017" data-original-width="2000" src="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_curve_example.svg.png" width="100%" /></a></div>
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_circle.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="2017" data-original-width="2000" src="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_circle.svg.png" width="100%" /></a></div>
This is an example that shows what happens when a weight is increased on one point:<br /><br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_curve_weight.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="1183" data-original-width="2000" src="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_curve_weight.svg.png" width="100%" /></a></div>
For NURBS surfaces instead we can draw bivariate basis functions. In these two examples, the first shows what happens when weights are all equal to 1, the second when weights are not all equal:<br /><br />
<a href="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_bivariate_basis.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="402" data-original-width="800" src="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_bivariate_basis.svg.png" width="100%" /></a><br />
<a href="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_bivariate_basis_weight.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="402" data-original-width="800" src="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_bivariate_basis_weight.svg.png" width="100%" /></a><br />
Now with the <font class="sourcecode">computeNURBSSurfPoint</font>, using homogeneous coords, we can draw some interesting surfaces. Scripts are included to draw a plate with a hole:<br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_plate.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img border="0" data-original-height="1948" data-original-width="2000" src="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_plate.svg.png" width="100%" /></a></div>
and one is provided to draw a toroid:<br /><br />
<a href="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_toroid.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="388" data-original-width="800" src="https://carlonluca.github.io/isogeometric-analysis/images/nurbs_toroid.svg.png" width="100%" /></a>
<h2>TypeScript Implementation</h2>
The same implementation is provided for TypeScript, so you can experiment with the browser. With the <font class="sourcecode">NurbsCurve</font> you can compute NURBS basis functions:<br /><br />
<a name='more'></a>
<div style="border: 1px solid rgb(0, 0, 0); display: block; margin: auto; width: 100%;"><div id="nurbsBasis2" style="margin: auto; width: 98%;"></div></div><br />
<div style="border: 1px solid rgb(0, 0, 0); display: block; margin: auto; width: 100%;"><div id="nurbsBasis3" style="margin: auto; width: 98%;"></div></div><br />
and you can draw the actual curves:<br />
<div style="border: 1px solid rgb(0, 0, 0); display: block; margin: auto; width: 100%;"><div id="nurbsCurve1" style="margin: auto; width: 98%;"></div></div><br />
<div style="border: 1px solid rgb(0, 0, 0); display: block; margin: auto; width: 100%;"><div id="nurbsCurve2" style="margin: auto; width: 98%;"></div></div><br />
<div style="border: 1px solid rgb(0, 0, 0); display: block; margin: auto; width: 100%;"><div id="nurbsCurve3" style="margin: auto; width: 98%;"></div></div><br />
With the <font class="sourcecode">NurbsSurf</font> class instead, you can draw the surfaces:<br />
<div style="border: 1px solid rgb(0, 0, 0); display: block; margin: auto; width: 100%;"><div id="nurbsSurf1" style="margin: auto; width: 98%;"></div></div>
<div style="border: 1px solid rgb(0, 0, 0); display: block; margin: auto; width: 100%;"><div id="nurbsSurf2" style="margin: auto; width: 98%;"></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div style="border: 1px solid rgb(0, 0, 0); display: block; margin: auto; width: 100%;"><br /></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-6920433589750758372021-06-26T10:02:00.025+02:002021-08-19T14:21:06.536+02:00Isogeometric Analysis: B-spline Curves and Surfaces in Octave and TypeScript<script charset='utf-8' src='https://cdn.plot.ly/plotly-latest.min.js'></script>
<script src='https://unpkg.com/mathjs@9.3.2/lib/browser/math.js'></script>
<script src='https://requirejs.org/docs/release/2.3.6/comments/require.js'></script>
<script src='https://carlonluca.github.io/isogeometric-analysis/dist/bundle.js'></script>
<script>
window.addEventListener("load", function() {
require(["bspline/drawBsplineCurveExample"], function(d) {
d.drawBsplineCurve1("bsplineCanvas1", true)
d.drawBsplineCurve2("bsplineCanvas2", true, "basisCanvas")
})
require(["bspline/drawBsplineSurfExample"], function(d) {
d.drawBsplineSurfExample1("bsplineCanvas3", true)
d.drawBsplineSurfExample2("bsplineCanvas4", true)
})
}, false)
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']], processEscapes: true}});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"> </script>
In the previous blog post <a href="https://thebugfreeblog.blogspot.com/2021/05/isogeometric-analysis-bezier-curves-and.html">here</a> I implemented Bézier curves. There are other important structures that are used in computer graphics and I'd need those structures to define a domain and a solution in IGA for my implementation here: <a href="https://github.com/carlonluca/isogeometric-analysis" target="_blank">https://github.com/carlonluca/isogeometric-analysis</a>.<br/><br/>
Bézier curves are great, but the polynomials needed to describe some curves may need a high degree to satisfy multiple constraints. To overcome this problem, some structures were designed to use piecewise-polynomials instead. Examples in this case are NURBS and B-splines.
<h2>B-spline Curves</h2>
B-splines are curves that are described using piecewise-polynomials with minimal support. The parametric domain is split into multiple ranges by using a vector. The general definition of a B-spline curve is:<br/><br/>
$$\boldsymbol{C}\left(\xi\right)=\sum_{i=0}^{n}N_{i}^{p}\left(\xi\right)\boldsymbol{P}_{i},\;a\leq\xi\leq b$$<br/>
where $\boldsymbol{P}_{i}$'s are the control points of the curve and the functions $N_{i}^{p}\left(\xi\right)$ are basis functions defined as:<br/><br/>
$$N_{i}^{0}\left(\xi\right)=\left\{ \begin{array}{ll}1, & \xi_{i}\leq\xi<\xi_{i+1}\\0,&\text{otherwise}\end{array}\right.,a\leq\xi\leq b$$
$$N_{i}^{p}\left(\xi\right)=\frac{\xi-\xi_{i}}{\xi_{i+p}-\xi_{i}}\cdot N_{i}^{p-1}\left(\xi\right)+\frac{\xi_{i+p+1}-\xi}{\xi_{i+p+1}-\xi_{i+1}}\cdot N_{i+1}^{p-1}\left(\xi\right),a\leq\xi\leq b$$<br/>
The values $\xi_{i}$ are elements of the aforementioned knot vector, defined as:<br/><br/>
$$\Xi=\left[\underset{p+1}{\underbrace{a,\ldots,a}},\xi_{p+1},\ldots,\xi_{n},\underset{p+1}{\underbrace{b,\ldots,b}}\right],\left|\Xi\right|=n+p+2$$<br/>
where $p$ is the degree of the basis functions. A knot vector in this form is said to be nonperiodic or clamped or open.<br/>
<h2>B-spline Surfaces</h2>
By using the tensor product we can obtain B-splines in spaces of higher dimension. For surfaces, given the knot vectors:<br/><br/>
$$\Xi=\left[\underset{p+1}{\underbrace{a_{0},\ldots,a_{0}}},\xi_{p+1},\ldots,\xi_{n},\underset{p+1}{\underbrace{b_{0},\ldots,b_{0}}}\right],\left|\Xi\right|=n+p+2$$
$$H=\left[\underset{q+1}{\underbrace{a_{1},\ldots,a_{1}}},\xi_{q+1},\ldots,\xi_{m},\underset{q+1}{\underbrace{b_{1},\ldots,b_{1}}}\right],\left|H\right|=m+q+2$$<br/>
a B-spline surface can be defined as:<br/><br/>
$$\boldsymbol{S}\left(\xi,\eta\right)=\sum_{i=0}^{n}\sum_{j=0}^{m}N_{i}^{p}\left(\xi\right)N_{j}^{q}\left(\eta\right)\boldsymbol{P}_{i,j},\;\left\{ \begin{array}{c}
a_{0}\leq\xi\leq b_{0}\\
a_{1}\leq\eta\leq b_{1}
\end{array}\right.$$<br/>
where $p$ and $q$ are the degrees of the polynomials.
In the implementations, sometimes I preferred the matrix form of the equations:<br/><br/>
$$\boldsymbol{C}\left(\xi\right)=\left[N_{i-p}\left(\xi\right),\ldots,N_{i}\left(\xi\right)\right]\cdot\left[\begin{array}{c}
\boldsymbol{P}_{i-p}\\
\vdots\\
\boldsymbol{P}_{i}
\end{array}\right],\;\xi\in\left[\xi_{i},\xi_{i+1}\right)$$<br/>
For the surfaces instead, the matrix form is:
$$\boldsymbol{S}\left(\xi,\eta\right)=\left[N_{i-p}\left(\xi\right),\ldots,N_{i}\left(\xi\right)\right]\cdot\left[\begin{array}{ccc}
\boldsymbol{P}_{j-q,i-p} & \cdots & \boldsymbol{P}_{j-q,i}\\
\vdots & \ddots & \vdots\\
\boldsymbol{P}_{j,i-p} & \cdots & \boldsymbol{P}_{j,i}
\end{array}\right]\cdot\left[\begin{array}{c}
N_{j-q}\left(\eta\right)\\
\vdots\\
N_{j}\left(\eta\right)
\end{array}\right],$$
$$\xi\in\left[\xi_{i},\xi_{i+1}\right),\eta\in\left[\eta_{j},\eta_{j+1}\right)$$<br/>
These forms leverage a more performant algorithm for the computation of the basis functions, which returns the value of all nonvanishing functions for a point in the parametric space. The Octave implementation is clearly simpler as Octave has native support for matrices, the TypeScript implementation instead includes a basic <a href="https://github.com/carlonluca/isogeometric-analysis/blob/master/ts/src/core/matrix.ts">Matrix2</a> class that offers the simplest operators.
<h2>Octave Implementation</h2>
An implementation for Octave is provided in <a href="https://github.com/carlonluca/isogeometric-analysis/tree/master/3.4">https://github.com/carlonluca/isogeometric-analysis/tree/master/3.4</a>. There are examples to show how to draw B-spline curves with the implementation.<br/>
For example, the <font class="sourcecode">drawBsplineBasisFuns</font> script shows the B-spline basis functions over the knot vector $\Xi=[0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5]$ using the provided implementation of the basis functions:<br/><br/>
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/bspline_basis.svg.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="100%" data-original-height="800" data-original-width="735" src="https://carlonluca.github.io/isogeometric-analysis/images/bspline_basis.svg.png"/></a></div><br/><br/>
The <font class="sourcecode">drawBsplineCurve</font> script draws, instead, the real curve. For example, to draw the B-spline of degree $p=2$ defined over the knot vector $\Xi=[0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1]$ with control points:<br/><br/>
$$\boldsymbol{P}_{0}=\left(0,0,0\right),\;\boldsymbol{P}_{1}=\left(1,1,1\right),\;\boldsymbol{P}_{2}=\left(2,0.5,0\right)$$
$$\boldsymbol{P}_{3}=\left(3,0.5,0\right),\;\boldsymbol{P}_{4}=\left(0.5,1.5,0\right),\;\boldsymbol{P}_{5}=\left(1.5,0,1\right)$$<br/><br/>
a simple call to:<br/><br/>
<p class="sourcecode">
drawBsplineCurve(5, 2, [<br/>
0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1<br/>
], [<br/>
0, 0; 1, 1; 2, 0.5; 3, 0.5; 0.5, 1.5; 1.5, 0<br/>
]);</p><br/>
draws:<br/><br/>
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/bspline_curve.svg.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="100%" data-original-height="550" data-original-width="600" src="https://carlonluca.github.io/isogeometric-analysis/images/bspline_curve.svg.png"/></a></div><br/><br/>
For surfaces, <font class="sourcecode">drawBivariateBsplineBasisFuns</font> can be used to draw bivariate basis functions. For example:<br/><br/>
<p class="sourcecode">
drawBivariateBsplineBasisFuns([<br/>
0, 0, 0, 0.5, 1, 1, 1<br/>
], 3, 2, [<br/>
0, 0, 0, 0.5, 1, 1, 1<br/>
], 3, 2);
</p><br/>
gives this result:<br/><br/>
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/bspline_bivariate_basis.svg.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="100%" data-original-height="402" data-original-width="800" src="https://carlonluca.github.io/isogeometric-analysis/images/bspline_bivariate_basis.svg.png"/></a></div>
By using the defined basis functions, data defined in <a href="https://github.com/carlonluca/isogeometric-analysis/blob/master/3.4/defineBsplineRing.m">https://github.com/carlonluca/isogeometric-analysis/blob/master/3.4/defineBsplineRing.m</a> can draw a shape similar to a ring:<br/><br/>
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/bspline_surf_ring.svg.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="100%" data-original-height="457" data-original-width="800" src="https://carlonluca.github.io/isogeometric-analysis/images/bspline_surf_ring.svg.png"/></a></div><br/><br/>
Note that this is not yet a toroid.
<h2>TypeScript Implementation</h2>
A TypeScript implementation is also present in the repo. With a simple code like this:<br/><br/>
<a name='more'></a>
<p class="sourcecode">let controlPoints = []<br/>
controlPoints.push(new Point(0, 0))<br/>
controlPoints.push(new Point(1, 1))<br/>
controlPoints.push(new Point(2, 0.5))<br/>
controlPoints.push(new Point(3, 0.5))<br/>
controlPoints.push(new Point(0.5, 1.5))<br/>
controlPoints.push(new Point(1.5, 0))<br/>
let knotVector = [ 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1 ]<br/>
drawBsplineCurve(controlPoints, knotVector, 2, false, drawControlPoints, plot, bernsteinPlot)</p><br/>
It is possible to draw the B-spline curve in a div:<br/><br/>
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; width: 100%; padding: 1em 0;"><div id="bsplineCanvas1" style="margin: auto; width: 95%;"></div></div><br />
By using points with 3 coordinates a curve in 3 dimensions can be drawn:<br/><br/>
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; margin: auto; width: 100%;"><div id="bsplineCanvas2" style="margin: auto; width: 98%;"></div></div><br /><br />
and we can also observe the B-spline basis functions being used in the calculation:<br/><br/>
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; margin: auto; width: 100%;"><div id="basisCanvas" style="margin: auto; width: 98%;"></div></div><br /><br />
For surfaces, the <font class="sourcecode">BsplineSurf</font> can draw the surface with the equations above. This is an example with degree 1 in one direction:<br/><br/>
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; margin: auto; width: 100%;"><div id="bsplineCanvas3" style="margin: auto; width: 98%;"></div></div><br /><br />
this is an example with degree 2:<br/><br/>
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; margin: auto; width: 100%;"><div id="bsplineCanvas4" style="margin: auto; width: 98%;"></div></div><br /><br />
Plots are drawn using <a href="https://plotly.com/">Plotly</a>, but the implementation is pure TypeScript.Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-28834496626329155692021-05-13T13:04:00.027+02:002021-08-19T14:22:40.444+02:00Isogeometric Analysis: Bezier Curves and Surfaces in Octave and TypeScript<script charset='utf-8' src='https://cdn.plot.ly/plotly-latest.min.js'></script>
<script src='https://unpkg.com/mathjs@9.3.2/lib/browser/math.js'></script>
<script src='https://requirejs.org/docs/release/2.3.6/comments/require.js'></script>
<script src='https://carlonluca.github.io/isogeometric-analysis/dist/bundle.js'></script>
<script>
window.addEventListener("load", function() {
require(["bezier/drawBezierCurveExample"], function(d) {
d.drawBezierCurve1("bezierCanvas1", true)
d.drawBezierCurve2("bezierCanvas2", true, "bernsteinCanvas")
})
require(["bezier/drawBezierSurfExample"], function(d) {
d.drawBezierSurfExample("bezierCanvas3", true)
})
}, false)
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']], processEscapes: true}});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"> </script>
While working on my sample IGA implementation here <a href="https://github.com/carlonluca/isogeometric-analysis" target="_blank">https://github.com/carlonluca/isogeometric-analysis</a>, I found myself in need of defining and implementing the math structures used to define the domain and the solution space. This means that I had to implement various algorithms to define structures like Bezier, B-spline, NURBS and T-spline. So this is a quick intro to Bezier curves and surfaces with a couple of implementations.
<h2 style="text-align: left;">Power Basis</h2>
A simple math structure to handle curves and surfaces is the power basis representation. Power basis representation uses polynomials, which are fast to compute and simple to handle.<br />
A $n^{th}$-degree power basis curve can be defined in the parametric space as:<br /><br />
<p align="center">$$\begin{eqnarray*}
\boldsymbol{C}\left(\xi\right) & = & \left(x\left(\xi\right),y\left(\xi\right),z\left(\xi\right)\right)\\
& = & \sum_{i=0}^{n}\boldsymbol{a}_{i}\xi^{i}\\
& = & \left(\left[\boldsymbol{a}_{i}\right]_{i=0}^{n}\right)^{T}\left[\xi^{i}\right]_{i=0}^{n},
\end{eqnarray*}$$</p><br />
where the functions $\xi^{i}$ are the basis (or blending) functions. Using the tensor product scheme we can also define a power basis surface:<br /><br />
<p align="center">$$\begin{eqnarray*}
\boldsymbol{S}\left(\xi,\eta\right) & = & \left(x\left(\xi,\eta\right),y\left(\xi,\eta\right),z\left(\xi,\eta\right)\right)\\
& = & \sum_{i=0}^{n}\sum_{j=0}^{m}\boldsymbol{a}_{i,j}\xi^{i}\eta^{j}\\
& = & \left(\left[\xi^{i}\right]_{i=0}^{n}\right)^{T}\left[\boldsymbol{a}_{i,j}\right]_{i,j=0}^{i=n,j=m}\left[\eta^{j}\right]_{j=0}^{m}
\end{eqnarray*}$$</p><br />
where:<br /><br />
<p align="center">$$
\left\{ \begin{array}{l}
\boldsymbol{a}_{i,j}=\left(x_{i,j},y_{i,j},z_{i,j}\right)\\
b\leq\xi\leq c\\
d\leq\eta\leq e
\end{array}\right.$$</p><br />
<h2 style="text-align: left;">Bezier</h2>
Bezier curves do not increase the space of curves representable by the power basis form, but introduce the concept of control point. Control points convey a clear geometrical meaning, which is very useful during the design process. So, a $n^{th}$-degree Bezier curve is defined as:<br /><br />
<p align="center">$$\boldsymbol{C}\left(\xi\right)=\sum_{i=0}^{n}B_{i}^{n}\left(\xi\right)\boldsymbol{P}_{i},\;a\leq\xi\leq b$$</p><br />
where $\boldsymbol{P}_{i}$ represents the $i^{th}$ control point and:<br /><br />
<p align="center">$$B_{i}^{n}\left(\xi\right)=\frac{n!\cdot\xi^{i}\left(1-\xi\right)^{n-i}}{i!\cdot\left(n-i\right)!}$$</p>
is the $i^{th}$ basis function (also known as Bernstein polynomial). With the tensor product scheme, we can also define a Bezier surface with:<br /><br />
<p align="center">$$\boldsymbol{S}\left(\xi,\eta\right)=\sum_{i=0}^{n}\sum_{j=0}^{m}B_{i}^{n}\left(\xi\right)B_{j}^{m}\left(\eta\right)\boldsymbol{P}_{i,j},\;\left\{ \begin{array}{l}
a\leq\xi\leq b\\
c\leq\eta\leq d
\end{array}\right.$$</p>
<h2 style="text-align: left;">Octave Implementation</h2>
In the repo <a href="https://github.com/carlonluca/isogeometric-analysis" target="_blank">https://github.com/carlonluca/isogeometric-analysis</a>, you can find a basic implementation of Bezier curves and surfaces written for Octave (and Matlab) in: <a href="https://github.com/carlonluca/isogeometric-analysis/tree/master/3.3" target="_blank">https://github.com/carlonluca/isogeometric-analysis/tree/master/3.3</a>. The implementation is tested with a few examples. For example, given these control points:<br /><br />
<p align="center">$$\boldsymbol{P}_{0}=\left(0,0\right),\;\boldsymbol{P}_{1}=\left(1,1\right),\;\boldsymbol{P}_{2}=\left(2,0.5\right)$$
$$\boldsymbol{P}_{3}=\left(3,0.5\right),\;\boldsymbol{P}_{4}=\left(0.5,1.5\right),\;\boldsymbol{P}_{5}=\left(1.5,0\right)$$</p><br />
we can get to this result by using the computeBezier.m script:<br /><br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/bezier_2d.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="322" data-original-width="600" src="https://carlonluca.github.io/isogeometric-analysis/images/bezier_2d.svg.png" width="100%" /></a></div><br /><br />
We can also define the curve in the 3D space. For example these control points:<br /><br />
<p align="center">$$\boldsymbol{P}_{0}=\left(0,0,0\right),\;\boldsymbol{P}_{1}=\left(1,1,1\right),\;\boldsymbol{P}_{2}=\left(2,0.5,0\right)$$
$$\boldsymbol{P}_{3}=\left(3,0.5,0\right),\;\boldsymbol{P}_{4}=\left(0.5,1.5,0\right),\;\boldsymbol{P}_{5}=\left(1.5,0,1\right)$$</p>
lead to this result:<br /><br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/bezier_3d.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="472" data-original-width="600" src="https://carlonluca.github.io/isogeometric-analysis/images/bezier_3d.svg.png" width="100%" /></a></div><br /><br />
It may also be interesting to see what happens to a curve when a new control point is added to the previous one:<br /><br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/bezier_deg.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="800" data-original-width="794" height="0" width="100%" src="https://carlonluca.github.io/isogeometric-analysis/images/bezier_deg.svg.png" /></a></div>
Another example is provided for Bezier surfaces. From these control points:<br /><br />
<p align="center">$$\boldsymbol{P}_{0}=\left(-3,0,2\right),\;\boldsymbol{P}_{1}=\left(-2,0,6\right),\;\boldsymbol{P}_{2}=\left(-1,0,7\right),\boldsymbol{P}_{3}=\left(0,0,2\right)$$
$$\boldsymbol{P}_{4}=\left(-3,1,2\right),\;\boldsymbol{P}_{5}=\left(-2,1,4\right),\;\boldsymbol{P}_{6}=\left(-1,1,5\right),\;\boldsymbol{P}_{7}=\left(0,1,2.5\right)$$
$$\boldsymbol{P}_{8}=\left(-3,3,0\right),\;\boldsymbol{P}_{9}=\left(-2,3,2.5\right),\;\boldsymbol{P}_{10}=\left(-1,3,4.5\right),\;\boldsymbol{P}_{11}=\left(0,3,6.5\right)$$</p><br /><br />
this is what the algorithms produce:<br /><br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/bezier_surf.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="478" data-original-width="600" src="https://carlonluca.github.io/isogeometric-analysis/images/bezier_surf.svg.png" width="100%" /></a></div>
<h2 style="text-align: left;">Typescript Implementation</h2>
What about a browser implemenation? The above algorithms can clearly be implemented in a browser, so this is an attempt written in TypeScript: <a href="https://github.com/carlonluca/isogeometric-analysis/tree/master/ts/src/bezier" target="_blank">https://github.com/carlonluca/isogeometric-analysis/tree/master/ts/src/bezier</a>.
The BezierCurve object can be used to draw a plot of the first examples:<br /><br />
<a name='more'></a>
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; margin: auto; width: 100%;"><div id="bezierCanvas1" style="margin: auto; width: 98%;"></div></div><br />
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; margin: auto; width: 100%;"><div id="bezierCanvas2" style="margin: auto; width: 98%;"></div></div>
<br />
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; margin: auto; width: 100%;"><div id="bernsteinCanvas" style="margin: auto; width: 98%;"></div></div>
<br /><br />
The BezierSurf instead can be used to compute the surface example:<br /><br />
<div style="background: white; border: 1px solid rgb(255, 154, 2); display: block; margin: auto; width: 100%;"><div id="bezierCanvas3" style="margin: auto; width: 98%;"></div></div><br />
The TypeScript implementation is rendering the plots using <a href="https://plotly.com/javascript/" target="_blank">Plotly</a>.
The demo embedded into this post can be found in this <a href="https://carlonluca.github.io/isogeometric-analysis/bezier.html">GitHub page</a>.Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-85036113117305338622021-04-27T23:07:00.005+02:002021-08-19T14:24:36.322+02:00Isogeometric Analysis and Finite Element Method<script type="text/x-mathjax-config">
MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']], processEscapes: true}}); </script> <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"> </script>
It's been some years since I completed my dissertation on FEM and Isogeometric Analysis, but I realised I never had the time to organise my code properly and archive it. So I archived a part of it in a new repo here: <a href="https://github.com/carlonluca/isogeometric-analysis" target="_blank">https://github.com/carlonluca/isogeometric-analysis</a>. It may be useful for someone studying the topic.<br /><br />
The main topic of the dissertation is not the Finite Element Method (FEM) actually, but the first and the second chapters present it and I wrote a basic implementation that works for 1D problems here: <a href="" target="_blank">https://github.com/carlonluca/isogeometric-analysis/blob/master/2.3/drawFEM1DExample.m</a>. The first example uses the implementation to compute an approximation using FEM.<br /><br />
<h2>Problem</h2>
In the code, the first example solves the differential equation:<br /><br />
<p align="center">$$\left\{ \begin{array}{ll}
\frac{d^{2}u(x)}{dx^{2}}=10 & \forall x\in\Omega=\left(0,1\right)\\
u(x)=0 & x=0\\
u(x)=1 & x=1
\end{array}\right.$$</p><br />
<h2>Exact solution</h2>
It is possible to find an exact solution by integrating both parts twice:<br /><br />
<p align="center">$$\iint_{\Omega}u''(x)dxdx=\iint_{\Omega}10dxdx\Rightarrow u(x)=5x^{2}+c_{1}x+c_{2}$$</p><br />
The solution of the system:<br /><br />
<p align="center">$$\left\{ \begin{array}{ll}
u(x)=5x^{2}+c_{1}x+c_{2} & \forall x\in\Omega=\left(0,1\right)\\
u(x)=0 & x=0\\
u(x)=1 & x=1
\end{array}\right.$$</p><br />
is the exact solution to the problem:<br /><br />
<p align="center">$$u(x)=x\cdot(5x-4)$$</p>
<h2>Weak Formulation</h2>
To calculate the weak formulation we need to first define a Dirichlet lift, as the boundary conditions are non-homogeneous:<br /><br />
<p align="center">$$u(x)=\gamma(x)+v(x)\Rightarrow(\gamma(x)+v(x))''=10$$</p><br />
Multiply by a test function $\varphi\in C_{0}^{\infty}(\Omega)$:<br /><br />
<p align="center">$$(\gamma(x)+v(x))''\cdot\varphi(x)=10\cdot\varphi(x)$$</p><br />
Now integrate both parts:<br /><br />
<p align="center">$$\int_{\Omega}(\gamma(x)+v(x))''\cdot\varphi(x)dx=\int_{\Omega}10\cdot\varphi(x)dx$$</p><br />
Using the technique of integration by parts:<br /><br />
<p align="center">$$\int_{a}^{b}u(x)v'(x)dx=\left[u(x)v(x)\right]_{a}^{b}-\int_{a}^{b}u'(x)v(x)dx$$</p><br />
we can get to:<br /><br />
<p align="center">$$\left[\varphi(x)\left(\gamma(x)+v(x)\right)'\right]_{\Omega}-\int_{\Omega}\varphi'(x)\left(\gamma(x)+v(x)\right)'dx=\int_{\Omega}10\varphi(x)dx$$</p><br />
$\varphi$ is a distribution and it therefore vanishes on the boundary:<br /><br />
<p align="center">$$-\int_{\Omega}\varphi'(x)\left(\gamma(x)+v(x)\right)'dx=\int_{\Omega}10\varphi(x)dx$$</p><br />
It is now possible to define the two terms:<br /><br />
<p align="center">$$a(v,\varphi)=\int_{\Omega}\varphi'(x)v'(x)dx$$
$$l(\varphi)=-\int_{\Omega}\left(\varphi'(x)\gamma'(x)+10\varphi(x)\right)dx$$</p><br />
<h2>Galerkin Method</h2>
At this point, the Galerkin method can be applied if we accept to look for an approximate solution in a space $V_{n}$ of dimension $dim(V_{n})=n$. Thus, assuming $\left\{ v_{i}\right\} _{i=0}^{n-1}$ is a basis for $V_{n}$, then we can write our approx solution:<br /><br />
<p align="center">$$\tilde{v}(x)=\sum_{i=0}^{n-1}\bar{v}_{i}\cdot v_{i}(x)$$</p><br />
where $\left\{ \bar{v}_{i}\right\} _{i=0}^{n-1}$ are coefficients of the linear combination.<br />
We can create a linear system with $n$ independent equations that can be written in matrix form as:<br /><br />
<p align="center">$$\boldsymbol{S}_{n}\cdot\boldsymbol{\Upsilon}_{n}=\boldsymbol{F}_{n}$$</p><br />
where:<br /><br />
<p align="center">$$\boldsymbol{S}_{n}=\left[\int_{0}^{1}v_{i}v_{j}dx\right]_{i,j=0}^{n-1}$$
$$\boldsymbol{\Upsilon}_{n}=\left[\bar{v}_{i}\right]_{i=0}^{n-1}$$
$$\boldsymbol{F}_{n}=\left[-\int_{0}^{1}\left(v_{i}'(x)\gamma'(x)+10\gamma(x)\right)dx\right]_{i=0}^{n-1}$$</p><br />
The basis functions $\left\{ v_{i}\right\} _{i=0}^{n-1}$ can be chosen according to the needs. In the example, simple roof functions are used: <a href="https://github.com/carlonluca/isogeometric-analysis/blob/master/2.3/computePhi.m" target="_blank">https://github.com/carlonluca/isogeometric-analysis/blob/master/2.3/computePhi.m</a> and <a href="https://github.com/carlonluca/isogeometric-analysis/blob/master/2.3/computeDphi.m" target="_blank">https://github.com/carlonluca/isogeometric-analysis/blob/master/2.3/computeDphi.m</a> (note that nomenclature in the code is slightly different). Different approximations can be achieved with a different basis for the space $V_{n}$.<br />
A possible choice for the Dirichlet lift is:<br /><br />
<p align="center">$$\gamma(x)=0\cdot v_{0}(x)+1\cdot v_{n-1}(x)$$</p><br />
which is the one that is used in the example implementation.
<h2>Result</h2>
The example script solves the problem for $n=2,...,7$. As expected with FEM, the approximation is exact at the nodes. By increasing the dimension of the space where the solution is to be found, the approximation gets closer to the exact curve.
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/fem_h_refinement_1.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="800" data-original-width="794" width="100%" src="https://carlonluca.github.io/isogeometric-analysis/images/fem_h_refinement_1.svg.png" /></a></div>
<h2>Lagrange Polynomials</h2>
In the previous implementation, roof functions were used. It is possible to use piecewise-polynomials of higher order. One possible implementation is Lagrange polynomials.<br /><br />
<p align="center">$$l_{Lag,i}\left(\xi\right)={\displaystyle \prod_{1\leq j\leq p_{m}+1,j\neq i}\dfrac{\left(\xi-y_{j}\right)}{\left(y_{i}-y_{j}\right)},\;i=1,2,\ldots,p_{m}+1}$$</p><br />
In the repo there is a sample implementation. The demo draws Lagrange polynomials interpolating an increasing number of points:<br /><br />
<div class="separator" style="clear: both;"><a href="https://carlonluca.github.io/isogeometric-analysis/images/lagrange.svg.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="527" data-original-width="800" src="https://carlonluca.github.io/isogeometric-analysis/images/lagrange.svg.png" width="100%" /></a></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-65001439344830322482021-03-01T13:19:00.004+01:002021-06-15T23:28:34.086+02:00Versioning and CI/CD on a Raspberry Pi (or other arm embedded devices)<h2 style="text-align: left;">Blog</h2>It's been many years now since I started to use a Pi as a version control server. I recently even started to use it more heavily for my development, using it for running my unit tests and for CI/CD. I list here the alternatives I tested and the results.<br /><h2 style="text-align: left;">Subversion</h2>The first version control system that I used on the Pi was SVN. It does not probably make much sense to use SVN as a version control service in 2021, but I still have old SVN repos that I do not want to migrate to git. If this is the case for you as well, user krisdavison prepared a docker image that includes a SVN server with a web server to browse the repos: <a href="https://hub.docker.com/r/krisdavison/svn-server">https://hub.docker.com/r/krisdavison/svn-server</a>. Unfortunately, krisdavison is only providing amd64 images, so I created my own fork, including images for armv7, arm64, x86 and x64, which should cover Pi versions from 2 to 4: <a href="https://hub.docker.com/r/carlonluca/docker-svn">https://hub.docker.com/r/carlonluca/docker-svn</a>.<br />If you prefer, Raspbian also offers the SVN server package and WebSVN for browsing.<br /><h2 style="text-align: left;">Gitea</h2>At the beginning, I simply installed git in my Raspbian to be able to push to remotes stored in my pi. This was quick, worked well and I could also browse with GitWeb <a href="https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb">https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb</a>. Raspbian includes all you need to setup git and GitWeb on Apache.<br /><br />After some time though, I started to feel this was a bit restrictive. I could benefit from an issue tracker, a better browser experience with syntax highlighting etc... Therefore, I started to think about installing GitLab on my Pi. On my first Pi 2, this was difficult and, as a matter of fact, impossible, due to hardware limitations (it was taking minutes to load the first login page). 1GB of RAM, with other services running, is not enough for GitLab, so I started to look for other options and I found Gitea: <a href="https://gitea.io">https://gitea.io</a>. Gitea is an excellent git service written in Go, it does not provide all the features GitLab offers, but is incredibly fast and requires much much less RAM. Unfortunately, the Gitea team was not providing a docker arm image for my Pi (<a href="https://hub.docker.com/r/gitea/gitea">https://hub.docker.com/r/gitea/gitea</a>), so I started to build my own fork for x86, amd64, armv6, armv7 and armv8. For Pi 2, the armv7 image was working perfectly fine: <a href="https://hub.docker.com/r/carlonluca/gitea">https://hub.docker.com/r/carlonluca/gitea</a>.<br /><br />Gitea is a great self-hosted service if you are running on a Pi. It is a git service with many features, it is fast and it is lightweight.<br /><h2 style="text-align: left;">GitLab</h2>Unfortunately, all good things come to an end :-( and my glorious Pi 2 died in a tragical stormy summer night. RIP. I therefore "had" to switch to a shiny new Pi 4, with 4GB of RAM. This led me to think: "hey, what about GitLab now"?!<br />It seems GitLab is not currently providing docker images for arm64 (or any other arm variant): <a href="https://hub.docker.com/r/gitlab/gitlab-ce">https://hub.docker.com/r/gitlab/gitlab-ce</a>. I therefore built my own image for arm64: <a href="https://hub.docker.com/r/carlonluca/gitlab">https://hub.docker.com/r/carlonluca/gitlab</a>. The result is awesome. GitLab is a bit heavy, but it works well. Follow the same instructions of the original image (<a href="https://docs.gitlab.com/omnibus/docker">https://docs.gitlab.com/omnibus/docker</a>) and everything should work. It is a bit slower than Gitea, much heavier, but has more to offer. In particular, package repos and the docker registry can be very handy.<div>Reference repo for GitLab docker image is <a href="https://github.com/carlonluca/docker-gitlab">https://github.com/carlonluca/docker-gitlab</a>.<br /><h2 style="text-align: left;">Jenkins</h2>Another interesting topic in software development is continuous integration and deployment. As I'm used to Jenkins, this is what I looked into at first. There is a good official docker image for Jenkins: <a href="https://hub.docker.com/r/jenkins/jenkins">https://hub.docker.com/r/jenkins/jenkins</a>. Unfortunately, atm, the image is only provided for amd64. I therefore, again, forked and created my arm64 image: <a href="https://hub.docker.com/r/carlonluca/jenkins">https://hub.docker.com/r/carlonluca/jenkins</a>. On my Pi 4, Jenkins behaves fine. You can also create other docker containers in your Pi and communicate with those containers from the Jenkins container. Everything seems to be working fine.<br /><h2 style="text-align: left;">GitLab Runner</h2>After some time, I wanted to also try the CI/CD feature included in my GitLab arm64 image. I therefore created a few gitlab configurations and configured a GitLab runner on the same Pi 4. The configuration of the runner was a bit tricky, but seems to be possible. In particular I had troubles using my internal DNS service, but host networking for the runner seems to work so far. Luckily, the runner is already available for arm64: <a href="https://hub.docker.com/r/gitlab/gitlab-runner">https://hub.docker.com/r/gitlab/gitlab-runner</a>. I created a configuration for a node app and created a CI configuration using a mongo docker image for running my unit tests. Everything worked properly. So you can have your node + angular apps versioned and tested on your arm64 Pi.<br /><h2 style="text-align: left;">Dind</h2>Of course, I also wanted to create a docker image for my node app. So I tried to use the dind service included in GitLab, to see if it could be used on the Pi properly. Yes, it worked :-) So you can have your app versioned on the Pi, tested on the Pi, dockerized on your Pi and uploaded to docker hub or the GitLab registry on the Pi.<br /><h2 style="text-align: left;">Multiarch</h2>The image resulting from the previous step worked great, it can be installed and used properly... on arm64. Also, the images I listed above are pretty long to build and maintain. Gitea, in particular, needs a long building process on an Intel Xeon, because the simplest procedure needs emulators for cross-arch building. Also, I have a slow Internet service, which is even slower when uploading. I was wondering if it could be possible to do all this on the Pi and let it build and transfer for me, instead of keeping my main machine busy... Yes, it is technically possible :-) qemu seems to be able to emulate other arm archs and amd64 on an arm64 kernel.<br />To do this, I needed an image including docker and buildkit for arm64: I couldn't find one, so I created one for me: <a href="https://hub.docker.com/r/carlonluca/docker-multiarch">https://hub.docker.com/r/carlonluca/docker-multiarch</a>. At this point I wrote the gitlab CI file and tested. Unfortunately, I got less encouraging results this time: I got many types of failures, probably due to several unrelated causes. I could however identify some:<br /><ul style="text-align: left;"><li><b>slow Internet connection</b>: it seems that docker or buildkit have too short timeouts. Couldn't find a way to set the timeout, but reducing concurrency of builds reduced the frequency of errors (see below).</li><li><b>ubuntu binfmt not properly working</b> in some cases: I used this project this fix this issue: <a href="https://hub.docker.com/r/tonistiigi/binfmt">https://hub.docker.com/r/tonistiigi/binfmt</a>. I use it in all my GitLab CI files.</li><li>buildx building with <b>high concurrency</b>: the authors tried to make full use of the build machine by building the images concurrently. This is reasonable, but... they are not currently providing a way to reduce or remove concurrency when needed... which is less reasonable. On the Pi, concurrent complex builds are difficult/impossible. If a single build requires much RAM, 4 builds concurrently over emulators require really too much RAM. The only way I found to build sequentially is to build and push each arch separately, and then use the manifest tool to merge. Here is an example: <a href="https://github.com/carlonluca/darkmediawiki-docker/blob/master/.gitlab-ci.yml">https://github.com/carlonluca/darkmediawiki-docker/blob/master/.gitlab-ci.yml</a>.</li></ul>I'm still working on this topic, but I'm mostly able to multiarch-build on my Pi with GitLab CI/CD. All the docker images I listed above are built this way, including the docker-multiarch image, which requires itself to build itself :-) this is a handy way of keeping them up to date. The only partial exception is Gitea: the build procedure of the image also builds Gitea itself, and there seems to be an issue building for x86. The other archs seem to properly build.<br /><br />This is a list of the images I'm currently using on my Pi 4 in this context:<br />* <a href="https://hub.docker.com/r/carlonluca/docker-svn">https://hub.docker.com/r/carlonluca/docker-svn</a><br />* <a href="https://hub.docker.com/r/carlonluca/gitea">https://hub.docker.com/r/carlonluca/gitea</a><br />* <a href="https://hub.docker.com/r/carlonluca/gitlab">https://hub.docker.com/r/carlonluca/gitlab</a><br />* <a href="https://hub.docker.com/r/carlonluca/jenkins">https://hub.docker.com/r/carlonluca/jenkins</a><br />* <a href="https://hub.docker.com/r/gitlab/gitlab-runner">https://hub.docker.com/r/gitlab/gitlab-runner</a><br />* <a href="https://hub.docker.com/r/carlonluca/docker-multiarch">https://hub.docker.com/r/carlonluca/docker-multiarch</a><br /><br /><br />Have fun! ;-)<br /></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-40064803604903098192020-07-17T13:06:00.003+02:002021-03-16T23:42:47.417+01:00Serialize/Deserialize JSON Representations to Qt Objects (QObject's) in C++<div>Calls to HTTP servers are very frequent nowadays, and JSON is frequently used when dealing with structured data. When I write applications in Java/Kotlin, I always use retrofit2 with gson integration, or similar approaches. It is very comfortable to be able to serialize/deserialize to Java objects automatically. I tried to find something similar for Qt, but I couldn't find much. JSON support in Qt is good, but does not seem to be able to map QOject's to QJSonObject. I also could not find other C++ libraries doing this. Probably the difficulty of implementing reflection in C++ would make the implementation a bit convoluted. A good candidate I found is this: <a href="https://github.com/Loki-Astari/ThorsSerializer">https://github.com/Loki-Astari/ThorsSerializer</a>, which seems not to require much boilerplate code, not too verbose and no generated code.</div><div><br /></div><div>However, Qt includes the meta object system (<a href="https://doc.qt.io/qt-5/metaobjects.html">https://doc.qt.io/qt-5/metaobjects.html</a>), and therefore I tried to use it to get the desired result. In a couple of hours I got to a pretty decent result: <a href="https://github.com/carlonluca/lqobjectserializer">https://github.com/carlonluca/lqobjectserializer</a>. It is far from perfect, but it seems to work. Have a look at the readme or the unit tests to know more.</div><div>The draft is free to use: you can contribute, report bugs etc...</div><div><br /></div><div>For instance, a JSON object like this:</div><div><br /></div><div><font color="#6aa84f" face="courier" size="2">{"menu": {</font></div><div><font color="#6aa84f" face="courier" size="2"> "header": "SVG Viewer",</font></div><div><font color="#6aa84f" face="courier" size="2"> "items": [</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "Open"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "OpenNew", "label": "Open New"},</font></div><div><font color="#6aa84f" face="courier" size="2"> null,</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "ZoomIn", "label": "Zoom In"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "ZoomOut", "label": "Zoom Out"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "OriginalView", "label": "Original View"},</font></div><div><font color="#6aa84f" face="courier" size="2"> null,</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "Quality"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "Pause"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "Mute"},</font></div><div><font color="#6aa84f" face="courier" size="2"> null,</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "Find", "label": "Find..."},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "FindAgain", "label": "Find Again"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "Copy"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "CopyAgain", "label": "Copy Again"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "CopySVG", "label": "Copy SVG"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "ViewSVG", "label": "View SVG"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "ViewSource", "label": "View Source"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "SaveAs", "label": "Save As"},</font></div><div><font color="#6aa84f" face="courier" size="2"> null,</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "Help"},</font></div><div><font color="#6aa84f" face="courier" size="2"> {"id": "About", "label": "About Adobe CVG Viewer..."}</font></div><div><font color="#6aa84f" face="courier" size="2"> ]</font></div><div><font color="#6aa84f" face="courier" size="2">}}</font></div><div><br /></div><div>can be deserialized to a QObject simply by defining the classes (macros here are inherited by my other project <a href="https://github.com/carlonluca/lqtutils">https://github.com/carlonluca/lqtutils</a>, but this is not mandatory):</div><div><br /></div><div><font color="#6aa84f" face="courier" size="2">L_BEGIN_CLASS(Item)</font></div><div><font color="#6aa84f" face="courier" size="2">L_RW_PROP(QString, id, setId, QString())</font></div><div><font color="#6aa84f" face="courier" size="2">L_RW_PROP(QString, label, setLabel, QString())</font></div><div><font color="#6aa84f" face="courier" size="2">L_END_CLASS</font></div><div><font color="#6aa84f" face="courier" size="2"><br /></font></div><div><font color="#6aa84f" face="courier" size="2">L_BEGIN_CLASS(Menu)</font></div><div><font color="#6aa84f" face="courier" size="2">L_RW_PROP(QString, header, setHeader)</font></div><div><font color="#6aa84f" face="courier" size="2">L_RW_PROP_ARRAY_WITH_ADDER(Item*, items, setItems)</font></div><div><font color="#6aa84f" face="courier" size="2">L_END_CLASS</font></div><div><font color="#6aa84f" face="courier" size="2"><br /></font></div><div><font color="#6aa84f" face="courier" size="2">L_BEGIN_CLASS(MenuRoot)</font></div><div><font color="#6aa84f" face="courier" size="2">L_RW_PROP(Menu*, menu, setMenu, nullptr)</font></div><div><font color="#6aa84f" face="courier" size="2">L_END_CLASS</font></div><div><br /></div><div>and by writing these few lines:</div><div><br /></div><div><div><font color="#6aa84f" face="courier" size="2">LDeserializer<MenuRoot> deserializer(factory);</font></div><div><font color="#6aa84f" face="courier" size="2">QScopedPointer<MenuRoot> g(deserializer.deserialize(jsonString));</font></div></div><div><br /></div><div>Please leave a comment if you know of other tools in this context, serializing and deserializing JSON is very frequent.</div><div>Bye! ;-)</div><div><br /></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-91434270590553073492020-06-14T00:15:00.002+02:002020-06-14T00:19:03.349+02:00Synthesize Qt Settings<div>I frequently create classes that I use as an interface to settings in my apps. Using a single class with accessors makes the code readable, safer and simple to maintain. Unfortunately, doing this requires to create getters and setters for every entry in the settings file, which is a bit bothering. Also, QSettings is not a QObject and cannot provide signals to notify changes.</div><div><br /></div><div>My use cases are typically very simple, so I created a couple of macros that synthesise classes for me. Macros synthesise a reentrant class that can be used to access settings and a notifier, that can be used to get notifications of the changes. An example of definition of the class is:</div><div><br /></div><div><font color="#0b8043" size="2">L_DECLARE_SETTINGS(LSettingsTest, new QSettings("settings.ini", QSettings::IniFormat))</font></div><div><font color="#0b8043" size="2">L_DEFINE_VALUE(QString, string1, QString("string1"), toString)</font></div><div><font color="#0b8043" size="2">L_DEFINE_VALUE(QSize, size, QSize(100, 100), toSize)</font></div><div><font color="#0b8043" size="2">L_DEFINE_VALUE(double, temperature, -1, toDouble)</font></div><div><font color="#0b8043" size="2">L_DEFINE_VALUE(QByteArray, image, QByteArray(), toByteArray)</font></div><div><font color="#0b8043" size="2">L_END_CLASS</font></div><div><font color="#0b8043" size="2"><br /></font></div><div><font color="#0b8043" size="2">L_DECLARE_SETTINGS(LSettingsTestSec1, new QSettings("settings.ini", QSettings::IniFormat), "SECTION_1")</font></div><div><font color="#0b8043" size="2">L_DEFINE_VALUE(QString, string2, QString("string2"), toString)</font></div><div><font color="#0b8043" size="2">L_END_CLASS</font></div><div><br /></div><div>this will let you instantiate objects of class LSettingsTest and LSettingsTestSec1, and access entries with strong typed methods. Also, by calling LSettingsTest::notifier(), you can get a reference to the unique notifier. By setting an instance as a context property, you can get notifications and you can update settings from QML. You can find some more info in the repo <a href="https://github.com/carlonluca/lqtutils">https://github.com/carlonluca/lqtutils</a> and an example using Qt Quick here: <a href="https://github.com/carlonluca/lqtutils/tree/master/LQtUtilsQuick">https://github.com/carlonluca/lqtutils/tree/master/LQtUtilsQuick</a>.</div><div>Bye! ;-)</div><div><br /></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-20353127652758563052020-05-28T19:31:00.003+02:002020-06-14T00:17:18.937+02:00Synthesize Qt propertiesThe are some utils that I use in most of my Qt projects. I'm a bit fed up of copy-pasting those every time I need something, so I created a project containing tools that are of frequent use when I write Qt apps, regardless of the type of app.<div><br />The only interesting tool I added yet is the synthesizer of Q_PROPERTY's. You can use the macros:<div><pre style="text-align: left;"><font color="#0b8043" size="2">L_RW_PROP<br />L_RO_PROP</font></pre>to synthétise props, with getter, setter and notifications. Each macro is overloaded: with 3 params, you do not have initialisation, adding a 4th param, also initialises the variable to the provided value. Also, I frequently need QObject that are just containers of properties, to be used in QML. I added these two macros to spare some lines:</div><div><pre style="text-align: left;"><font color="#0b8043" size="2">L_BEGIN_CLASS(<class_name>)<br />L_END_CLASS</font></pre></div><div>A class like:</div><div style="text-align: left;"><pre><font color="#0b8043" size="2">class Fraction : public QObject<br />{<br /> Q_OBJECT<br /> Q_PROPERTY(double numerator READ numerator WRITE setNumerator NOTIFY numeratorChanged)<br /> Q_PROPERTY(double denominator READ denominator WRITE setDenominator NOTIFY denominatorChanged)<br />public:<br /> Fraction(QObject* parent = nullptr) : QObject(parent) {}<br /> double numerator() const {<br /> return m_numerator;<br /> }<br /> double denominator() const {<br /> return m_denominator;<br /> }<br />public slots:<br /> void setNumerator(double numerator) {<br /> if (m_numerator == numerator)<br /> return;<br /> m_numerator = numerator;<br /> emit numeratorChanged(numerator);<br /> }<br /> void setDenominator(double denominator) {<br /> if (m_denominator == denominator)<br /> return;<br /> m_denominator = denominator;<br /> emit denominatorChanged(denominator);<br /> }<br />signals:<br /> void numeratorChanged(double numerator);<br /> void denominatorChanged(double denominator);<br />private:<br /> double m_numerator;<br /> double m_denominator;<br />};</font></pre></div><div style="text-align: left;">can be simplified to:</div><div style="text-align: left;"><pre style="text-align: left;"><font color="#0b8043" size="2">L_BEGIN_CLASS(Fraction)<br />L_RW_PROP(double, numerator, setNumerator)<br />L_RW_PROP(double, denominator, setDenominator)<br />L_END_CLASS</font></pre></div><div style="text-align: left;">I'm sure there are other similar approaches out there, but if you need it, you can simply add this repo as a submodule like I do: <a href="https://www.blogger.com/#">https://github.com/carlonluca/lqtutils</a>.</div><div>Bye! ;-)</div></div>Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-77050007718911802622019-09-09T19:10:00.001+02:002019-09-09T19:10:38.298+02:00Raspbian Buster and Cross Toolchain for Linux and Mac OS 8.3.0Raspbian Buster is out. It seems it updated gcc from version 6.3.0 (used for Stretch) to gcc version 8.3.0. This is not always needed, but I had a lot of problems in the past related to using an outdated crosscompiler, or the one provided in the raspberry repo: <a href="https://github.com/raspberrypi/tools">https://github.com/raspberrypi/tools</a>. I therefore built my own toolchain for Stretch, which I provided <a href="http://thebugfreeblog.blogspot.com/2017/11/raspbian-stretch-and-cross-toolchain.html">here</a>, both for Linux and Mac OS.<br />
<br />
I did the same for Buster: I built my own toolchain and I built many projects with it, like Qt, ffmpeg etc... Just place the toolchain in /opt/rpi (probably position independent) and you should be done. This toolchain should be 100% compatible with gcc provided by Buster.<br />
<br />
Download cross toolchain GCC 6.3.0 for Stretch <a href="http://thebugfreeblog.blogspot.com/2017/11/raspbian-stretch-and-cross-toolchain.html">here</a>.<br />
Download Linux x64 cross toolchain GCC 8.3.0 <a href="https://bugfreeblog.page.link/rasplinuxgcc830">here</a>.<br />
Download Mac OS cross toolchain GCC 8.3.0 <a href="https://bugfreeblog.page.link/raspmacgcc830">here</a>.<br />
<br />
Bye ;-)Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com49tag:blogger.com,1999:blog-3944174827064012298.post-39025647974498214422018-03-04T23:55:00.000+01:002018-03-05T00:09:35.635+01:00Yocto Recipe for Accelerated Video Playback with Qt on Raspberry PiRaspberry has a huge community that creates a considerable amount of material in a large number of projects. A relevant support for Yocto cannot therefore be missing for it. Months ago I started to work on using Yocto to create images for the Raspberry Pi. Unfortunately I had to stop for a few months to work on other projects, so the result could not be published immediately: the project is based on Pyro while current Yocto release is Rocko. The concept is however similar.<br />
<br />
I created a test image for the Raspberry Pi 3 board, using the best compilation flags I found available, and added a recipe for POT to include hardware acceleration in Qt. The result is good: just invoke qmlscene on a little QML code and you have a hardware accelerated OpenGL scene rendering video with Qt API (QML) in your Yocto image.<br />
<br />
You can find the layer here: <a href="https://github.com/carlonluca/meta-pot">https://github.com/carlonluca/meta-pot</a>. It is based on the POT project that can be found here: <a href="https://github.com/carlonluca/pot">https://github.com/carlonluca/pot</a>.<br />
<h2>
Images</h2>
In the repo I also added a couple of examples of images I created for me. I'll improve those in case I'll find the time to do it.<br />
<br />
All you have to do is include the recipe and POT will be installed in the image (satisfy the dependencies if some were missing).<br />
<h2>
Example</h2>
I created some images using this setup (I included many things that are not mandatory at all for POT):<br />
<br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">BBLAYERS ?= " \<br /> ${WORKSPACE}/poky-pyro/meta \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-poky \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-openembedded/meta-oe \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-openembedded/meta-multimedia \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-openembedded/meta-networking \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-openembedded/meta-python \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-raspberrypi-crypto \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-qt5 \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-oracle-java \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-java \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/poky-pyro/meta-office \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">${WORKSPACE}/meta-pot \</span></span><br />
<span style="color: #38761d;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">"</span></span><br />
<br />
in my layer.conf I placed:<br />
<br />
<span style="color: #38761d; font-family: "courier new" , "courier" , monospace; font-size: x-small;">LICENSE_FLAGS_WHITELIST = "commercial oracle_java" <br />DISTRO_FEATURES = "ext2 ext3 ext4 pam gles2 usbhost ${DISTRO_FEATURES_LIBC}" <br />DISTRO_FEATURES_BACKFILL_CONSIDERED += "pulseaudio" <br />PACKAGE_CLASSES = "package_deb" <br />IMAGE_FEATURES += "package-management ssh-server-openssh" <br />DISTRO_FEATURES_remove = "X11 wayland" <br />EXTRA_IMAGE_FEATURES = "debug-tweaks dev-pkgs tools-sdk tools-debug"<br />PREFERRED_PROVIDER_jpeg = "libjpeg-turbo" <br />PREFERRED_PROVIDER_jpeg-native = "libjpeg-turbo-native" <br />PREFERRED_PROVIDER_udev = "eudev" <br />PREFERRED_PROVIDER_virtual/java-initial-native = "cacao-initial-native" <br />PREFERRED_PROVIDER_virtual/java-native = "cacao-native"<br />PREFERRED_PROVIDER_virtual/javac-native = "ecj-bootstrap-native" <br />VIRTUAL_RUNTIME_init_manager = "sysvinit" <br />MACHINE_FEATURES_remove = "apm" <br />IMAGE_FSTYPES ?= "rpi-sdimg" <br />MACHINE = "raspberrypi3" <br />DISTRO = "poky"</span><br />
<br />
At this point you can use something like pot-minimal (https://github.com/carlonluca/meta-pot/blob/master/images/pot-minimal.bb) and you should have a working image.<br />
<br />
You can test it pretty simply by using a trivial QML like this:<br />
<br />
<span style="color: #38761d; font-family: "courier new" , "courier" , monospace; font-size: x-small;">import QtQuick 2.2 <br />import QtMultimedia 5.5 <br /> <br />Rectangle { <br /> color: "orange" <br /> <br /> Video { <br /> autoLoad: true <br /> autoPlay: true <br /> source: "file:///home/root/bbb_3m.mov" <br /> anchors.fill: parent <br /> }<br />}</span><br />
<br />
and you should see your video in the QML scene right away with the command:<br />
<div>
<br /></div>
<div>
<span style="color: #38761d; font-family: "courier new" , "courier" , monospace; font-size: x-small;">qmlscene -platform eglfs main.qml</span></div>
<div>
<br />
<h2>
Optimization</h2>
I wanted to also create an image fully optimized for the Raspberry Pi 3 board, which is a Cortex-A53 armv8-a architecture which includes crc and new A64, A32, and T32 instructions to Advanced SIMD that accelerate Advanced Encryption Standard (AES) encryption and decryption, and the Secure Hash Algorithm (SHA) functions SHA-1, SHA-224, and SHA-256. Still I wanted a fully 32-bit system as hardware libraries are only supported for this bitness. To do this I had to apply a few patches to the Yocto repos. I uploaded every patch to these forks:<br />
<br />
<a href="https://github.com/carlonluca/poky.git">https://github.com/carlonluca/poky.git</a> (branch: pyro_cortexa53)<br />
<a href="https://github.com/carlonluca/meta-raspberrypi">https://github.com/carlonluca/meta-raspberrypi</a> (branch: pyro_cortexa53)<br />
<br />
Bye! ;-)</div>
Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com13tag:blogger.com,1999:blog-3944174827064012298.post-7309939729137783842018-01-02T17:55:00.000+01:002018-01-02T17:55:24.635+01:00POT 5.7.0 with Qt 5.10.0 built for armv8 with GCC 6.3.0 on Raspbian StretchThis was a good test for my <a href="http://thebugfreeblog.blogspot.it/2017/11/raspbian-stretch-and-cross-toolchain.html">cross toolchain with gcc 6.3.0</a> I uploaded some days ago: the new Qt 5.10.0 built with <span style="font-family: Courier New, Courier, monospace;">-march=armv8-a -mtune=cortex-a53 -mfpu=crypto-neon-fp-armv8 -mfloat-abi=hard</span>, including POT for video acceleration on Raspbian Stretch. The build includes most Qt modules plus Qt WebKit (the modernized QtWebKit from <br />Konstantin Tokarev, version 5.212, <a href="https://github.com/annulen/webkit">https://github.com/annulen/webkit</a>) plus QtWebEngine 5.9.1, a bit patched to build here. I didn't test browsers much, you'll have to work on those yourself if you need them.<br />
<br />
By using the Qt build and the cross toolchain you can build your own applications.<br />
<br />
Download <a href="https://goo.gl/kUuqMg">here</a> the build for Qt 5.10.0 with POT 5.7.<br />
Download <a href="http://thebugfreeblog.blogspot.it/2017/11/raspbian-stretch-and-cross-toolchain.html">here</a> the cross toolchain.Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com60tag:blogger.com,1999:blog-3944174827064012298.post-50426498915344835832017-11-24T00:04:00.002+01:002017-11-24T00:09:05.036+01:00Raspbian Stretch and Cross Toolchain for Linux and Mac OSRaspbian Stretch is out for Raspberry Pi. I needed a cross toolchain with the same exact version used to build the system so I built my own. As I had my script ready, I also tried to build one for Mac OS and it seems to work for the moment. I tested these cross toolchains for my projects and seemed to be able to build everything that I tried: Qt libs, apps, omxplayer, ffmpeg etc...<br />
<br />
Download Linux x64 cross toolchain GCC 6.3.0 for Stretch <a href="https://goo.gl/N8M9hM">here</a>.<br />
Download Mac OS cross toolchain GCC 6.3.0 for Stretch <a href="https://goo.gl/vWnLMJ">here</a>.<br />
<br />
<u>NOTE</u>: The Mac OS version requires some packages to be installed from macports.<br />
<u>NOTE</u>: The toolchain is built to crossbuild for armv7-a. I could also build for armv8 but not sure if it also works for armv6.<br />
<br />
Have fun! Bye! ;-)Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com11tag:blogger.com,1999:blog-3944174827064012298.post-5281601632622965492017-06-03T10:51:00.001+02:002017-06-03T10:51:18.829+02:00Mounting Shared Directories on Ubuntu Running on VMWareThis post is mostly for myself :-) This was very simple years ago; actually it was automatic. Now, I have no idea why, but shared directories are not automatically mounted anymore. By searching online it is incredibly difficult to find a proper answer: I tried a million answers but none was working properly. The only one that worked is simply the shortest and the one I never remember for some reason (and also difficult to find) :-):<br /><br /><span style="color: #38761d; font-family: Courier New, Courier, monospace;">vmhgfs-fuse /mount/dir</span><br /><div>
<br /></div>
<div>
this is how I do it, and it works for me. No idea why the other techniques are not.</div>
Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com0tag:blogger.com,1999:blog-3944174827064012298.post-60115143594786449752017-03-19T11:15:00.002+01:002021-09-01T00:08:22.727+02:00Experimenting with Pi3 optimisations - POT 5.6.0-beta1 with Qt 5.8.0 built for armv8 with GCC 4.9.4At the moment I still don't want to test custom firmwares or 64 bit arch builds, but I started to test a couple of new features: a new compiler from Linaro (the one provided by the foundation keeps giving me headaches), version 4.9.4 instead of 4.8, and optimised compiler flags for the Rapsberry Pi 3, which is an armv8.<br />
In this build, Qt, ffmpeg and POT are all built with 4.9.4 Linaro toolchain and optimised compiler flags for Pi3. <b>This will only work on Pi3</b>.<br />
You won't probably see much difference in GPU intensive apps, but it is a step on the road of optimisation!<br />
<br />
Have fun! Bye! ;-)<br />
<br />
Download the toolchain <a href="https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabihf/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz">here</a>.<br />
Download POT 5.6.0-beta1 for Raspbian Jessie Lite Pi3 <a href="https://polr.luc4.duckdns.org/qt-560-pot-520">here</a> (md5: 0eec41ef02e9369fc7e569030b8ff868).Luca Carlonhttp://www.blogger.com/profile/05071568155815750619noreply@blogger.com22