Рисование пересекающихся 3D-поверхностных графиков

Рисование пересекающихся 3D-поверхностных графиков

Я пытаюсь нарисовать шесть полупрозрачных пересекающихся сфер разных цветов — по две на каждой оси x, y, z, и все они соединяются в начале координат, — как показано на рисунке ниже. Обратите внимание, как пересекаются все сферы.

(Примерно) предполагаемый результат

Поскольку эта фигура создана в Matlab, я попытался преобразовать фигуру в pgfplotsкод, используя matlab2tikz, но это не сработало. Ниже приведен Matlabкод для фигуры.

Theta=linspace(0,2*pi,200);
Phi=linspace(-pi/2,pi/2,200);
[theta,phi]=meshgrid(Theta,Phi);

rho1=cos(theta).*cos(phi);
rho2=-cos(theta).*cos(phi);
rho3=sin(theta).*cos(phi);
rho4=-sin(theta).*cos(phi);
rho5=sin(phi);
rho6=-sin(phi);

[x1,y1,z1]=sph2cart(theta,phi,rho1);
[x2,y2,z2]=sph2cart(theta,phi,rho2);
[x3,y3,z3]=sph2cart(theta,phi,rho3);
[x4,y4,z4]=sph2cart(theta,phi,rho4);
[x5,y5,z5]=sph2cart(theta,phi,rho5);
[x6,y6,z6]=sph2cart(theta,phi,rho6);

surf(x1,y1,z1,'FaceColor','red','EdgeColor','none')
hold on
surf(x2,y2,z2,'FaceColor','red','EdgeColor','none')
surf(x3,y3,z3,'FaceColor','blue','EdgeColor','none')
surf(x4,y4,z4,'FaceColor','blue','EdgeColor','none')
surf(x5,y5,z5,'FaceColor','green','EdgeColor','none')
surf(x6,y6,z6,'FaceColor','green','EdgeColor','none')

alpha(0.6)
camlight left
lighting flat

Далее я попробовал нарисовать фигуру в tikz-3dplotи pst-solides3d. При обоих этих методах у меня возникла проблема, что поверхности не пересекались. Вместо этого 2-мерные проекции сфер рисовались отдельно на холсте, одна поверх другой, как показано на рисунках ниже. Первая фигура — это вывод из tikz-3dplot, а вторая фигура — это вывод из pst-solides3d.

Попытка с tikz-3dplot Попытка с pst-solides3d

При использовании tikz-3dplotу меня также возникла проблема с некоторыми осями, которые казались находящимися поверх сфер, хотя они должны были находиться внутри них (см. отрицательную половину оси Y).

Ниже приведены коды для вышеуказанных рисунков в том же порядке.

\documentclass[11pt]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{tikz,tikz-3dplot}
    \usetikzlibrary{arrows}

\begin{document}

\tdplotsetmaincoords{70}{135}

\begin{tikzpicture}[tdplot_main_coords,fill  opacity=.5,>=latex]
\pgfsetlinewidth{.1pt}

\tdplotsphericalsurfaceplot{72}{36}{4*abs(cos(\tdplotphi)*sin(\tdplottheta))}{black!85!white}{blue}
{\draw[color=black,thick,->]  (-6,0,0) --  (6,0,0)  node[anchor=north  east]{\textbf{x}};}
{\draw[color=black,thick,->]  (0,-6,0) --  (0,6,0)  node[anchor=north  west]{\textbf{y}};}
{\draw[color=black,thick,->]  (0,0,-6) --  (0,0,6)  node[anchor=south]{\textbf{z}};}

\tdplotsphericalsurfaceplot{72}{36}{4*abs(cos(\tdplottheta))}{black!85!white}{green}
{\draw[color=black,ultra thin,->]  (-6,0,0) --  (6,0,0)  node[anchor=north  east]{};}
{\draw[color=black,ultra thin,->]  (0,-6,0) --  (0,6,0)  node[anchor=north  west]{};}
{\draw[color=black,ultra thin,->]  (0,0,-6) --  (0,0,6)  node[anchor=south]{};}

\tdplotsphericalsurfaceplot{72}{36}{4*abs(sin(\tdplotphi)*sin(\tdplottheta))}{black!85!white}{red}
{\draw[color=black,ultra thin,->]  (-6,0,0) --  (6,0,0)  node[anchor=north  east]{};}
{\draw[color=black,ultra thin,->]  (0,-6,0) --  (0,6,0)  node[anchor=north  west]{};}
{\draw[color=black,ultra thin,->]  (0,0,-6) --  (0,0,6)  node[anchor=south]{};}

\end{tikzpicture}

\end{document}

