in core/indigo-core/layout/src/molecule_layout_graph_assign_smart.cpp [289:1017]
void MoleculeLayoutGraphSmart::_assignEveryCycle(const Cycle& cycle)
{
profTimerStart(t, "_assignFirstCycle");
const int size = cycle.vertexCount();
_first_vertex_idx = cycle.getVertex(0);
MoleculeLayoutMacrocyclesLattice layout(size);
if (size <= 6)
for (int i = 0; i < size; i++)
_molecule->cis_trans.setParity(_layout_edges[cycle.getEdge(i)].orig_idx, 0);
for (int i = 0; i < size; i++)
{
// edge parallels
// !!
int order_next = 0;
int edge_number = cycle.getEdge(i);
LayoutEdge edge = _layout_edges[edge_number];
int ext_edge_number = edge.orig_idx;
int order = _molecule->getBondOrder(ext_edge_number);
switch (order)
{
case BOND_SINGLE:
order_next = 1;
break;
case BOND_DOUBLE:
order_next = 2;
break;
case BOND_TRIPLE:
order_next = 3;
break;
default:
order_next = 1;
}
int order_prev;
int ext_edge_number_prev = _layout_edges[cycle.getEdgeC(i - 1)].orig_idx;
switch (_molecule->getBondOrder(ext_edge_number_prev))
{
case BOND_SINGLE:
order_prev = 1;
break;
case BOND_DOUBLE:
order_prev = 2;
break;
case BOND_TRIPLE:
order_prev = 3;
break;
default:
order_prev = 1;
}
layout.setVertexEdgeParallel(i, order_next + order_prev >= 4);
// tras-cis configuration
int next_vertex = _layout_vertices[cycle.getEdgeFinish(i + 1)].orig_idx;
int prev_vertex = _layout_vertices[cycle.getEdgeStart(i - 1)].orig_idx;
if (_molecule->cis_trans.getParity(ext_edge_number))
{
int _sameside = _molecule->cis_trans.sameside(ext_edge_number, prev_vertex, next_vertex);
if (_sameside)
layout.setEdgeStereo(i, MoleculeCisTrans::CIS);
else
layout.setEdgeStereo(i, MoleculeCisTrans::TRANS);
}
else
{
// if (_layout_vertices[cycle.getVertex(i)].type != ELEMENT_NOT_DRAWN &&
// _layout_vertices[cycle.getVertex((i + 1) % size)].type != ELEMENT_NOT_DRAWN) {
if (_layout_edges[cycle.getEdge(i)].type != ELEMENT_NOT_DRAWN)
{
Vec2f prev_point;
if (_layout_edges[cycle.getEdgeC(i - 1)].type != ELEMENT_NOT_DRAWN)
prev_point = _layout_vertices[cycle.getVertexC(i - 1)].pos;
else
{
for (int j = getVertex(cycle.getVertex(i)).neiBegin(); j != getVertex(cycle.getVertex(i)).neiEnd();
j = getVertex(cycle.getVertex(i)).neiNext(j))
if (_layout_edges[getVertex(cycle.getVertex(i)).neiEdge(j)].type != ELEMENT_NOT_DRAWN &&
getVertex(cycle.getVertex(i)).neiVertex(j) != cycle.getVertexC(i + 1))
prev_point = _layout_vertices[getVertex(cycle.getVertex(i)).neiVertex(j)].pos;
}
Vec2f next_point;
if (_layout_edges[cycle.getEdgeC(i + 1)].type != ELEMENT_NOT_DRAWN)
next_point = _layout_vertices[cycle.getVertexC(i + 2)].pos;
else
{
for (int j = getVertex(cycle.getVertexC(i + 1)).neiBegin(); j != getVertex(cycle.getVertexC(i + 1)).neiEnd();
j = getVertex(cycle.getVertexC(i + 1)).neiNext(j))
if (_layout_edges[getVertex(cycle.getVertexC(i + 1)).neiEdge(j)].type != ELEMENT_NOT_DRAWN &&
getVertex(cycle.getVertexC(i + 1)).neiVertex(j) != cycle.getVertex(i))
next_point = _layout_vertices[getVertex(cycle.getVertexC(i + 1)).neiVertex(j)].pos;
}
int _sameside =
_isCisConfiguratuin(prev_point, _layout_vertices[cycle.getVertexC(i)].pos, _layout_vertices[cycle.getVertexC(i + 1)].pos, next_point);
if (_layout_edges[cycle.getEdgeC(i - 1)].type != ELEMENT_NOT_DRAWN && _layout_edges[cycle.getEdgeC(i + 1)].type != ELEMENT_NOT_DRAWN)
{
if (_sameside)
layout.setEdgeStereo(i, MoleculeCisTrans::CIS);
else
layout.setEdgeStereo(i, MoleculeCisTrans::TRANS);
}
else
{
if ((_layout_edges[cycle.getEdgeC(i - 1)].type != ELEMENT_NOT_DRAWN) ^ (_layout_edges[cycle.getEdgeC(i + 1)].type != ELEMENT_NOT_DRAWN))
{
if (_sameside)
layout.setEdgeStereo(i, MoleculeCisTrans::TRANS);
else
layout.setEdgeStereo(i, MoleculeCisTrans::CIS);
}
else
layout.setEdgeStereo(i, MoleculeCisTrans::CIS);
}
}
}
layout.setVertexDrawn(i, _layout_vertices[cycle.getVertex(i)].type != ELEMENT_NOT_DRAWN);
// trees sizes
}
/*
* A patrial fix for Ketcher issues 486 and 487
*
* The _segment_smoothing_prepearing() contains an error which leads to
* a crash when cycles with double bonds are being processed. Currently,
* we skip smoothing altogether. This seems not to create any regressions
*/
QS_DEF(ObjArray<MoleculeLayoutSmoothingSegment>, segment);
QS_DEF(Array<Vec2f>, rotation_point);
QS_DEF(Array<int>, rotation_vertex);
segment.clear();
rotation_point.zerofill();
rotation_vertex.zerofill();
// _segment_smoothing_prepearing(cycle, rotation_vertex, rotation_point, segment, layout);
int segment_count = segment.size();
for (int i = 0; i < segment_count; i++)
{
for (int v = segment[i]._graph.vertexBegin(); v != segment[i]._graph.vertexEnd(); v = segment[i]._graph.vertexNext(v))
{
if (segment[i].is_start(v))
if (segment[i]._graph.getVertex(v).degree() > 2)
layout.setEdgeStereo(rotation_vertex[i], 0);
if (segment[i].is_finish(v))
if (segment[i]._graph.getVertex(v).degree() > 2)
layout.setEdgeStereo((rotation_vertex[(i + 1) % segment_count] - 1 + size) % size, 0);
}
}
/*bool easy_case = size <= 9;
if (easy_case) {
QS_DEF(Array<int>, last);
last.clear_resize(_layout_component_count);
last.fill(-1);
for (int i = 0; i < size; i++) {
int comp = _layout_component_number[cycle.getEdge(i)];
if (comp >= 0) {
if (last[comp] >= 0) easy_case = false;
last[comp] = i;
}
}
QS_DEF(Array<int>, order);
order.clear_resize(size);
for (int i = 0; i < size; i++) {
order[i] = _molecule->getBondOrder(getEdgeOrigIdx(cycle.getEdge(i)));
if (order[i] > 3) order[i] = 1;
}
order.push(order[0]);
for (int i = 0; i < size; i++) easy_case &= (order[i] + order[i + 1] < 4);
for (int i = 0; i < size; i++) {
int next_vertex = _layout_vertices[cycle.getEdgeFinish(i + 1)].orig_idx;
int prev_vertex = _layout_vertices[cycle.getEdgeStart(i - 1)].orig_idx;
if (_molecule->cis_trans.getParity(getEdgeOrigIdx(cycle.getEdge(i)))) {
easy_case &= _molecule->cis_trans.sameside(getEdgeOrigIdx(cycle.getEdge(i)), prev_vertex, next_vertex);
}
}
if (easy_case) {
for (int i = 0; i < size; i++) {
layout.getPos(cycle.getVertex(i)) = Vec2f(1, 0);
layout.getPos(cycle.getVertex(i)).rotate(2 * M_PI / size * i);
}
for (int i = 0; i < size; i++)
if (getVertexType(cycle.getVertex(i)) == ELEMENT_NOT_DRAWN)
getPos(cycle.getVertex(i)) = layout.getPos(i);
for (int i = 0; i < size; i++)
{
setVertexType(cycle.getVertex(i), ELEMENT_DRAWN);
setEdgeType(cycle.getEdge(i), ELEMENT_DRAWN);
}
}
*/
// printf("%d do layout cycle \n", size);
// calculate target angle
for (int s = 0; s < segment_count; s++)
{
for (int i = rotation_vertex[s]; i != rotation_vertex[(s + 1) % segment_count]; i = (i + 1) % size)
{
int prev_layout_component = _layout_component_number[cycle.getEdgeC(i - 1)];
int next_layout_component = _layout_component_number[cycle.getEdge(i)];
if (prev_layout_component < 0 && next_layout_component < 0)
{
layout.setTargetAngle(i, _2FLOAT(2. * M_PI / 3.));
layout.setAngleImportance(i, 0.2f);
}
else if ((prev_layout_component < 0) ^ (next_layout_component < 0))
{
const MoleculeLayoutSmoothingSegment& calc_segment = prev_layout_component < 0 ? segment[s] : segment[(s + segment_count - 1) % segment_count];
int calc_vertex = prev_layout_component < 0 ? calc_segment.get_start() : calc_segment.get_finish();
Cycle border;
calc_segment._graph._getBorder(border);
int calc_vertex_in_border = -1;
for (int j = 0; j < border.vertexCount(); j++)
{
if (border.getVertex(j) == calc_vertex)
{
calc_vertex_in_border = j;
break;
}
}
float angle = 0;
int prev_vertex = -1;
int next_vertex = -1;
if (border.vertexCount() != 0 && calc_vertex_in_border >= 0)
{
prev_vertex = border.getVertexC(calc_vertex_in_border - 1);
next_vertex = border.getVertexC(calc_vertex_in_border + 1);
}
else
{
for (int n : calc_segment._graph.getVertex(calc_vertex).neighbors())
{
int v = calc_segment._graph.getVertex(calc_vertex).neiVertex(n);
if (prev_vertex < 0 || calc_segment.getIntPosition(v).y > calc_segment.getIntPosition(prev_vertex).y)
prev_vertex = v;
if (next_vertex < 0 || calc_segment.getIntPosition(v).y < calc_segment.getIntPosition(next_vertex).y)
next_vertex = v;
}
if (next_layout_component < 0)
{
int temp = prev_vertex;
prev_vertex = next_vertex;
next_vertex = temp;
}
}
angle = (calc_segment.getIntPosition(next_vertex) - calc_segment.getIntPosition(calc_vertex)).tiltAngle2();
angle -= (calc_segment.getIntPosition(prev_vertex) - calc_segment.getIntPosition(calc_vertex)).tiltAngle2();
while (angle < 0.f)
angle += _2FLOAT(2. * M_PI);
while (angle >= _2FLOAT(2. * M_PI))
angle -= _2FLOAT(2 * M_PI);
layout.setTargetAngle(i, _2FLOAT(M_PI - angle / 2.));
}
else if (prev_layout_component == next_layout_component)
{
float angle = (getPos(cycle.getVertexC(i - 1)) - getPos(cycle.getVertexC(i))).tiltAngle2();
angle -= (getPos(cycle.getVertexC(i + 1)) - getPos(cycle.getVertexC(i))).tiltAngle2();
while (angle < 0.f)
angle += _2FLOAT(2. * M_PI);
while (angle >= _2FLOAT(2. * M_PI))
angle -= _2FLOAT(2. * M_PI);
if (angle > _2FLOAT(M_PI))
angle = _2FLOAT(2. * M_PI - angle);
layout.setTargetAngle(i, angle);
}
// temporary value
else
{
layout.setTargetAngle(i, _2FLOAT(M_PI));
layout.setAngleImportance(i, 0.2f);
}
}
}
QS_DEF(Array<int>, _is_vertex_taken);
enum
{
NOT_CONSIDERED,
IN_LIST,
NOT_IN_LIST
};
QS_DEF(Array<int>, _list_of_vertex);
QS_DEF(Array<int>, _segment_weight_outside);
_segment_weight_outside.clear_resize(segment_count);
_segment_weight_outside.zerofill();
for (int i = 0; i < size; i++)
if (_layout_component_number[cycle.getEdge(i)] < 0)
_layout_component_number[cycle.getEdge(i)] = _layout_component_count;
_layout_component_count++;
QS_DEF(Array<bool>, _is_layout_component_incoming);
_is_layout_component_incoming.clear_resize(_layout_component_count);
_is_layout_component_incoming.zerofill();
for (int i = 0; i < size; i++)
_is_layout_component_incoming[_layout_component_number[cycle.getEdge(i)]] = true;
for (int i = 0; i < segment_count; i++)
{
for (int up = 0; up <= 1; up++)
{
_is_vertex_taken.clear_resize(_graph->vertexEnd());
_is_vertex_taken.fill(NOT_CONSIDERED);
if (i == segment_count - 1)
{
// int x = 5;
}
_list_of_vertex.clear_resize(0);
bool is_segment_trivial =
segment[i].get_layout_component_number() == -1 && segment[(i + segment_count - 1) % segment_count].get_layout_component_number() == -1 && up;
for (int v = segment[i]._graph.vertexBegin(); v != segment[i]._graph.vertexEnd(); v = segment[i]._graph.vertexNext(v))
{
if ((!segment[i].is_finish(v) && !segment[i].is_start(v) && segment[i].isVertexUp(v) ^ !up) || (is_segment_trivial && !segment[i].is_finish(v)))
{
int ext_v = segment[i]._graph.getVertexExtIdx(v);
_is_vertex_taken[getVertexExtIdx(ext_v)] = IN_LIST;
_list_of_vertex.push(ext_v);
}
}
bool touch_to_another_segment = false;
for (int j = 0; j < _list_of_vertex.size(); j++)
{
const Vertex& vert = getVertex(_list_of_vertex[j]);
for (int n = vert.neiBegin(); n != vert.neiEnd(); n = vert.neiNext(n))
{
int vn = vert.neiVertex(n);
if (_is_vertex_taken[getVertexExtIdx(vn)] != NOT_CONSIDERED)
continue;
bool is_this_comp = false;
for (int n2 = getVertex(vn).neiBegin(); n2 != getVertex(vn).neiEnd(); n2 = getVertex(vn).neiNext(n2))
if (_layout_component_number[getVertex(vn).neiEdge(n2)] >= 0)
{
if (_is_layout_component_incoming[_layout_component_number[getVertex(vn).neiEdge(n2)]])
is_this_comp = true;
if (!is_segment_trivial && _layout_component_number[getVertex(vn).neiEdge(n2)] != segment[i].get_layout_component_number() &&
_layout_component_number[getVertex(vn).neiEdge(n2)] != _layout_component_count - 1)
touch_to_another_segment = true;
}
if (!is_this_comp)
{
_list_of_vertex.push(vn);
_is_vertex_taken[getVertexExtIdx(vn)] = IN_LIST;
}
else
_is_vertex_taken[getVertexExtIdx(vn)] = NOT_IN_LIST;
}
}
for (int j = 0; j < _list_of_vertex.size(); j++)
_list_of_vertex[j] = getVertexExtIdx(_list_of_vertex[j]);
for (int j = 0; j < _list_of_vertex.size(); j++)
{
const Vertex& vert = _graph->getVertex(_list_of_vertex[j]);
for (int n = vert.neiBegin(); n != vert.neiEnd(); n = vert.neiNext(n))
{
int vn = vert.neiVertex(n);
if (_is_vertex_taken[vn] != NOT_CONSIDERED)
continue;
_list_of_vertex.push(vn);
_is_vertex_taken[vn] = IN_LIST;
}
}
_segment_weight_outside[i] += (up ? 1 : -1) * (touch_to_another_segment ? 3 : 1) * _list_of_vertex.size();
}
}
QS_DEF(Array<int>, _index_in_cycle);
_index_in_cycle.clear_resize(vertexEnd());
_index_in_cycle.fffill();
for (int i = 0; i < size; i++)
_index_in_cycle[cycle.getVertex(i)] = i;
for (int i = 0; i < segment_count; i++)
{
if (segment[i].get_layout_component_number() < 0 && segment[(i + segment_count - 1) % segment_count].get_layout_component_number() < 0)
layout.addVertexOutsideWeight(rotation_vertex[i], _segment_weight_outside[i] - 1);
else
{
layout.setComponentFinish(rotation_vertex[i], rotation_vertex[(i + 1) % segment_count]);
layout.setVertexAddedSquare(rotation_vertex[i], segment[i].get_square());
Cycle border;
if (segment[i].get_layout_component_number() >= 0)
segment[i]._graph._getBorder(border);
int count_neibourhoods_outside = 0;
if (segment[i].get_layout_component_number() >= 0 && border.vertexCount() != 0)
{
int start_in_border = -1;
int finish_in_border = -1;
for (int j = 0; j < border.vertexCount(); j++)
{
if (border.getVertex(j) == segment[i].get_start())
start_in_border = j;
if (border.getVertex(j) == segment[i].get_finish())
finish_in_border = j;
}
if (start_in_border >= 0 && finish_in_border >= 0)
{
for (int j = (start_in_border + 1) % border.vertexCount(); j != finish_in_border; j = (j + 1) % border.vertexCount())
{
if (_index_in_cycle[segment[i]._graph.getVertexExtIdx(border.getVertex(j))] == (rotation_vertex[i] + 1) % size)
count_neibourhoods_outside++;
if (_index_in_cycle[segment[i]._graph.getVertexExtIdx(border.getVertex(j))] ==
(rotation_vertex[(i + 1) % segment_count] - 1 + size) % size)
count_neibourhoods_outside++;
}
for (int j = (finish_in_border + 1) % border.vertexCount(); j != start_in_border; j = (j + 1) % border.vertexCount())
{
if (_index_in_cycle[segment[i]._graph.getVertexExtIdx(border.getVertex(j))] == (rotation_vertex[i] + 1) % size)
count_neibourhoods_outside--;
if (_index_in_cycle[segment[i]._graph.getVertexExtIdx(border.getVertex(j))] ==
(rotation_vertex[(i + 1) % segment_count] - 1 + size) % size)
count_neibourhoods_outside--;
}
}
}
bool right_orientation;
if (count_neibourhoods_outside > 0)
right_orientation = true;
else if (count_neibourhoods_outside < 0)
right_orientation = false;
else
{
float y1 = 0, y2 = 0;
for (int v = segment[i]._graph.vertexBegin(); v != segment[i]._graph.vertexEnd(); v = segment[i]._graph.vertexNext(v))
{
if (_index_in_cycle[segment[i]._graph.getVertexExtIdx(v)] == (rotation_vertex[i] + 1) % size)
{
y1 = segment[i].getIntPosition(v).y;
}
if (_index_in_cycle[segment[i]._graph.getVertexExtIdx(v)] == (rotation_vertex[(i + 1) % segment_count] + size - 1) % size)
{
y2 = segment[i].getIntPosition(v).y;
}
}
if ((y1 + y2) / 2 > EPSILON || ((fabs((y1 + y2) / 2) <= EPSILON) && (y1 + y2) / 2 > segment[i].getIntCenter().y))
{
right_orientation = true;
}
else
{
right_orientation = false;
}
}
if (right_orientation)
{
layout.addVertexOutsideWeight(rotation_vertex[i], -_segment_weight_outside[i]);
layout.addVertexOutsideWeight(rotation_vertex[(i + 1) % segment_count], -_segment_weight_outside[i]);
}
else
{
layout.addVertexOutsideWeight(rotation_vertex[i], _segment_weight_outside[i]);
layout.addVertexOutsideWeight(rotation_vertex[(i + 1) % segment_count], _segment_weight_outside[i]);
}
}
}
layout.doLayout();
// now we must to smooth just made layout
// lets check if all cycle is layouted ealier in single biconnected compenent
/*int start = -1;
bool undrawn = false;
for (int i = 0; i < size; i++) undrawn |= _layout_vertices[cycle.getVertex(i)].type == ELEMENT_NOT_DRAWN;
if (undrawn) {
for (int i = size - 1; i >= 0; i--) if (_layout_vertices[cycle.getVertex(i)].type != ELEMENT_NOT_DRAWN) start = i;
if (start == 0 && _layout_vertices[cycle.getVertex(size - 1)].type != ELEMENT_NOT_DRAWN) {
while (_layout_vertices[cycle.getVertex(start)].type != ELEMENT_NOT_DRAWN) start = (start + 1) % size;
while (_layout_vertices[cycle.getVertex(start)].type == ELEMENT_NOT_DRAWN) start = (start + 1) % size;
}
}*/
QS_DEF(Array<bool>, need_to_insert);
need_to_insert.clear_resize(size);
need_to_insert.zerofill();
for (int i = 0; i < size; i++)
need_to_insert[i] = _layout_vertices[cycle.getVertex(i)].type != ELEMENT_NOT_DRAWN;
// int start = 0;
bool componentIsWholeCycle = false;
QS_DEF(Array<bool>, _is_component_touch);
_is_component_touch.clear_resize(_layout_component_count);
for (int index = 0; index < size; index++)
if (need_to_insert[index])
{
// 1. search of connected component
QS_DEF(Array<int>, insideVertex);
insideVertex.clear_resize(0);
insideVertex.push(cycle.getVertex(index));
QS_DEF(Array<bool>, takenVertex);
takenVertex.clear_resize(vertexCount());
takenVertex.zerofill();
takenVertex[cycle.getVertex(index)] = true;
_is_component_touch.zerofill();
for (int i = 0; i < insideVertex.size(); i++)
for (int j = getVertex(insideVertex[i]).neiBegin(); j != getVertex(insideVertex[i]).neiEnd(); j = getVertex(insideVertex[i]).neiNext(j))
{
int vertj = getVertex(insideVertex[i]).neiVertex(j);
if (_layout_edges[getVertex(insideVertex[i]).neiEdge(j)].type != ELEMENT_NOT_DRAWN && !takenVertex[vertj])
{
_is_component_touch[_layout_component_number[getVertex(insideVertex[i]).neiEdge(j)]] = true;
insideVertex.push(vertj);
takenVertex[vertj] = true;
}
}
if (!componentIsWholeCycle)
{
componentIsWholeCycle = true;
for (int i = 0; i < size; i++)
componentIsWholeCycle &= takenVertex[cycle.getVertex(i)];
}
for (int i = 0; i < size; i++)
if (takenVertex[cycle.getVertex(i)])
need_to_insert[i] = false;
if (componentIsWholeCycle)
break;
int startIndex = index;
int endIndex = index;
while (takenVertex[cycle.getVertex(startIndex)])
startIndex = (startIndex - 1 + size) % size;
startIndex = (startIndex + 1) % size;
while (takenVertex[cycle.getVertex(endIndex)])
endIndex = (endIndex + 1) % size;
// 2. flip
bool need_to_flip = false;
float rotate1 = Vec2f::cross(layout.getPos((startIndex + 1) % size) - layout.getPos(startIndex),
layout.getPos((startIndex + 2) % size) - layout.getPos((startIndex + 1) % size));
if (isEdgeDrawn(cycle.getEdgeC(startIndex + 1)))
{
float rotate2 = Vec2f::cross(getPos(cycle.getVertexC(startIndex + 1)) - getPos(cycle.getVertexC(startIndex)),
getPos(cycle.getVertexC(startIndex + 2)) - getPos(cycle.getVertexC(startIndex + 1)));
if (isEdgeDrawn(cycle.getEdgeC(startIndex)))
need_to_flip = rotate1 * rotate2 < 0;
}
else
{
float rotate1_next = rotate1;
float rotate1_prev = Vec2f::cross(layout.getPos(startIndex) - layout.getPos((startIndex - 1 + size) % size),
layout.getPos((startIndex + 1) % size) - layout.getPos(startIndex));
int do_flip_cnt = 0;
int dont_flip_cnt = 0;
int ind0 = cycle.getVertexC(startIndex);
int ind1 = cycle.getVertexC(startIndex + 1);
const Vertex& v0 = getVertex(ind0);
const Vertex& v1 = getVertex(ind1);
for (int j = v0.neiBegin(); j != v0.neiEnd(); j = v0.neiNext(j))
if (v0.neiVertex(j) != ind1 && isEdgeDrawn(v0.neiEdge(j)))
{
float current_rotate = Vec2f::cross(getPos(ind0) - getPos(v0.neiVertex(j)), getPos(ind1) - getPos(ind0));
if (current_rotate * rotate1_prev > 0)
do_flip_cnt++;
else
dont_flip_cnt++;
}
for (int j = v1.neiBegin(); j != v1.neiEnd(); j = v1.neiNext(j))
if (v1.neiVertex(j) != ind0 && isEdgeDrawn(v1.neiEdge(j)))
{
float current_rotate = Vec2f::cross(getPos(ind1) - getPos(ind0), getPos(v1.neiVertex(j)) - getPos(ind1));
if (current_rotate * rotate1_next > 0)
do_flip_cnt++;
else
dont_flip_cnt++;
}
need_to_flip = do_flip_cnt > dont_flip_cnt;
}
/*float rotate1 = Vec2f::cross(layout.getPos((startIndex + 1) % size) - layout.getPos(startIndex), layout.getPos((startIndex + 2) % size) -
layout.getPos((startIndex + 1) % size)); Vec2f next_point; if (isEdgeDrawn(cycle.getEdgeC(startIndex + 1))) next_point =
getPos(cycle.getVertexC(startIndex + 2)); else { for (int j = getVertex(cycle.getVertexC(startIndex + 1)).neiBegin(); j !=
getVertex(cycle.getVertexC(startIndex + 1)).neiEnd(); j = getVertex(cycle.getVertexC(startIndex + 1)).neiNext(j)) if
(isEdgeDrawn(getVertex(cycle.getVertexC(startIndex + 1)).neiEdge(j)) && getVertex(cycle.getVertexC(startIndex + 1)).neiVertex(j) !=
cycle.getVertex(startIndex)) next_point = _layout_vertices[getVertex(cycle.getVertexC(startIndex + 1)).neiVertex(j)].pos;
}
float rotate2 = Vec2f::cross(getPos(cycle.getVertexC(startIndex + 1)) - getPos(cycle.getVertexC(startIndex)),
next_point - getPos(cycle.getVertexC(startIndex + 1)));
if (!isEdgeDrawn(cycle.getEdgeC(startIndex + 1))) {
need_to_flip = rotate1 * rotate2 > 0;
}
else if (isEdgeDrawn(cycle.getEdgeC(startIndex))) need_to_flip = rotate1 * rotate2 < 0;
*/
if (need_to_flip)
{
for (int i = 0; i < insideVertex.size(); i++)
getPos(insideVertex[i]).x *= -1;
for (int i = 0; i < segment.size(); i++)
if (segment[i].get_layout_component_number() >= 0 && _is_component_touch[segment[i].get_layout_component_number()])
segment[i].inverse();
}
// 3. shift
Vec2f middle_host;
Vec2f middle_new;
int countVertex = 0;
for (int i = startIndex; i != endIndex; i = (i + 1) % size)
{
middle_host += _layout_vertices[cycle.getVertex(i)].pos;
middle_new += layout.getPos(i);
countVertex++;
}
middle_host /= _2FLOAT(countVertex);
middle_new /= _2FLOAT(countVertex);
for (int i = 0; i < insideVertex.size(); i++)
_layout_vertices[insideVertex[i]].pos += middle_new - middle_host;
// 4. rotate
Vec2f direction_host;
Vec2f direction_new;
if (countVertex > 1)
{
int currentIndex = 0;
for (int i = startIndex; i != endIndex; i = (i + 1) % size)
{
if (2 * currentIndex < countVertex - 1)
{
direction_host += _layout_vertices[cycle.getVertex(i)].pos;
direction_new += layout.getPos(i);
}
else if (2 * currentIndex > countVertex - 1)
{
direction_host -= _layout_vertices[cycle.getVertex(i)].pos;
direction_new -= layout.getPos(i);
}
currentIndex++;
}
float dot = Vec2f::dot(direction_host, direction_new) / (direction_host.length() * direction_new.length());
if (dot > 1)
dot = 1;
if (dot < -1)
dot = -1;
float angle = acos(dot);
if (Vec2f::cross(direction_host, direction_new) < 0)
angle = -angle;
for (int i = 0; i < insideVertex.size(); i++)
_layout_vertices[insideVertex[i]].pos.rotateAroundSegmentEnd(_layout_vertices[insideVertex[i]].pos, middle_new, angle);
}
}
for (int i = 0; i < size; i++)
if (getVertexType(cycle.getVertex(i)) == ELEMENT_NOT_DRAWN)
getPos(cycle.getVertex(i)) = layout.getPos(i);
for (int i = 0; i < size; i++)
{
setVertexType(cycle.getVertex(i), ELEMENT_DRAWN);
setEdgeType(cycle.getEdge(i), ELEMENT_DRAWN);
}
// 5. smoothing
for (int e = edgeBegin(); e != edgeEnd(); e = edgeNext(e))
if (_layout_component_number[e] >= 0 && _is_layout_component_incoming[_layout_component_number[e]])
_layout_component_number[e] = _layout_component_count - 1;
_segment_smoothing(cycle, layout, rotation_vertex, rotation_point, segment);
}