Comment dessiner une boule de cristal avec des particules bicolores à l'intérieur


Answers

Ceci est très similaire à la réponse de Ben Bolker, mais je montre comment on pourrait ajouter un peu d'aura à la boule de cristal en utilisant une coloration mystique:

library(rgl)
lapply(seq(0.01, 1, by=0.01), function(x) rgl.spheres(0,0,0, rad=1.1*x, alpha=.01,
    col=colorRampPalette(c("orange","blue"))(100)[100*x]))
rgl.spheres(0,0,0, radius=1.11, col="red", alpha=.1)
rgl.spheres(0,0,0, radius=1.12, col="black", alpha=.1)
rgl.spheres(0,0,0, radius=1.13, col="white", alpha=.1)

xyz <- matrix(rnorm(3*100), ncol=3)
xyz <- xyz * runif(100)^(1/3) / sqrt(rowSums(xyz^2))

rgl.spheres(xyz[1:50,], rad=.02, col="blue")
rgl.spheres(xyz[51:100,], rad=.02, col="red")

rgl.bg(col="black")
rgl.viewpoint(zoom=.75)
rgl.snapshot("crystalball.png")

La seule différence entre les deux est dans l'appel lapply . Vous pouvez voir que juste en changeant les couleurs dans colorRampPalette vous pouvez changer l'apparence de la boule de cristal de manière significative. Celui de gauche utilise le code lapply ci-dessus, celui de droite l'utilise à la place:

lapply(seq(0.01, 1, by=0.01), function(x) rgl.spheres(0,0,0,rad=1.1*x, alpha=.01,
     col=colorRampPalette(c("orange","yellow"))(100)[100*x]))
...code from above

Voici une approche différente où vous pouvez définir votre propre fichier de texture et l'utiliser pour colorer la boule de cristal:

# create a texture file, get as creative as you want:
png("texture.png")
x <- seq(1,870)
y <- seq(1,610)
z <- matrix(rnorm(870*610), nrow=870)
z <- t(apply(z,1,cumsum))/100

# Swirly texture options:
# Use the Simon O'Hanlon's roll function from this answer:
# http://stackoverflow.com/questions/18791212/equivalent-to-numpy-roll-in-r/18791252#18791252
# roll <- function( x , n ){
#   if( n == 0 )
#     return( x )
#   c( tail(x,n) , head(x,-n) )
# }

# One option
# z <- mapply(function(x,y) roll(z[,x], y), x = 1:ncol(z), y=1:ncol(z))
#
# Another option
# z <- mapply(function(x,y) roll(z[,x], y), x = 1:ncol(z), y=rep(c(1:50,51:2), 10))[1:870, 1:610]
#
# One more
# z <- mapply(function(x,y) roll(z[,x], y), x = 1:ncol(z), y=rep(seq(0, 100, by=10), each=5))[1:870, 1:610]

par(mar=c(0,0,0,0))
image(x, y, z, col = colorRampPalette(c("cyan","black"))(100), axes = FALSE)
dev.off()

xyz <- matrix(rnorm(3*100), ncol=3)
xyz <- xyz * runif(100)^(1/3) / sqrt(rowSums(xyz^2))

rgl.spheres(xyz[1:50,], rad=.02, col="blue")
rgl.spheres(xyz[51:100,], rad=.02, col="red")

rgl.spheres(0,0,0, rad=1.1, texture="texture.png", alpha=0.4, back="cull")
rgl.viewpoint(phi=90, zoom=.75) # change the view if need be
rgl.bg(color="black")

!

La première image en haut à gauche est ce que vous obtenez si vous exécutez simplement le code ci-dessus, les trois autres sont les résultats de l'utilisation des différentes options dans le code commenté.

Question

Je lance juste une idée avec possibilité de fermeture. J'ai besoin de dessiner une boule de cristal dans laquelle les particules rouges et bleues se localisent au hasard. Je suppose que je dois aller avec photoshop, et même essayé de faire la balle dans une image, mais comme c'est pour le papier de recherche et ne doit pas être fantaisie, je me demande s'il est possible de programmer avec R, matlab, ou tout autre langue.




Un peu en retard dans le jeu, mais voici un code Matlab qui implémente scatter3sph (à partir de FEX)

figure('Color', [0.04 0.15 0.4]);
nos = 11; % number small of spheres
S= 3; %small spheres sizes
Grid_Size=256;
%Coordinates
X= Grid_Size*(0.5+rand(2*nos,1));
Y= Grid_Size*(0.5+rand(2*nos,1));
Z= Grid_Size*(0.5+rand(2*nos,1));
%Small spheres colors: (Red & Blue)
C= ones(nos,1)*[0 0 1];
C= [C;ones(nos,1)*[1 0 0]];
% Plot big Sphere
scatter3sph(Grid_Size,Grid_Size,Grid_Size,'size',220,'color',[0.9 0.9 0.9]); hold on
light('Position',[0 0 0],'Style','local');
alpha(0.45);
material shiny 
% Plot small spheres 
scatter3sph(X,Y,Z,'size',S,'color',C);  
axis equal; axis tight; grid off
view([108 -42]);
set(gca,'Visible','off')
set(gca,'color','none')




En Javascript avec d3.js: http://jsfiddle.net/jjcosare/rggn86aj/6/ ou> Run Code Snippet

Utile pour la publication en ligne.

var particleChangePerMs = 1000;
var particleTotal = 250;
var particleSizeInRelationToCircle = 75;

var svgWidth = (window.innerWidth > window.innerHeight) ? window.innerHeight : window.innerWidth;
var svgHeight = (window.innerHeight > window.innerWidth) ? window.innerWidth : window.innerHeight;

