2D Vertex Model
geometrical f(x)
geometrical f(x)
In[]:=
(*getvertexinthelistbyccworder*)Clear[getCounterClockwise];getCounterClockwise[vertex_,vertices_]:=Block[{pos,v},pos=First@@Position[vertices,vertex];If[posLength[vertices],pos=1,pos+=1];vertices[[pos]]];
In[]:=
(*getvertexinthelistbycworder*)Clear[getClockwise];getClockwise[vertex_,vertices_]:=Block[{ls,pos},pos=First@@Position[vertices,vertex];If[pos1,pos=Length[vertices],pos-=1];vertices[[pos]]];
In[]:=
getCounterClockwise[{,},{{,},{,},{,},d,e}]
x
i
y
i
x
i-1
y
i-1
x
i
y
i
x
i+1
y
i+1
Out[]=
{,}
x
1+i
y
1+i
In[]:=
getClockwise[{,},{{,},{,},{,},d,e}]
x
i
y
i
x
i-1
y
i-1
x
i
y
i
x
i+1
y
i+1
Out[]=
{,}
x
-1+i
y
-1+i
In[]:=
Clear[areaOfPolygon];areaOfPolygon[cells_/;Head[cells]===Association]:=Map[Area@*Polygon,cells];
In[]:=
Clear[areaPolygon];areaPolygon[vertices_]:=Block[{edges},edges=Partition[vertices,2,1,1];0.5Abs@Total[(#[[1,1]]*#[[2,2]])-(#[[2,1]]*#[[1,2]])&/@edges]]
In[]:=
randpoly=Polygon;
In[]:=
Area[randpoly]
Out[]=
0.287052
In[]:=
areaPolygon[MeshPrimitives[randpoly,0]/.PointSequence]
Out[]=
0.287052
In[]:=
Clear[perimeterOfPolygon];perimeterOfPolygon[cells_/;Head[cells]===Association]:=(Perimeter@*Polygon)/@cells;
In[]:=
Clear[perimeterPolygon];perimeterPolygon[vertices_]:=Block[{edges},edges=Partition[vertices,2,1,1];Total[Apply[EuclideanDistance]/@edges]]
In[]:=
Perimeter@randpoly
Out[]=
2.4033
In[]:=
perimeterPolygon[MeshPrimitives[randpoly,0]/.PointSequence]
Out[]=
2.4033
In[]:=
Clear[centroidPolygon];centroidPolygon[vertices_]:=Mean[vertices]
In[]:=
(*counterclockwisepolygonQ*)Block{signedarea=0,j,vertlen=5},Doj=Mod[i,vertlen]+1;signedarea+=(-),{i,vertlen};Echo(signedarea);
x
i
y
j
x
j
y
i
1
2
»
1
2
x
2
y
1
x
5
y
1
x
1
y
2
x
3
y
2
x
2
y
3
x
4
y
3
x
3
y
4
x
5
y
4
x
1
y
5
x
4
y
5
In[]:=
Clear[polyCounterClockwiseQ];polyCounterClockwiseQ[poly_]:=Block[{area=0,j,vertLength=Length[poly]},Do[j=Mod[i,vertLength]+1;area+=poly[[i,1]]*poly[[j,2]];area-=poly[[j,1]]*poly[[i,2]],{i,vertLength}];(area/2.)>0]
In[]:=
(*Clear[sortCC];sortCC[polyinds_,indTopts_,ptsToInds_]:=Block[{cent,poly},poly=Lookup[indTopts,polyinds];Lookup[ptsToInds,DeleteDuplicates@Flatten[MeshPrimitives[ConvexHullMesh[poly],1]/.LineSequence,1]]];*)
In[]:=
(*sortpointsforaconvexpolygonincounter-clockwisedirection*)
In[]:=
Clear[sortPointsCC];sortPointsCC[polyinds_,indTopts_,ptsToInds_]:=Block[{cent,ordering,polyPoints},polyPoints=Lookup[indTopts,polyinds];cent=Mean[polyPoints];ordering=Ordering[ArcTan[#[[1]],#[[2]]]&@(#-cent)&/@polyPoints];Lookup[ptsToInds,Part[polyPoints,ordering]]]
mesh restructuring operations
mesh restructuring operations
In[]:=
bagged=CreateDataStructure["DynamicArray"]
Out[]=
DataStructure
T1 transition
T1 transition
In[]:=
(*T1transition:neighbourswitching*)
In[]:=
Clear@edgesforT1;edgesforT1[edgeLs_,indToPts_,threshLength_:0.002]:=Block[{edges,dist,bool},edges=Lookup[indToPts,#]&/@edgeLs;dist=EuclideanDistance@@#&/@edges;bool=Thread[dist≤threshLength];{Pick[edges,bool,True],Pick[edgeLs,bool,True]}];
In[]:=
Clear@T1transitionFn;T1transitionFn[edges_,indToPtsAssoc_,vertexToCellG_,cellToVertexG_,dSep_:0.0075]:=Block{findEdges,edgeind,connectedcellKeys,edge,newpts,cellvertIndices,cellvertices,pos,cellpolys,memF,keyscellP,selcellKeys,ptToCell,newptsindices,indToPts=indToPtsAssoc,ptsToInds,PtIndToCell,keysToMap,cellindicesAssoc,f1,otherkeys,f2,polysharingEdge,bag=bagged,vertToCellG=vertexToCellG,cellToVertG=cellToVertexG,testpts,edgechanged,localtopology,ls,cs,cc,ccw,trimmedtopo,ordering,edgeordered},{edgechanged,findEdges}=edgesforT1[edges,indToPts];(*findingallpossibleedgesforT1transition*)IffindEdges≠{},Scanedgeind=#;IfContainsAll[Keys[indToPts],edgeind],(*shouldbeanedgenotconnectedtoanedgethathasalreadyundergoneaT1*)connectedcellKeys=DeleteDuplicates[Flatten@Lookup[vertToCellG,edgeind]];cellvertIndices=Lookup[cellToVertG,connectedcellKeys];edge=Lookup[indToPts,edgeind];IfLength[connectedcellKeys]1,(*edgethatisexposedtothevoidtobemergedasasinglevertex*)newpts=Mean[edge];newptsindices=Max[Keys@indToPts]+1;KeyDropFrom[indToPts,edgeind];AppendTo[indToPts,newptsindicesnewpts];bag["Append",edgeind];ptsToInds=AssociationMap[Reverse,indToPts];cellToVertG=MapAt[DeleteDuplicates[#/.(Alternatives@@edgeind)newptsindices]&,cellToVertG,Key[connectedcellKeys/.{z_Integer}z]],(*elseproceedwithT1transition*)newpts=With{midPt=Mean[edge]},midPt+dSepNormalize[(#-midPt)]&/@FlattenRotationTransform-,midPt/@{edge},1;testpts=With[{midPt=Mean[edge]},midPt+0.000001Normalize[(#-midPt)]&/@newpts];pos=Position[cellvertIndices,{OrderlessPatternSequence[___,First@edgeind,___,Last@edgeind,___]},{1}];polysharingEdge=Extract[cellvertIndices,pos];(*theedgeshouldnotbepartofanyΔ*)If[(AllTrue[polysharingEdge,Length[#]≠3&])&&ContainsNone[edgeind,Union@*Flatten@*Normal@bag],cellvertices=Map[Lookup[indToPts,#]&,cellvertIndices];cellpolys=Polygon/@cellvertices;memF=Function[x,RegionMember@*DiscretizeRegion@x,Listable][Extract[cellpolys,pos]];keyscellP=Extract[connectedcellKeys,pos];selcellKeys=Thread[keyscellPmemF];ptToCell=Quiet[#First@@Select[selcellKeys,Function[x,Last[x][#]]]&/@testpts/.HoldPattern[_First[]]Nothing];(*pttocell*)ptToCell=ptToCell/.Thread[testptsnewpts];newptsindices=Range[#+1,#+2]&[Max[Keys@indToPts]];AppendTo[indToPts,Thread[newptsindicesnewpts]];ptsToInds=AssociationMap[Reverse,indToPts];bag["Append",edgeind];PtIndToCell=MapAt[ptsToInds,ptToCell,{All,1}]/.RuleList;(*indextocell*)keysToMap=MapAt[Key,PtIndToCell,{All,2}];cellindicesAssoc=AssociationThread[connectedcellKeys,cellvertIndices];f1=Fold[MapAt[Function[x,DeleteDuplicates[x/.Thread[edgeind#2[[1]]]]],#1,#2[[2]]]&,cellindicesAssoc,keysToMap];f1=Lookup[indToPts,#]&/@f1;KeyDropFrom[indToPts,edgeind];otherkeys=List@*Key/@Complement[connectedcellKeys,keyscellP];(*Print@Graphics[{EdgeForm[Black],FaceForm[Red],Polygon/@cellvertices},ImageSizeTiny];*)localtopology=AssociationThread[connectedcellKeyscellvertices];ls=Lookup[localtopology,First@@otherkeys];cs=FirstCase[ls,Alternatives@@edge];cc=getClockwise[cs,ls];ccw=getCounterClockwise[cs,ls];trimmedtopo=KeyDrop[localtopology,connectedcellKeys~Complement~keyscellP];ordering={FirstCase[Position[trimmedtopo,cc],x:{Key[First@keyscellP],_}|{Key[Last@keyscellP],_}First@@x],FirstCase[Position[trimmedtopo,ccw],x:{Key[First@keyscellP],_}|{Key[Last@keyscellP],_}First@@x]};If[Length[otherkeys]1,edgeordered=ordering/.Reverse[ptToCell,2];f2=MapAt[Replace[#,Alternatives@@edgeSplice[edgeordered],{1}]&,f1,First@otherkeys];(*Print@Graphics[{EdgeForm[Black],FaceForm[Red],Polygon/@Values@f2},ImageSizeTiny];*),If[MatchQ[ordering,{_Missing,_}|{_,_Missing}],ordering=Flatten[ordering/._MissingComplement[newpts,Keys@ptToCell],1];edgeordered=ordering,edgeordered=ordering/.Reverse[ptToCell,2];];f2=MapAt[Replace[#,Alternatives@@edgeSplice[edgeordered],{1}]&,f1,First@otherkeys];f2=MapAt[Replace[#,Alternatives@@edgeSplice[Reverse[edgeordered]],{1}]&,f2,Last@otherkeys];(*Print@Graphics[{EdgeForm[Black],FaceForm[Red],Polygon/@Values@f2},ImageSizeTiny];*)];AppendTo[cellToVertG,Lookup[ptsToInds,#]&/@f2];];;vertToCellG=GroupBy[Flatten[(Reverse[#,2]&)@*Thread/@Normal@cellToVertG],FirstLast];&,findEdges;bagged["DropAll"];{edgechanged,indToPts,cellToVertG,vertToCellG};
π
2
T2 transition
T2 transition
T3 transition
T3 transition
cell division
cell division
Difference from Farahdifar's paper: in his article he dilates the cells before dividing them. Here I randomly select a cell and divide it into two.
force computation
force computation
create mesh
create mesh
run simulation 1
run simulation 1
run simulation 2
run simulation 2