I have some normalized points for (Red, Blue, Green). When I convert them to RGB, I get values such as:
R: 0.23
G: 0.44
B: 0.33
However, this is not showing up as any color but white when I color my face on my tubegeometry. This happens to almost all RGB values except the main ones such as 255, 0, 0 or 0, 255, 0
var rVal = parseFloat(rLow + normalizedGr * (rHigh - rLow));
var gVal = parseFloat(gLow + normalizedGr * (gHigh - gLow));
var bVal = parseFloat(bLow + normalizedGr * (bHigh - bLow));
var logColor = new THREE.Color().setRGB(rVal, gVal, bVal);
for (var j = startingPoint; j < endingPoint; j++) {
tube.faces[j].color = logColor;
}
var mesh = THREE.SceneUtils.createMultiMaterialObject(tube, [new THREE.MeshLambertMaterial({ color: color, vertexColors: THREE.FaceColors })]);
According to http://threejs.org/docs/#Reference/Math/Color setRGB( r, g, b ) sets the color from RGB values between 0 and 1.
Related
I used tmap to create the plot attached. However, I would like to add a scale bar to the inset map, but I haven't been able to figured out how to do that. Can someone please help me?
Here are the codes that I used to create the attached map:
main_map <- tmap::tm_shape(main_map_df) +
tmap::tm_polygons(
col = "var.q5",
palette = c("#CCCCCC", "#999999", "#666666", "#333333", "#000000"),
#alpha = 0.7,
lwd = 0.5,
title = "") +
tmap::tm_layout(
frame = FALSE,
legend.outside = TRUE,
legend.hist.width = 5,
legend.text.size = 0.5,
fontfamily = "Verdana") +
tmap::tm_scale_bar(
position = c("LEFT", "BOTTOM"),
breaks = c(0, 10, 20),
text.size = 0.5
) +
tmap::tm_compass(position = c("LEFT", "TOP"))
inset_map <- tmap::tm_shape(inset_map_df) +
tmap::tm_polygons() +
tmap::tm_shape(main_map_df) +
tm_fill("grey50") +
tmap::tm_scale_bar(
position = c("LEFT", "BOTTOM"),
breaks = c(0, 10, 20),
text.size = 0.5
)
# Combine crude rate map (inset + main) =====
tiff(
"main_map_w_iset.tiff",
height = 1200,
width = 1100,
compression = "lzw",
res = 300
)
main_map
print(
inset_map,
vp = viewport(
x = 0.7,
y = 0.18,
width = 0.3,
height = 0.3,
clip = "off")
)
dev.off()
Thank you!
Here's a simple example using the World data set:
library(tidyverse)
library(tmap)
library(grid)
data("World")
# main map
tm_main <- World %>%
filter(name == "Australia") %>%
tm_shape() +
tm_polygons(col = "red",
alpha = .5) +
tm_scale_bar()
# inset map
tm_inset <- tm_shape(World) +
tm_polygons(col = "gray",
alpha = .5) +
tm_scale_bar()
vp <- viewport(x = .615, y = .5, width = .6, height = .6, just = c("right", "top"))
# final map
tmap_save(tm_main, filename = "test_inset.png", insets_tm = tm_inset, insets_vp = vp,
height = 200, width = 200, units = "mm")
How can I curve a sheet (cube)? I'd like to control the angle of the bend/curve.
e.g.
cube([50,50,2]);
You can rotate_extrude() an rectangle with the parameter angle. This requires the openscad version 2016.xx or newer, see documentation.
It is necessary to install a development snapshot, see download openscad
$fn= 360;
width = 10; // width of rectangle
height = 2; // height of rectangle
r = 50; // radius of the curve
a = 30; // angle of the curve
rotate_extrude(angle = a) translate([r, 0, 0]) square(size = [height, width], center = true);
looks like this:
The curve is defined by radius and angle. I think it is more realistic, to use other dimensions like length or dh in this sketch
and calculate radius and angle
$fn= 360;
w = 10; // width of rectangle
h = 2; // height of rectangle
l = 25; // length of chord of the curve
dh = 2; // delta height of the curve
module curve(width, height, length, dh) {
// calculate radius and angle
r = ((length/2)*(length/2) - dh*dh)/(2*dh);
a = asin((length/2)/r);
rotate_extrude(angle = a) translate([r, 0, 0]) square(size = [height, width], center = true);
}
curve(w, h, l, dh);
Edit 30.09.2019:
considering comment of Cfreitas, additionally moved the resulting shape to origin, so dimensions can be seen on axes of coordinates
$fn= 360;
w = 10; // width of rectangle
h = 2; // height of rectangle
l = 30; // length of chord of the curve
dh = 4; // delta height of the curve
module curve(width, height, length, dh) {
r = (pow(length/2, 2) + pow(dh, 2))/(2*dh);
a = 2*asin((length/2)/r);
translate([-(r -dh), 0, -width/2]) rotate([0, 0, -a/2]) rotate_extrude(angle = a) translate([r, 0, 0]) square(size = [height, width], center = true);
}
curve(w, h, l, dh);
and the result:
Edit 19.09.2020: There was a typo in the last edit: In the first 'translate' the local 'width' should be used instead of 'w'. Corrected it in the code above.
I can do it this way but it would be better if you could specify the bend/curve in #degrees as an argument to the function:
$fn=300;
module oval(w, h, height, center = false) {
scale([1, h/w, 1]) cylinder(h=height, r=w, center=center);
}
module curved(w,l,h) {
difference() {
oval(w,l,h);
translate([0.5,-1,-1]) color("red") oval(w,l+2,h+2);
}
}
curved(10,20,30);
Using the concept used by a_manthey_67, corrected the math and centered (aligned the chord with y axis) the resulting object:
module bentCube(width, height, length, dh) {
// calculate radius and angle
r = (length*length + 4*dh*dh)/(8*dh);
a = 2*asin(length/(2*r));
translate([-r,0,0]) rotate([0,0,-a/2])
rotate_extrude(angle = a) translate([r, 0, 0]) square(size = [height, width], center = true);}
Or, if you just want something with a fixed length, and a certain bent angle do this:
module curve(width, height, length, a) {
if( a > 0 ) {
r = (360 * (length/a)) / (2 * pi);
translate( [-r-height/2,0,0] )
rotate_extrude(angle = a)
translate([r, 0, 0])
square(size = [height, width], center = false);
} else {
translate( [-height/2,0,width] )
rotate( a=270, v=[1,0,0] )
linear_extrude( height = length )
square(size = [height, width], center = false);
}
}
The if (a > 0) statement is needed to make an exception when the bending angle is 0 (which, if drawing a curved surface, would result in an infinite radius).
Animated GIF here
I'm generating image programmatically inside canvas.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
// here I have some code in loop setting individual pixels
// ...
//
// save image to variable
var dataURL = canvas.toDataURL();
How can I rotate created image by 90 degrees?
EDIT:
This is not duplicate because I don't draw image, it is never visible. I only want to generate it, rotate it and save to variable.
EDIT2:
I'm trying to rotate it with this code:
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(90 * Math.PI / 180)
But it doesn't work
EDIT3:
This is more complex example of my code:
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
canvas.setPixel = function (x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, 1, 1);
}
for (var i in data) {
for (var j in data[i]) {
switch (data[i][j]) {
case 1:
var color = '#ffff00',
type = 'w'
break
case 3:
var rgb = (256 - parseInt(pixels[i][j]) - minus.grass).toString(16),
color = '#00' + rgb + '00',
type = 'g'
break
case 4:
var rgb = (256 - parseInt(pixels[i][j]) - minus.hills).toString(16),
color = '#' + rgb + rgb + '00',
type = 'h'
break
case 5:
var rgb = (parseInt(pixels[i][j]) + minus.mountains).toString(16),
color = '#' + rgb + rgb + rgb,
type = 'm'
break
case 6:
var rgb = (parseInt(pixels[i][j]) + minus.snow).toString(16),
color = '#' + rgb + rgb + rgb,
type = 'm'
break
}
if (i % fieldSize == 0 && j % fieldSize == 0) {
if (notSet(fields[y])) {
fields[y] = []
}
fields[y][x] = type
x++
}
canvas.setPixel(i, j, color)
}
if (i % fieldSize == 0) {
x = 0
y++
}
}
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(90 * Math.PI / 180)
var token = {
type: 'save',
map: canvas.toDataURL('image/png')
}
ws.send(JSON.stringify(token))
To rotate image by 90 degrees I had to put
ctx.translate(0, canvas.height)
ctx.rotate(270 * Math.PI / 180)
before
for (var i in data) {
for (var j in data[i]) {
switch (data[i][j]) {
// ... drawing pixels
}
}
}
I'm trying to render a matrix of points in Three.js but I need to treat each particle in the cloud as an individual "pixel" for which I can change the color of each on the fly. I figured out how to basically render the point cloud, and can set the initial color, but cannot figure out how to change the color of each point once it's set.
I'm generating the point cloud like this:
function generateRegularPointcloud( color, width, length ) {
var geometry = new THREE.Geometry();
var numPoints = width * length;
var colors = [];
var k = 0;
for( var i = 0; i < width; i++ ) {
for( var j = 0; j < length; j++ ) {
var u = i / width;
var v = j / length;
var x = u - 0.5;
var y = 0;
var z = v - 0.5;
var v = new THREE.Vector3( x,y,z );
var intensity = ( y + 0.1 ) * 7;
colors[ 3 * k ] = color.r * intensity;
colors[ 3 * k + 1 ] = color.g * intensity;
colors[ 3 * k + 2 ] = color.b * intensity;
geometry.vertices.push( v );
colors[ k ] = ( color.clone().multiplyScalar( intensity ) );
k++;
}
}
geometry.colors = colors;
geometry.computeBoundingBox();
var material = new THREE.PointCloudMaterial( { size: pointSize, vertexColors: THREE.VertexColors } );
var pointcloud = new THREE.PointCloud( geometry, material );
return pointcloud;
}
My basic code is here: http://jsfiddle.net/dg34sbsk/
Any idea how to change each point color separately and dynamically? (Data for the colors will be coming in from a web service).
You can directly change its's value pointclouds[0].geometry.colors=... and after that pointclouds[0].geometry.colorsNeedUpdate=true.
To set each point's color just set the colors's children's value like pointclouds[0].geometry.colors[22]=new THREE.Color("rgb(255,0,0)");.
see this:http://jsfiddle.net/aboutqx/dg34sbsk/2/ .click and you will see the color of one point changes.
I found a way to increase the gamma, but no way to decrease it! This article states a formula for increasing the gamma. The formula works for increasing the gamma but not for decreasing, even if I apply the reduction on a new instance of the canvas. I tried redrawing the canvas and using a negative value for gamma calculation, but I don't get my original canvas back.
//For increasing, I tried
gamma = 0.5;
gammacorrection = 1/gamma;
r = Math.pow(255 * (r / 255), gammacorrection);
g = ...
b = ...
//For decreasing
gamma = -0.5;
gammacorrection = 1/gamma;
r = Math.pow(255 * (r / 255), gammacorrection);
g = ...
b = ...
First part works. Second doesn't.
For sake of completeness here's a working piece of code
async function adjustGamma(gamma) {
const gammaCorrection = 1 / gamma;
const canvas = document.getElementById('canvasOutput');
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0.0, 0.0, canvas.width, canvas.height);
const data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
data[i] = 255 * Math.pow((data[i] / 255), gammaCorrection);
data[i+1] = 255 * Math.pow((data[i+1] / 255), gammaCorrection);
data[i+2] = 255 * Math.pow((data[i+2] / 255), gammaCorrection);
}
ctx.putImageData(imageData, 0, 0);
}
Here the function adjusts the gamma based on the formula in the Article linked by OP on the Canvas with id "canvasOutput"
There is no negative gamma correction. You should save the original values and use them when making gamma changes, and set gamma to 1.0 to revert back to the original.
Also note that you have the wrong order of operations (exponents come before multiplication).
var originals = { r: r, g: g, b: b };
// increase
gamma = 0.5;
gammacorrection = 1/gamma;
r = 255 * Math.pow(( originals.r / 255), gammacorrection);
g = ...
b = ...
// revert to original
gamma = 1;
gammacorrection = 1/gamma;
r = 255 * Math.pow(( originals.r / 255), gammacorrection);
g = ...
b = ...
There is no negative value for gamma. Ideally this value will range between 0.01 and 7.99. So reverting back the gamma to the original value should be possible either by creating a new canvas instance with the original values of the image, then instantiating it, or either by creating a pool of pixels with the original image and reverting back to it.
I wrote a script how would i construct the algorithm for gamma reduction.
var gamma = 0.5;
var gammaCorrection = 1 / gamma;
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0.0, canvas.width, canvas.height);
function GetPixelColor(x, y) {
var index = parseInt(x + canvas.width * y) * 4;
var rgb = {
r : imageData.data[index + 0],
g : imageData.data[index + 1],
b : imageData.data[index + 2]
};
return rgb;
}
function SetPixelColor(x, y, color) {
var index = parseInt(x + this.width * y) * 4;
var data = imageData.data;
data[index+0] = color.r;
data[index+1] = color.g;
data[index+2] = color.b;
};
for (y = 0; y < canvas.height; y++) {
for (x = 0; x < canvas.width; x++) {
var color = GetPixelColor(x, y)
var newRed = Math.pow(255 * (color.r / 255), gammaCorrection);
var newGreen = Math.pow(255 * (color.g / 255), gammaCorrection);
var newBlue = Math.pow(255 * (color.b / 255), gammaCorrection);
var color = {
r: newRed,
g: newGreen,
b: newBlue
}
SetPixelColor(x, y, color);
}
}
I don't know how the application should adjust the gamma value, but i suppose it's done with a value adjuster. If so you should adjust the gamma value dynamically giving the min and max range. I didn't tested the code, this wasn't my scope, but the idea is hopefully clear.
EDIT:
To understand the principle of gamma correction first how about to define the gamma instead.
Gamma is the monitor particularity altering the pixels input. Gamma correction is the act of inverting that process for linear RGB values so that the final output remains linear. For example, if you calculated the light intensity of an object is 0.5, you don't store the result as 0.5 in the pixel. Store it as pow(0.5, 1.0/2.2) = 0.73. When you send 0.73 to the monitor, it will apply a gamma on the value and produce pow(0.73, 2.2) = 0.5, which is what you want. To do this, you apply the inverse gamma function.
o=pow(i, 1.0/gamma)
Where
o is the output value.
i is the input value.
gamma is the gamma value used by your monitor.
So the gamma correction is nothing else than the rise of input value to the power of inverse of gamma. So to restore the gamma to the original value you apply the formula before the gamma correction has been applied.
The blue line represents the inverse gamma curve you need to apply to your pixels before they're sent to the monitor. When your monitor applies its gamma curve (red line) to the pixels, the result is a linear line (green line) that represents your intended RGB pixel values.