var circleX = svgWidth / 2;
var circleY = svgHeight / 2;
var circleRadius = (circleX / 4) + (circleY / 4);
var circleDiameter = circleRadius * 2;

var particleX = function() {
  return Math.floor(Math.random() * circleDiameter) + circleX - circleRadius;
};
var particleY = function() {
  return Math.floor(Math.random() * circleDiameter) + circleY - circleRadius;
};
var particleRadius = function() {
  return circleDiameter / particleSizeInRelationToCircle;
};
var particleColorList = [
  'blue',
  'red'
];
var particleColor = function() {
  return "url(#" + particleColorList[Math.floor(Math.random() * particleColorList.length)] + "Gradient)";
};

var svg = d3.select("#quantumBall")
  .append("svg")
  .attr("width", svgWidth)
  .attr("height", svgHeight);

var blackGradient = svg.append("svg:defs")
  .append("svg:radialGradient")
  .attr("id", "blackGradient")
  .attr("cx", "50%")
  .attr("cy", "50%")
  .attr("radius", "90%")

blackGradient.append("svg:stop")
  .attr("offset", "80%")
  .attr("stop-color", "black")

blackGradient.append("svg:stop")
  .attr("offset", "100%")
  .attr("stop-color", "grey")

var redGradient = svg.append("svg:defs")
  .append("svg:linearGradient")
  .attr("id", "redGradient")
  .attr("x1", "0%")
  .attr("y1", "0%")
  .attr("x2", "100%")
  .attr("y2", "100%")
  .attr("spreadMethod", "pad");

redGradient.append("svg:stop")
  .attr("offset", "0%")
  .attr("stop-color", "red")
  .attr("stop-opacity", 1);

redGradient.append("svg:stop")
  .attr("offset", "100%")
  .attr("stop-color", "pink")
  .attr("stop-opacity", 1);

var blueGradient = svg.append("svg:defs")
  .append("svg:linearGradient")
  .attr("id", "blueGradient")
  .attr("x1", "0%")
  .attr("y1", "0%")
  .attr("x2", "100%")
  .attr("y2", "100%")
  .attr("spreadMethod", "pad");

blueGradient.append("svg:stop")
  .attr("offset", "0%")
  .attr("stop-color", "blue")
  .attr("stop-opacity", 1);

blueGradient.append("svg:stop")
  .attr("offset", "100%")
  .attr("stop-color", "skyblue")
  .attr("stop-opacity", 1);

svg.append("circle")
  .attr("r", circleRadius)
  .attr("cx", circleX)
  .attr("cy", circleY)
  .attr("fill", "url(#blackGradient)");

function isParticleInQuantumBall(particle) {
  var x1 = circleX;
  var y1 = circleY;
  var r1 = circleRadius;
  var x0 = particle.x;
  var y0 = particle.y;
  var r0 = particle.radius;
  return Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) < (r1 - r0);
};

function randomizedParticles() {
  d3.selectAll("svg > .particle").remove();
  var particle = {};
  particle.radius = particleRadius();
  for (var i = 0; i < particleTotal;) {
    particle.x = particleX();
    particle.y = particleY();
    particle.color = particleColor();
    if (isParticleInQuantumBall(particle)) {
      svg.append("circle")
        .attr("class", "particle")
        .attr("cx", particle.x)
        .attr("cy", particle.y)
        .attr("r", particle.radius)
        .attr("fill", particle.color);
      i++;
    }
  }
}

setInterval(randomizedParticles, particleChangePerMs);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="quantumBall"></div>




Je devais juste générer quelque chose d'aussi brillant que la R-réponse dans Matlab :) Alors, voici ma solution de fin de nuit, trop compliquée, super-lente, mais ma c'est joli n'est ce pas? :)

figure(1), clf, hold on
whitebg('k')    

light(...
    'Color','w',...
    'Position',[-3 -1 0],...
    'Style','infinite')

colormap cool
brighten(0.2)

[x,y,z] = sphere(50);
surf(x,y,z);

lighting phong
alpha(.2)
shading interp
grid off

blues = 2*rand(15,3)-1;
reds  = 2*rand(15,3)-1;
R     = linspace(0.001, 0.02, 20);

done = false;
while ~done

    indsB = sum(blues.^2,2)>1-0.02;    
    if any(indsB)
        done = false;
        blues(indsB,:) = 2*rand(sum(indsB),3)-1; 
    else
        done = true;
    end

    indsR = sum( reds.^2,2)>1-0.02;
    if any(indsR)
        done = false;
        reds(indsR,:) = 2*rand(sum(indsR),3)-1; 
    else
        done = done && true;
    end

end

nR = numel(R);
[x,y,z] = sphere(15);
for ii = 1:size(blues,1)
    for jj = 1:nR        
        surf(x*R(jj)-blues(ii,1), y*R(jj)-blues(ii,2), z*R(jj)-blues(ii,3), ...
            'edgecolor', 'none', ...
            'facecolor', [1-jj/nR 1-jj/nR 1],...
            'facealpha', exp(-(jj-1)/5));
    end
end

nR = numel(R);
[x,y,z] = sphere(15);
for ii = 1:size(reds,1)
    for jj = 1:nR        
        surf(x*R(jj)-reds(ii,1), y*R(jj)-reds(ii,2), z*R(jj)-reds(ii,3), ...
            'edgecolor', 'none', ...
            'facecolor', [1 1-jj/nR 1-jj/nR],...
            'facealpha', exp(-(jj-1)/5));
    end
end

set(findobj(gca,'type','surface'),...
    'FaceLighting','phong',...
    'SpecularStrength',1,...
    'DiffuseStrength',0.6,...
    'AmbientStrength',0.9,...
    'SpecularExponent',200,...
    'SpecularColorReflectance',0.4 ,...
    'BackFaceLighting','lit');

axis equal
view(30,60)