[gtk/layout-manager-transform-demo: 2/2] Add another layout manager demo
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/layout-manager-transform-demo: 2/2] Add another layout manager demo
- Date: Sat, 29 Aug 2020 02:59:20 +0000 (UTC)
commit 9209cf4d77ce5a74439a0162aa00748a59e3a839
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Aug 28 07:45:57 2020 -0400
Add another layout manager demo
This demo uses transforms to place icons on a sphere.
Still to do: backface culling, keynav instead of fixed
speed animation.
demos/gtk-demo/demo.gresource.xml | 7 +
demos/gtk-demo/demo2layout.c | 98 ++++---
demos/gtk-demo/demo2widget.c | 2 +-
demos/gtk-demo/four_point_transform.c | 90 ++++++
demos/gtk-demo/four_point_transform.h | 13 +
demos/gtk-demo/layoutmanager2.c | 168 ++++++++++-
demos/gtk-demo/meson.build | 2 +
demos/gtk-demo/singular_value_decomposition.c | 396 ++++++++++++++++++++++++++
demos/gtk-demo/singular_value_decomposition.h | 17 ++
tests/simple.c | 144 +++++++++-
10 files changed, 883 insertions(+), 54 deletions(-)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index d9084a96ae..a374cd0308 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -136,6 +136,12 @@
<file>demochild.h</file>
<file>demochild.c</file>
</gresource>
+ <gresource prefix="/layoutmanager2">
+ <file>demo2layout.h</file>
+ <file>demo2layout.c</file>
+ <file>demo2widget.h</file>
+ <file>demo2widget.c</file>
+ </gresource>
<gresource prefix="/listview_filebrowser">
<file>listview_filebrowser.ui</file>
<file>listview_filebrowser.css</file>
@@ -219,6 +225,7 @@
<file>images.c</file>
<file>infobar.c</file>
<file>layoutmanager.c</file>
+ <file>layoutmanager2.c</file>
<file>links.c</file>
<file>listbox.c</file>
<file>listbox2.c</file>
diff --git a/demos/gtk-demo/demo2layout.c b/demos/gtk-demo/demo2layout.c
index 9eaae52a60..7cf92ba720 100644
--- a/demos/gtk-demo/demo2layout.c
+++ b/demos/gtk-demo/demo2layout.c
@@ -1,5 +1,5 @@
#include "demo2layout.h"
-
+#include "four_point_transform.h"
struct _Demo2Layout
{
@@ -49,6 +49,14 @@ demo2_layout_measure (GtkLayoutManager *layout_manager,
*natural = 3 * natural_size;
}
+
+#define RADIANS(angle) ((angle)*M_PI/180.0);
+
+/* Spherical coordinates */
+#define SX(r,t,p) ((r) * sin (t) * cos (p))
+#define SZ(r,t,p) ((r) * sin (t) * sin (p))
+#define SY(r,t,p) ((r) * cos (t))
+
static void
demo2_layout_allocate (GtkLayoutManager *layout_manager,
GtkWidget *widget,
@@ -56,49 +64,61 @@ demo2_layout_allocate (GtkLayoutManager *layout_manager,
int height,
int baseline)
{
- Demo2Layout *self = DEMO2_LAYOUT (layout_manager);
GtkWidget *child;
- float t = fmodf (self->position, 4.0);
- int x, y;
-
- for (child = gtk_widget_get_first_child (widget);
+ GtkRequisition child_req;
+ int i, j, k;
+ float x0, y0;
+ float w, h;
+ graphene_point3d_t p1, p2, p3, p4;
+ graphene_point3d_t q1, q2, q3, q4;
+ double t_1, t_2, p_1, p_2;
+ double r;
+ graphene_matrix_t m;
+ GskTransform *transform;
+ double offset = DEMO2_LAYOUT (layout_manager)->position;
+
+ gtk_widget_get_preferred_size (gtk_widget_get_first_child (widget), &child_req, NULL);
+ w = child_req.width;
+ h = child_req.height;
+
+ r = 300;
+ x0 = y0 = 300;
+
+ for (child = gtk_widget_get_first_child (widget), i = 0;
child != NULL;
- child = gtk_widget_get_next_sibling (child))
+ child = gtk_widget_get_next_sibling (child), i++)
{
- GtkRequisition child_req;
+ j = i / 36;
+ k = i % 36;
- if (!gtk_widget_should_layout (child))
- continue;
+ graphene_point3d_init (&p1, 0., 0., 1);
+ graphene_point3d_init (&p2, w, 0., 1);
+ graphene_point3d_init (&p3, 0., h, 1);
+ graphene_point3d_init (&p4, w, h, 1);
+
+ t_1 = RADIANS (10 * j);
+ t_2 = RADIANS (10 * (j + 1));
+ p_1 = RADIANS (offset + 10 * k);
+ p_2 = RADIANS (offset + 10 * (k + 1));
+
+ graphene_point3d_init (&q1, x0 + SX (r, t_1, p_1), y0 + SY (r, t_1, p_1), SZ (r, t_1, p_1));
+ graphene_point3d_init (&q2, x0 + SX (r, t_2, p_1), y0 + SY (r, t_2, p_1), SZ (r, t_2, p_1));
+ graphene_point3d_init (&q3, x0 + SX (r, t_1, p_2), y0 + SY (r, t_1, p_2), SZ (r, t_1, p_2));
+ graphene_point3d_init (&q4, x0 + SX (r, t_2, p_2), y0 + SY (r, t_2, p_2), SZ (r, t_2, p_2));
+
+ perspective_3d (&p1, &p2, &p3, &p4,
+ &q1, &q2, &q3, &q4,
+ &m);
+
+ transform = gsk_transform_matrix (NULL, &m);
+
+ /* Since our matrix was built for transforming points with z = 1,
+ * prepend a translation to the z = 1 plane.
+ */
+ transform = gsk_transform_translate_3d (transform,
+ &GRAPHENE_POINT3D_INIT (0, 0, 1));
- gtk_widget_get_preferred_size (child, &child_req, NULL);
-
- if (t < 1.0)
- {
- x = t * (width - child_req.width);
- y = 0;
- }
- else if (t < 2.0)
- {
- t -= 1.0;
- x = (1.0 - t) * (width - child_req.width);
- y = t * (height - child_req.height);
- }
- else if (t < 3.0)
- {
- t -= 2.0;
- x = t * (width - child_req.width);
- y = height - child_req.height;
- }
- else
- {
- t -= 3.0;
- x = (1.0 - t) * (width - child_req.width);
- y = (1.0 - t) * (height - child_req.height);
- }
-
- gtk_widget_size_allocate (child,
- &(const GtkAllocation){ x, y, child_req.width, child_req.height},
- -1);
+ gtk_widget_allocate (child, w, h, -1, transform);
}
}
diff --git a/demos/gtk-demo/demo2widget.c b/demos/gtk-demo/demo2widget.c
index e8e200dd1c..661b701a66 100644
--- a/demos/gtk-demo/demo2widget.c
+++ b/demos/gtk-demo/demo2widget.c
@@ -32,7 +32,7 @@ transition (GtkWidget *widget,
gint64 now = g_get_monotonic_time ();
gtk_widget_queue_allocate (widget);
- demo2_layout_set_position (demo2_layout, (now - self->start_time) / (double)G_TIME_SPAN_SECOND);
+ demo2_layout_set_position (demo2_layout, (now - self->start_time) * 30.0 / ((double)G_TIME_SPAN_SECOND));
return G_SOURCE_CONTINUE;
}
diff --git a/demos/gtk-demo/four_point_transform.c b/demos/gtk-demo/four_point_transform.c
new file mode 100644
index 0000000000..9df10ef163
--- /dev/null
+++ b/demos/gtk-demo/four_point_transform.c
@@ -0,0 +1,90 @@
+#include "four_point_transform.h"
+#include "singular_value_decomposition.h"
+
+/* Make a 4x4 matrix that maps
+ * e1 -> p1
+ * e2 -> p3
+ * e3 -> p3
+ * (1,1,1,0) -> p4
+ */
+static void
+unit_to (graphene_point3d_t *p1,
+ graphene_point3d_t *p2,
+ graphene_point3d_t *p3,
+ graphene_point3d_t *p4,
+ graphene_matrix_t *m)
+{
+ graphene_vec3_t v1, v2, v3, v4;
+ graphene_vec4_t vv1, vv2, vv3, vv4, p;
+ graphene_matrix_t u, s;
+ float v[16] = { 0., };
+ double A[16];
+ double U[16];
+ double S[4];
+ double V[16];
+ double B[4];
+ double x[4];
+ int i, j;
+
+ graphene_point3d_to_vec3 (p1, &v1);
+ graphene_point3d_to_vec3 (p2, &v2);
+ graphene_point3d_to_vec3 (p3, &v3);
+ graphene_point3d_to_vec3 (p4, &v4);
+
+ graphene_vec4_init_from_vec3 (&vv1, &v1, 1.);
+ graphene_vec4_init_from_vec3 (&vv2, &v2, 1.);
+ graphene_vec4_init_from_vec3 (&vv3, &v3, 1.);
+ graphene_vec4_init_from_vec3 (&vv4, &v4, 1.);
+
+ graphene_vec4_init (&p, 0., 0., 0., 1.);
+
+ graphene_matrix_init_from_vec4 (&u, &vv1, &vv2, &vv3, &p);
+
+ /* solve x * u = vv4 */
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ A[j * 4 + i] = graphene_matrix_get_value (&u, i, j);
+
+ B[0] = graphene_vec4_get_x (&vv4);
+ B[1] = graphene_vec4_get_y (&vv4);
+ B[2] = graphene_vec4_get_z (&vv4);
+ B[3] = graphene_vec4_get_w (&vv4);
+
+ singular_value_decomposition (A, 4, 4, U, S, V);
+ singular_value_decomposition_solve (U, S, V, 4, 4, B, x);
+
+ v[ 0] = x[0];
+ v[ 5] = x[1];
+ v[10] = x[2];
+ v[15] = 1;
+
+ graphene_matrix_init_from_float (&s, (const float *)&v);
+ graphene_matrix_multiply (&s, &u, m);
+}
+
+/* Make a 4x4 matrix that maps
+ * p1 -> q1
+ * p2 -> q2
+ * p3 -> q3
+ * p4 -> q4
+ */
+void
+perspective_3d (graphene_point3d_t *p1,
+ graphene_point3d_t *p2,
+ graphene_point3d_t *p3,
+ graphene_point3d_t *p4,
+ graphene_point3d_t *q1,
+ graphene_point3d_t *q2,
+ graphene_point3d_t *q3,
+ graphene_point3d_t *q4,
+ graphene_matrix_t *m)
+{
+ graphene_matrix_t a, a_inv, b;
+
+ unit_to (p1, p2, p3, p4, &a);
+ unit_to (q1, q2, q3, q4, &b);
+
+ graphene_matrix_inverse (&a, &a_inv);
+ graphene_matrix_multiply (&a_inv, &b, m);
+}
diff --git a/demos/gtk-demo/four_point_transform.h b/demos/gtk-demo/four_point_transform.h
new file mode 100644
index 0000000000..44b73c21b5
--- /dev/null
+++ b/demos/gtk-demo/four_point_transform.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <graphene.h>
+
+void perspective_3d (graphene_point3d_t *p1,
+ graphene_point3d_t *p2,
+ graphene_point3d_t *p3,
+ graphene_point3d_t *p4,
+ graphene_point3d_t *q1,
+ graphene_point3d_t *q2,
+ graphene_point3d_t *q3,
+ graphene_point3d_t *q4,
+ graphene_matrix_t *m);
diff --git a/demos/gtk-demo/layoutmanager2.c b/demos/gtk-demo/layoutmanager2.c
index 97ed89fcee..ba48a4f1fd 100644
--- a/demos/gtk-demo/layoutmanager2.c
+++ b/demos/gtk-demo/layoutmanager2.c
@@ -11,6 +11,8 @@
#include <gtk/gtk.h>
#include "demo2widget.h"
+#include "demo2layout.h"
+#include "demochild.h"
GtkWidget *
do_layoutmanager2 (GtkWidget *parent)
@@ -21,6 +23,159 @@ do_layoutmanager2 (GtkWidget *parent)
{
GtkWidget *widget;
GtkWidget *child;
+ const char *color[] = {
+ "red", "orange", "yellow", "green",
+ "blue", "grey", "magenta", "lime",
+ "yellow", "firebrick", "aqua", "purple",
+ "tomato", "pink", "thistle", "maroon"
+ };
+ const char *name[] = {
+ "action-unavailable-symbolic",
+ "address-book-new-symbolic",
+ "application-exit-symbolic",
+ "appointment-new-symbolic",
+ "bookmark-new-symbolic",
+ "call-start-symbolic",
+ "call-stop-symbolic",
+ "camera-switch-symbolic",
+ "chat-message-new-symbolic",
+ "color-select-symbolic",
+ "contact-new-symbolic",
+ "document-edit-symbolic",
+ "document-new-symbolic",
+ "document-open-recent-symbolic",
+ "document-open-symbolic",
+ "document-page-setup-symbolic",
+ "document-print-preview-symbolic",
+ "document-print-symbolic",
+ "document-properties-symbolic",
+ "document-revert-symbolic-rtl",
+ "document-revert-symbolic",
+ "document-save-as-symbolic",
+ "document-save-symbolic",
+ "document-send-symbolic",
+ "edit-clear-all-symbolic",
+ "edit-clear-symbolic-rtl",
+ "edit-clear-symbolic",
+ "edit-copy-symbolic",
+ "edit-cut-symbolic",
+ "edit-delete-symbolic",
+ "edit-find-replace-symbolic",
+ "edit-find-symbolic",
+ "edit-paste-symbolic",
+ "edit-redo-symbolic-rtl",
+ "edit-redo-symbolic",
+ "edit-select-all-symbolic",
+ "edit-select-symbolic",
+ "edit-undo-symbolic-rtl",
+ "edit-undo-symbolic",
+ "error-correct-symbolic",
+ "find-location-symbolic",
+ "folder-new-symbolic",
+ "font-select-symbolic",
+ "format-indent-less-symbolic-rtl",
+ "format-indent-less-symbolic",
+ "format-indent-more-symbolic-rtl",
+ "format-indent-more-symbolic",
+ "format-justify-center-symbolic",
+ "format-justify-fill-symbolic",
+ "format-justify-left-symbolic",
+ "format-justify-right-symbolic",
+ "format-text-bold-symbolic",
+ "format-text-direction-symbolic-rtl",
+ "format-text-direction-symbolic",
+ "format-text-italic-symbolic",
+ "format-text-strikethrough-symbolic",
+ "format-text-underline-symbolic",
+ "go-bottom-symbolic",
+ "go-down-symbolic",
+ "go-first-symbolic-rtl",
+ "go-first-symbolic",
+ "go-home-symbolic",
+ "go-jump-symbolic-rtl",
+ "go-jump-symbolic",
+ "go-last-symbolic-rtl",
+ "go-last-symbolic",
+ "go-next-symbolic-rtl",
+ "go-next-symbolic",
+ "go-previous-symbolic-rtl",
+ "go-previous-symbolic",
+ "go-top-symbolic",
+ "go-up-symbolic",
+ "help-about-symbolic",
+ "insert-image-symbolic",
+ "insert-link-symbolic",
+ "insert-object-symbolic",
+ "insert-text-symbolic",
+ "list-add-symbolic",
+ "list-remove-all-symbolic",
+ "list-remove-symbolic",
+ "mail-forward-symbolic",
+ "mail-mark-important-symbolic",
+ "mail-mark-junk-symbolic",
+ "mail-mark-notjunk-symbolic",
+ "mail-message-new-symbolic",
+ "mail-reply-all-symbolic",
+ "mail-reply-sender-symbolic",
+ "mail-send-receive-symbolic",
+ "mail-send-symbolic",
+ "mark-location-symbolic",
+ "media-eject-symbolic",
+ "media-playback-pause-symbolic",
+ "media-playback-start-symbolic",
+ "media-playback-stop-symbolic",
+ "media-record-symbolic"
+ "media-seek-backward-symbolic",
+ "media-seek-forward-symbolic",
+ "media-skip-backward-symbolic",
+ "media-skip-forward-symbolic",
+ "media-view-subtitles-symbolic",
+ "object-flip-horizontal-symbolic",
+ "object-flip-vertical-symbolic",
+ "object-rotate-left-symbolic",
+ "object-rotate-right-symbolic",
+ "object-select-symbolic",
+ "open-menu-symbolic",
+ "process-stop-symbolic",
+ "send-to-symbolic",
+ "sidebar-hide-symbolic",
+ "sidebar-show-symbolic",
+ "star-new-symbolic",
+ "system-log-out-symbolic",
+ "system-reboot-symbolic",
+ "system-run-symbolic",
+ "system-search-symbolic",
+ "system-shutdown-symbolic",
+ "system-switch-user-symbolic",
+ "tab-new-symbolic",
+ "tools-check-spelling-symbolic",
+ "value-decrease-symbolic",
+ "value-increase-symbolic",
+ "view-app-grid-symbolic",
+ "view-conceal-symbolic",
+ "view-continuous-symbolic",
+ "view-dual-symbolic",
+ "view-fullscreen-symbolic",
+ "view-grid-symbolic",
+ "view-list-bullet-symbolic",
+ "view-list-ordered-symbolic",
+ "view-list-symbolic",
+ "view-mirror-symbolic",
+ "view-more-horizontal-symbolic",
+ "view-more-symbolic",
+ "view-paged-symbolic",
+ "view-pin-symbolic",
+ "view-refresh-symbolic",
+ "view-restore-symbolic",
+ "view-reveal-symbolic",
+ "view-sort-ascending-symbolic",
+ "view-sort-descending-symbolic",
+ "zoom-fit-best-symbolic",
+ "zoom-in-symbolic",
+ "zoom-original-symbolic",
+ "zoom-out-symbolic",
+ };
+ int i;
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Transformation");
@@ -29,9 +184,16 @@ do_layoutmanager2 (GtkWidget *parent)
widget = demo2_widget_new ();
- child = gtk_button_new_with_label ("Hello");
- gtk_widget_set_cursor_from_name (child, "crosshair");
- demo2_widget_add_child (DEMO2_WIDGET (widget), child);
+ for (i = 0; i < 18 * 36; i++)
+ {
+ child = gtk_image_new_from_icon_name (name[i % G_N_ELEMENTS (name)]);
+ //child = demo_child_new (color[i % G_N_ELEMENTS(color)]);
+ gtk_widget_set_margin_start (child, 4);
+ gtk_widget_set_margin_end (child, 4);
+ gtk_widget_set_margin_top (child, 4);
+ gtk_widget_set_margin_bottom (child, 4);
+ demo2_widget_add_child (DEMO2_WIDGET (widget), child);
+ }
gtk_window_set_child (GTK_WINDOW (window), widget);
}
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 358868d54e..05b32c6f46 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -106,6 +106,8 @@ extra_demo_sources = files(['main.c',
'demolayout.c',
'demowidget.c',
'demo2layout.c',
+ 'singular_value_decomposition.c',
+ 'four_point_transform.c',
'demo2widget.c'])
if harfbuzz_dep.found() and pangoft_dep.found()
diff --git a/demos/gtk-demo/singular_value_decomposition.c b/demos/gtk-demo/singular_value_decomposition.c
new file mode 100644
index 0000000000..d50bb80ace
--- /dev/null
+++ b/demos/gtk-demo/singular_value_decomposition.c
@@ -0,0 +1,396 @@
+#include <string.h>
+#include <float.h>
+#include <math.h>
+#include <alloca.h>
+
+/* See Golub and Reinsch,
+ * "Handbook for Automatic Computation vol II - Linear Algebra",
+ * Springer, 1971
+ */
+
+
+#define MAX_ITERATION_COUNT 30
+
+static void
+householder_reduction (double *A,
+ int nrows,
+ int ncols,
+ double *U,
+ double *V,
+ double *diagonal,
+ double *superdiagonal)
+{
+ int i, j, k, ip1;
+ double s, s2, si, scale;
+ double *pu, *pui, *pv, *pvi;
+ double half_norm_squared;
+
+ memcpy (U, A, sizeof (double) * nrows * ncols);
+
+ diagonal[0] = 0.0;
+ s = 0.0;
+ scale = 0.0;
+ for (i = 0, pui = U, ip1 = 1;
+ i < ncols;
+ pui += ncols, i++, ip1++)
+ {
+ superdiagonal[i] = scale * s;
+
+ for (j = i, pu = pui, scale = 0.0;
+ j < nrows;
+ j++, pu += ncols)
+ scale += fabs( *(pu + i) );
+
+ if (scale > 0.0)
+ {
+ for (j = i, pu = pui, s2 = 0.0; j < nrows; j++, pu += ncols)
+ {
+ *(pu + i) /= scale;
+ s2 += *(pu + i) * *(pu + i);
+ }
+ s = *(pui + i) < 0.0 ? sqrt (s2) : -sqrt (s2);
+ half_norm_squared = *(pui + i) * s - s2;
+ *(pui + i) -= s;
+
+ for (j = ip1; j < ncols; j++)
+ {
+ for (k = i, si = 0.0, pu = pui; k < nrows; k++, pu += ncols)
+ si += *(pu + i) * *(pu + j);
+ si /= half_norm_squared;
+ for (k = i, pu = pui; k < nrows; k++, pu += ncols)
+ *(pu + j) += si * *(pu + i);
+ }
+ }
+ for (j = i, pu = pui; j < nrows; j++, pu += ncols)
+ *(pu + i) *= scale;
+ diagonal[i] = s * scale;
+ s = 0.0;
+ scale = 0.0;
+ if (i >= nrows || i == ncols - 1)
+ continue;
+ for (j = ip1; j < ncols; j++)
+ scale += fabs (*(pui + j));
+ if (scale > 0.0)
+ {
+ for (j = ip1, s2 = 0.0; j < ncols; j++)
+ {
+ *(pui + j) /= scale;
+ s2 += *(pui + j) * *(pui + j);
+ }
+ s = *(pui + ip1) < 0.0 ? sqrt (s2) : -sqrt (s2);
+ half_norm_squared = *(pui + ip1) * s - s2;
+ *(pui + ip1) -= s;
+ for (k = ip1; k < ncols; k++)
+ superdiagonal[k] = *(pui + k) / half_norm_squared;
+ if (i < (nrows - 1))
+ {
+ for (j = ip1, pu = pui + ncols; j < nrows; j++, pu += ncols)
+ {
+ for (k = ip1, si = 0.0; k < ncols; k++)
+ si += *(pui + k) * *(pu + k);
+ for (k = ip1; k < ncols; k++)
+ *(pu + k) += si * superdiagonal[k];
+ }
+ }
+ for (k = ip1; k < ncols; k++)
+ *(pui + k) *= scale;
+ }
+ }
+
+ pui = U + ncols * (ncols - 2);
+ pvi = V + ncols * (ncols - 1);
+ *(pvi + ncols - 1) = 1.0;
+ s = superdiagonal[ncols - 1];
+ pvi -= ncols;
+ for (i = ncols - 2, ip1 = ncols - 1;
+ i >= 0;
+ i--, pui -= ncols, pvi -= ncols, ip1--)
+ {
+ if (s != 0.0)
+ {
+ pv = pvi + ncols;
+ for (j = ip1; j < ncols; j++, pv += ncols)
+ *(pv + i) = ( *(pui + j) / *(pui + ip1) ) / s;
+ for (j = ip1; j < ncols; j++)
+ {
+ si = 0.0;
+ for (k = ip1, pv = pvi + ncols; k < ncols; k++, pv += ncols)
+ si += *(pui + k) * *(pv + j);
+ for (k = ip1, pv = pvi + ncols; k < ncols; k++, pv += ncols)
+ *(pv + j) += si * *(pv + i);
+ }
+ }
+ pv = pvi + ncols;
+ for (j = ip1; j < ncols; j++, pv += ncols)
+ {
+ *(pvi + j) = 0.0;
+ *(pv + i) = 0.0;
+ }
+ *(pvi + i) = 1.0;
+ s = superdiagonal[i];
+ }
+
+ pui = U + ncols * (ncols - 1);
+ for (i = ncols - 1, ip1 = ncols;
+ i >= 0;
+ ip1 = i, i--, pui -= ncols)
+ {
+ s = diagonal[i];
+ for (j = ip1; j < ncols; j++)
+ *(pui + j) = 0.0;
+ if (s != 0.0)
+ {
+ for (j = ip1; j < ncols; j++)
+ {
+ si = 0.0;
+ pu = pui + ncols;
+ for (k = ip1; k < nrows; k++, pu += ncols)
+ si += *(pu + i) * *(pu + j);
+ si = (si / *(pui + i)) / s;
+ for (k = i, pu = pui; k < nrows; k++, pu += ncols)
+ *(pu + j) += si * *(pu + i);
+ }
+ for (j = i, pu = pui; j < nrows; j++, pu += ncols)
+ *(pu + i) /= s;
+ }
+ else
+ for (j = i, pu = pui; j < nrows; j++, pu += ncols)
+ *(pu + i) = 0.0;
+ *(pui + i) += 1.0;
+ }
+}
+
+static int
+givens_reduction (int nrows,
+ int ncols,
+ double *U,
+ double *V,
+ double *diagonal,
+ double *superdiagonal)
+{
+ double epsilon;
+ double c, s;
+ double f,g,h;
+ double x,y,z;
+ double *pu, *pv;
+ int i,j,k,m;
+ int rotation_test;
+ int iteration_count;
+
+ for (i = 0, x = 0.0; i < ncols; i++)
+ {
+ y = fabs (diagonal[i]) + fabs (superdiagonal[i]);
+ if (x < y)
+ x = y;
+ }
+ epsilon = x * DBL_EPSILON;
+ for (k = ncols - 1; k >= 0; k--)
+ {
+ iteration_count = 0;
+ while (1)
+ {
+ rotation_test = 1;
+ for (m = k; m >= 0; m--)
+ {
+ if (fabs (superdiagonal[m]) <= epsilon)
+ {
+ rotation_test = 0;
+ break;
+ }
+ if (fabs (diagonal[m-1]) <= epsilon)
+ break;
+ }
+ if (rotation_test)
+ {
+ c = 0.0;
+ s = 1.0;
+ for (i = m; i <= k; i++)
+ {
+ f = s * superdiagonal[i];
+ superdiagonal[i] *= c;
+ if (fabs (f) <= epsilon)
+ break;
+ g = diagonal[i];
+ h = sqrt (f*f + g*g);
+ diagonal[i] = h;
+ c = g / h;
+ s = -f / h;
+ for (j = 0, pu = U; j < nrows; j++, pu += ncols)
+ {
+ y = *(pu + m - 1);
+ z = *(pu + i);
+ *(pu + m - 1 ) = y * c + z * s;
+ *(pu + i) = -y * s + z * c;
+ }
+ }
+ }
+ z = diagonal[k];
+ if (m == k)
+ {
+ if (z < 0.0)
+ {
+ diagonal[k] = -z;
+ for (j = 0, pv = V; j < ncols; j++, pv += ncols)
+ *(pv + k) = - *(pv + k);
+ }
+ break;
+ }
+ else
+ {
+ if (iteration_count >= MAX_ITERATION_COUNT)
+ return -1;
+ iteration_count++;
+ x = diagonal[m];
+ y = diagonal[k-1];
+ g = superdiagonal[k-1];
+ h = superdiagonal[k];
+ f = ((y - z) * ( y + z ) + (g - h) * (g + h))/(2.0 * h * y);
+ g = sqrt (f * f + 1.0);
+ if (f < 0.0)
+ g = -g;
+ f = ((x - z) * (x + z) + h * (y / (f + g) - h)) / x;
+ c = 1.0;
+ s = 1.0;
+ for (i = m + 1; i <= k; i++)
+ {
+ g = superdiagonal[i];
+ y = diagonal[i];
+ h = s * g;
+ g *= c;
+ z = sqrt (f * f + h * h);
+ superdiagonal[i-1] = z;
+ c = f / z;
+ s = h / z;
+ f = x * c + g * s;
+ g = -x * s + g * c;
+ h = y * s;
+ y *= c;
+ for (j = 0, pv = V; j < ncols; j++, pv += ncols)
+ {
+ x = *(pv + i - 1);
+ z = *(pv + i);
+ *(pv + i - 1) = x * c + z * s;
+ *(pv + i) = -x * s + z * c;
+ }
+ z = sqrt (f * f + h * h);
+ diagonal[i - 1] = z;
+ if (z != 0.0)
+ {
+ c = f / z;
+ s = h / z;
+ }
+ f = c * g + s * y;
+ x = -s * g + c * y;
+ for (j = 0, pu = U; j < nrows; j++, pu += ncols)
+ {
+ y = *(pu + i - 1);
+ z = *(pu + i);
+ *(pu + i - 1) = c * y + s * z;
+ *(pu + i) = -s * y + c * z;
+ }
+ }
+ superdiagonal[m] = 0.0;
+ superdiagonal[k] = f;
+ diagonal[k] = x;
+ }
+ }
+ }
+ return 0;
+}
+
+static void
+sort_singular_values (int nrows,
+ int ncols,
+ double *S,
+ double *U,
+ double *V)
+{
+ int i, j, max_index;
+ double temp;
+ double *p1, *p2;
+
+ for (i = 0; i < ncols - 1; i++)
+ {
+ max_index = i;
+ for (j = i + 1; j < ncols; j++)
+ if (S[j] > S[max_index])
+ max_index = j;
+ if (max_index == i)
+ continue;
+ temp = S[i];
+ S[i] = S[max_index];
+ S[max_index] = temp;
+ p1 = U + max_index;
+ p2 = U + i;
+ for (j = 0; j < nrows; j++, p1 += ncols, p2 += ncols)
+ {
+ temp = *p1;
+ *p1 = *p2;
+ *p2 = temp;
+ }
+ p1 = V + max_index;
+ p2 = V + i;
+ for (j = 0; j < ncols; j++, p1 += ncols, p2 += ncols)
+ {
+ temp = *p1;
+ *p1 = *p2;
+ *p2 = temp;
+ }
+ }
+}
+
+int
+singular_value_decomposition (double *A,
+ int nrows,
+ int ncols,
+ double *U,
+ double *S,
+ double *V)
+{
+ double *superdiagonal;
+
+ superdiagonal = alloca (sizeof (double) * ncols);
+
+ if (nrows < ncols)
+ return -1;
+
+ householder_reduction (A, nrows, ncols, U, V, S, superdiagonal);
+
+ if (givens_reduction (nrows, ncols, U, V, S, superdiagonal) < 0)
+ return -1;
+
+ sort_singular_values (nrows, ncols, S, U, V);
+
+ return 0;
+}
+
+void
+singular_value_decomposition_solve (double *U,
+ double *S,
+ double *V,
+ int nrows,
+ int ncols,
+ double *B,
+ double *x)
+{
+ int i, j, k;
+ double *pu, *pv;
+ double d;
+ double tolerance;
+
+ tolerance = DBL_EPSILON * S[0] * (double) ncols;
+
+ for ( i = 0, pv = V; i < ncols; i++, pv += ncols)
+ {
+ x[i] = 0.0;
+ for (j = 0; j < ncols; j++)
+ {
+ if (S[j] > tolerance)
+ {
+ for (k = 0, d = 0.0, pu = U; k < nrows; k++, pu += ncols)
+ d += *(pu + j) * B[k];
+ x[i] += d * *(pv + j) / S[j];
+ }
+ }
+ }
+}
diff --git a/demos/gtk-demo/singular_value_decomposition.h b/demos/gtk-demo/singular_value_decomposition.h
new file mode 100644
index 0000000000..9b4c65a2a6
--- /dev/null
+++ b/demos/gtk-demo/singular_value_decomposition.h
@@ -0,0 +1,17 @@
+#pragma once
+
+int singular_value_decomposition (double *A,
+ int nrows,
+ int ncols,
+ double *U,
+ double *S,
+ double *V);
+
+void singular_value_decomposition_solve (double *U,
+ double *S,
+ double *V,
+ int nrows,
+ int ncols,
+ double *B,
+ double *x);
+
diff --git a/tests/simple.c b/tests/simple.c
index 062afdc9fa..b861631090 100644
--- a/tests/simple.c
+++ b/tests/simple.c
@@ -36,28 +36,150 @@ quit_cb (GtkWidget *widget,
g_main_context_wakeup (NULL);
}
+static void
+invert3 (double m[9], double n[9])
+{
+ double det;
+ double a = m[0];
+ double b = m[1];
+ double c = m[2];
+ double d = m[3];
+ double e = m[4];
+ double f = m[5];
+ double g = m[6];
+ double h = m[7];
+ double k = m[8];
+
+ det = a*(e*k - f*h) - b*(d*k - f*g) + c*(d*h - e*g);
+
+ n[0] = (e*k - f*h) / det;
+ n[1] = - (b*k - c*h) / det;
+ n[2] = (b*f - c*e) / det;
+ n[3] = - (d*k - f*g) / det;
+ n[4] = (a*k - c*g) / det;
+ n[5] = - (a*g - c*d) / det;
+ n[6] = (d*h - e*g) / det;
+ n[7] = - (a*h - b*g) / det;
+ n[8] = (a*e - b*d) / det;
+}
+
+static void
+perspective2d (double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ double o[9])
+{
+ double mat[9], inv[9];
+ double l, m, t;
+
+ mat[0] = x0;
+ mat[1] = x1;
+ mat[2] = x2;
+ mat[3] = y0;
+ mat[4] = y1;
+ mat[5] = y2;
+ mat[6] = 1;
+ mat[7] = 1;
+ mat[8] = 1;
+
+ invert3 (mat, inv);
+
+ l = inv[0] * x3 + inv[1] * y3 + inv[2];
+ m = inv[3] * x3 + inv[4] * y3 + inv[5];
+ t = inv[6] * x3 + inv[7] * y3 + inv[8];
+
+ o[0] = l*x0; o[1] = m*x1; o[2] = t*x2;
+ o[3] = l*y0; o[4] = m*y1; o[5] = t*y2;
+ o[6] = l; o[7] = m; o[8] = t;
+}
+
+#define RADIANS(angle) ((angle)*M_PI/180.0);
+#define SX(r,t,p) ((r) * sin (t) * cos (p))
+#define SZ(r,t,p) ((r) * sin (t) * sin (p))
+#define SY(r,t,p) ((r) * cos (t))
+
+static double offset;
+
+static gboolean
+tick_cb (GtkWidget *widget,
+ GdkFrameClock *clock,
+ gpointer data)
+{
+ offset += 1;
+ gtk_widget_queue_draw (widget);
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+draw_func (GtkDrawingArea *da,
+ cairo_t *cr,
+ int width,
+ int height,
+ gpointer data)
+{
+ double r = 500;
+ double t1, t2, p1, p2;
+ double x0, y0, x1, y1, x2, y2, x3, y3;
+ int i, j;
+
+ for (i = 0; i < 18; i++)
+ for (j = 0; j < 36; j++)
+ {
+ if ((i + j) % 2)
+ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
+ else
+ cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
+
+ t1 = RADIANS (10 * i);
+ t2 = RADIANS (10 * (i + 1));
+ p1 = RADIANS (offset + 10 * j);
+ p2 = RADIANS (offset + 10 * (j + 1));
+
+ x0 = SX (r, t1, p1);
+ y0 = SY (r, t1, p1);
+ x1 = SX (r, t1, p2);
+ y1 = SY (r, t1, p2);
+ x2 = SX (r, t2, p2);
+ y2 = SY (r, t2, p2);
+ x3 = SX (r, t2, p1);
+ y3 = SY (r, t2, p1);
+
+ if (SZ (r, t1, p1) > 0)
+ continue;
+
+ cairo_move_to (cr, 150, 150);
+ cairo_rel_move_to (cr, x0, y0);
+ cairo_rel_line_to (cr, x1 - x0, y1 - y0);
+ cairo_rel_line_to (cr, x2 - x1, y2 - y1);
+ cairo_rel_line_to (cr, x3 - x2, y3 - y2);
+ cairo_rel_line_to (cr, x0 - x3, y0 - y3);
+ cairo_close_path (cr);
+
+ cairo_fill (cr);
+ }
+}
+
int
main (int argc, char *argv[])
{
- GtkWidget *window, *button;
+ GtkWidget *window, *box, *da;
gboolean done = FALSE;
gtk_init ();
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "hello world");
- gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
- button = gtk_button_new ();
- gtk_button_set_label (GTK_BUTTON (button), "hello world");
- gtk_widget_set_margin_top (button, 10);
- gtk_widget_set_margin_bottom (button, 10);
- gtk_widget_set_margin_start (button, 10);
- gtk_widget_set_margin_end (button, 10);
- g_signal_connect (button, "clicked", G_CALLBACK (hello), NULL);
-
- gtk_window_set_child (GTK_WINDOW (window), button);
+ box = gtk_box_new (1, 10);
+ gtk_window_set_child (GTK_WINDOW (window), box);
+ da = gtk_drawing_area_new ();
+ gtk_widget_set_hexpand (da, TRUE);
+ gtk_widget_set_vexpand (da, TRUE);
+ gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
+ gtk_box_append (GTK_BOX (box), da);
+ gtk_widget_add_tick_callback (da, tick_cb, NULL, NULL);
gtk_widget_show (window);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]