\documentclass[11pt]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{pstricks,pst-solides3d}

\begin{document}

\begin{pspicture}(-6,-6)(6,6)

\psset{viewpoint=100  100  100,Decran=150}
\axesIIID[showOrigin=true,mathLabel=false,axisemph=\textbf,labelsep=8pt](-7,-7,-7)(7,7,7)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=green,linecolor=black!85!white,linewidth=0.5pt,opacity=0.6,ngrid=15 24,name=green2](0,0,-2)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=blue,linecolor=black!85!white,linewidth=0.5pt,opacity=0.6,ngrid=15 24,name=blue2](-2,0,0)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=red,linecolor=black!85!white,linewidth=0.5pt,opacity=0.6,ngrid=15 24,name=red2](0,-2,0)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=green,linecolor=black!85!white,linewidth=0.5pt,opacity=0.6,ngrid=15 24,name=green1](0,0,2)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=red,linecolor=black!85!white,linewidth=0.5pt,opacity=0.6,ngrid=15 24,name=red1](0,2,0)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=blue,linecolor=black!85!white,linewidth=0.5pt,opacity=0.6,ngrid=15 24,name=blue1](2,0,0)

\end{pspicture}

\end{document}

Как мне получить желаемый результат и сделать так, чтобы сферы действительно пересекались, как показано на первом рисунке? Могу ли я что-то добавить к моим методам выше, чтобы сферы пересекались? Если нет, есть ли другие методы, которые я могу использовать, чтобы получить желаемый результат? Выходные данные должны быть векторной графикой и использовать тот же шрифт, что и основной документ.

решение1

Вы можете использовать object=fusionдля объединения всех сфер в один объект. Для этого также необходимо установить опцию solidmemory:

\documentclass[11pt]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{pstricks,pst-solides3d}

\begin{document}

\begin{pspicture}(-6,-6)(6,6)

\psset{viewpoint=100  100  100,Decran=150}
\axesIIID[showOrigin=true,mathLabel=false,axisemph=\textbf,labelsep=8pt](-7,-7,-7)(7,7,7)
\psset{linecolor=black!85!white,linewidth=0.5pt, opacity=0.6, strokeopacity=0.6,
       object=sphere, r=2, ngrid=15 24, action=none, solidmemory, grid}
\psSolid[fillcolor=green, name=green2](0,0,-2)
\psSolid[fillcolor=blue, name=blue2](-2,0,0)
\psSolid[fillcolor=red, name=red2](0,-2,0)
\psSolid[fillcolor=green, name=green1](0,0,2)
\psSolid[fillcolor=red, name=red1](0,2,0)
\psSolid[fillcolor=blue, name=blue1](2,0,0)

\psSolid[object=fusion, base=green1 green2 red1 red2 blue1 blue2, action=draw**]

\end{pspicture}

\end{document}

введите описание изображения здесь

решение2

\documentclass[pstricks]{standalone}
\usepackage{pst-solides3d}
\begin{document}

\begin{pspicture}(-6,-6)(6,6)
\psset{viewpoint=100 100 100,Decran=150,solidmemory,object=sphere,r=2,
   action=none,linewidth=0.5pt,ngrid=45 60,linecolor=black!85!white}
\axesIIID[mathLabel=false,axisemph=\textbf,labelsep=8pt](-7,-7,-7)(7,7,7)
\psSolid[fillcolor=green,name=green2](0,0,-2)
\psSolid[fillcolor=blue,name=blue2](-2,0,0)
\psSolid[fillcolor=red,name=red2](0,-2,0)
\psSolid[fillcolor=green,name=green1](0,0,2)
\psSolid[fillcolor=red,name=red1](0,2,0)
\psSolid[fillcolor=blue,name=blue1](2,0,0)
\psSolid[object=fusion,base=green2 blue2 red2 green1 red1 blue1,action=draw**,opacity=0.9]
\end{pspicture}

\end{document}

введите описание изображения здесь

То же самое с источником света:

\documentclass[pstricks]{standalone}
\usepackage{pst-solides3d}
\begin{document}

\begin{pspicture}(-6,-6)(6,6)
\psset{viewpoint=60 45 30 rtp2xyz,lightsrc=viewpoint,
  Decran=60,solidmemory,object=sphere,r=2,
  action=none,linewidth=0.5pt,
  ngrid=45 60,linecolor=black!45!white}
\axesIIID[axisemph=\mathbf,labelsep=8pt](-5,-5,-5)(5,5,5)
\psSolid[fillcolor=green,name=green2](0,0,-2)
\psSolid[fillcolor=blue,name=blue2](-2,0,0)
\psSolid[fillcolor=red,name=red2](0,-2,0)
\psSolid[fillcolor=green,name=green1](0,0,2)
\psSolid[fillcolor=red,name=red1](0,2,0)
\psSolid[fillcolor=blue,name=blue1](2,0,0)
\psSolid[object=fusion,base=green2 blue2 red2 green1 red1 blue1,action=draw**,opacity=0.7,grid]
\end{pspicture}

\end{document}

введите описание изображения здесь

решение3

Вот решение для pstricks, но оно не очень хорошее.

Томас

\documentclass[11pt]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{pstricks,pst-solides3d}

\begin{document}

\begin{pspicture}(-6,-6)(6,6)

\psset{viewpoint=100 100 100,Decran=150,solidmemory}
\axesIIID[showOrigin=true,mathLabel=false,axisemph=\textbf,labelsep=8pt](-7,-7,-7)(7,7,7)

\psSolid[object=sphere,r=2,action=draw*,fillcolor=green,linecolor=black!85!white,linewidth=0.5pt,ngrid=45 60,name=green2,action=none](0,0,-2)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=blue,linecolor=black!85!white,linewidth=0.5pt,ngrid=45 60,name=blue2,action=none](-2,0,0)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=red,linecolor=black!85!white,linewidth=0.5pt,ngrid=45 60,name=red2,action=none](0,-2,0)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=green,linecolor=black!85!white,linewidth=0.5pt,ngrid=45 60,name=green1,action=none](0,0,2)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=red,linecolor=black!85!white,linewidth=0.5pt,ngrid=45 60,name=red1,action=none](0,2,0)
\psSolid[object=sphere,r=2,action=draw*,fillcolor=blue,linecolor=black!85!white,linewidth=0.5pt,ngrid=45 60,name=blue1,action=none](2,0,0)

\psSolid[object=fusion,base=green2 blue2 red2 green1 red1 blue1,action=draw**,opacity=0.7,linewidth=0.01pt,grid]
\end{pspicture}

\end{document}

введите описание изображения здесь

решение4

Поработав с решениями, представленными здесь, я решил дать свой собственный, обобщенный ответ. Основываясь на предыдущих ответах, кажется,pst-solides3d — лучший вариант. (Чарльз Стаатс предлагаетасимптотакак еще один возможный метод.) Как указал Кристоф, можно сделать так, чтобы сферы пересекались object=fusion(что также требует опции solidmemory). Для меня это работает только тогда, когда действие объекта слияния установлено на draw**(см. обсуждение ниже ответа Кристофа).

Ответ Герберта показывает два других примера, один с линиями сетки и один с освещением. Ответ Томаса С показывает похожий пример как без освещения, так и без линий сетки.

Примеры Герберта и Кристофа показывают, как можно писать код более эффективно.

Однако во всех этих примерах оси рисуются под сферами, поскольку оси не являются частью слияния. Мое решение этой проблемы — нарисовать два набора осей друг над другом. Первый рисуется под сферами, а второй — поверх сфер, где это уместно.

В моем примере я увеличил разрешение сфер до максимума (более высокие разрешения, похоже, приводят к сбоям в работе компилятора), чтобы сделать пересечения максимально плавными. Я также добавил освещение и уменьшил интенсивность цветов, чтобы сделать результат более приятным для глаз.

Спасибо за вашу помощь.

ИЗМЕНИТЬ: Язык.

\documentclass[11pt]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{pstricks,pst-solides3d}

\begin{document}

\begin{pspicture}(-6,-6)(6,6)

\psset{lightsrc=100 50 130,viewpoint=100 100 100,Decran=150}
\axesIIID[showOrigin=true,axisnames={}](-6.5,-6.5,-6.5)(6.5,6.5,6.5)

\psset{linewidth=0.5pt,opacity=0.7,object=sphere,r=2,ngrid=39 90,action=none,solidmemory,grid}

\psSolid[fillcolor=green!70!gray,name=green2](0,0,-2)
\psSolid[fillcolor=blue!70!gray,name=blue2](-2,0,0)
\psSolid[fillcolor=red!70!gray,name=red2](0,-2,0)
\psSolid[fillcolor=green!70!gray,name=green1](0,0,2)
\psSolid[fillcolor=red!70!gray,name=red1](0,2,0)
\psSolid[fillcolor=blue!70!gray,name=blue1](2,0,0)

\psSolid[object=fusion,base=green1 green2 red1 red2 blue1 blue2,action=draw**]

\psset{linewidth=0.8pt,opacity=1}
\axesIIID[showOrigin=false,mathLabel=false,axisemph=\textbf,labelsep=8pt](4,4,4)(6.5,6.5,6.5)

\end{pspicture}

\end{document}

Конечный результат

Связанный контент