core/indigo-core/layout/patmake/patmake.cpp (246 lines of code) (raw):
/****************************************************************************
* Copyright (C) from 2009 to Present EPAM Systems.
*
* This file is part of Indigo toolkit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include "base_cpp/output.h"
#include "base_cpp/scanner.h"
#include "graph/biconnected_decomposer.h"
#include "molecule/molecule.h"
#include "molecule/molfile_loader.h"
int edge_cmp(const int& e1, const int& e2, const void* context)
{
Molecule& mol = *(Molecule*)context;
const Edge& edge1 = mol.getEdge(e1);
const Edge& edge2 = mol.getEdge(e2);
Vec3f v1 = mol.getAtomPos(edge1.beg);
Vec3f v2 = mol.getAtomPos(edge1.end);
v1.z = 0.f;
v2.z = 0.f;
float len1 = Vec3f::dist(v1, v2);
v1 = mol.getAtomPos(edge2.beg);
v2 = mol.getAtomPos(edge2.end);
v1.z = 0.f;
v2.z = 0.f;
float len2 = Vec3f::dist(v1, v2);
if (len2 > len1)
return 1;
else if (len2 < len1)
return -1;
return 0;
}
bool edge_intersection(const Molecule& mol, int edge1_idx, int edge2_idx, Vec2f& p)
{
const Edge& edge1 = mol.getEdge(edge1_idx);
const Edge& edge2 = mol.getEdge(edge2_idx);
if (edge1.beg == edge2.beg || edge1.beg == edge2.end || edge1.end == edge2.beg || edge1.end == edge2.end)
return false;
Vec2f v1_1(mol.getAtomPos(edge1.beg).x, mol.getAtomPos(edge1.beg).y);
Vec2f v1_2(mol.getAtomPos(edge1.end).x, mol.getAtomPos(edge1.end).y);
Vec2f v2_1(mol.getAtomPos(edge2.beg).x, mol.getAtomPos(edge2.beg).y);
Vec2f v2_2(mol.getAtomPos(edge2.end).x, mol.getAtomPos(edge2.end).y);
return Vec2f::intersection(v1_1, v1_2, v2_1, v2_2, p);
}
void convertMolfile(char* path, char* filename, FileOutput& cpp_file)
{
FileScanner molfile("%s\\%s", path, filename);
MolfileLoader mf_loader(molfile);
Molecule mol;
QS_DEF(Array<int>, edges);
printf("%s\n", filename);
mf_loader.loadMolecule(mol, true);
BiconnectedDecomposer bd(mol);
if (bd.decompose() != 1)
{
printf("Error: %s is not biconnected\n", filename);
return;
}
int i, j;
edges.clear_reserve(mol.edgeCount());
for (i = mol.edgeBegin(); i < mol.edgeEnd(); i = mol.edgeNext(i))
edges.push(i);
edges.qsort(edge_cmp, &mol);
const Edge& edge = mol.getEdge(edges[edges.size() / 2]);
Vec3f v1 = mol.getAtomPos(edge.beg);
Vec3f v2 = mol.getAtomPos(edge.end);
v1.z = 0.f;
v2.z = 0.f;
float scale = Vec3f::dist(v1, v2);
if (scale < 0.0001f)
{
printf("Error: %s has zero bond\n", filename);
return;
}
scale = 1.f / scale;
int first_idx = mol.vertexBegin();
Vec3f pos = mol.getAtomPos(first_idx);
for (i = mol.vertexNext(first_idx); i < mol.vertexEnd(); i = mol.vertexNext(i))
{
if (mol.getAtomPos(i).y < pos.y)
{
pos = mol.getAtomPos(i);
first_idx = i;
}
}
for (i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
{
mol.getAtom2(i).pos.sub(pos);
mol.getAtom2(i).pos.scale(scale);
}
char buf[1024];
sprintf_s(buf, "BEGIN_PATTERN(\"%s\")", filename);
cpp_file.writeStringCR(buf);
for (i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
{
sprintf_s(buf, " ADD_ATOM(%d, %ff, %ff)", i, mol.getAtomPos(i).x, mol.getAtomPos(i).y);
cpp_file.writeStringCR(buf);
}
for (i = mol.edgeBegin(); i < mol.edgeEnd(); i = mol.edgeNext(i))
{
const Edge& edge = mol.getEdge(i);
int type = mol.getBond(i).type;
int qtype = mol.getQueryBond(i).type;
sprintf_s(buf, " ADD_BOND(%d, %d, %d)", edge.beg, edge.end, qtype != 0 ? qtype : type);
cpp_file.writeStringCR(buf);
}
Vec2f v, inter;
Vec2f pos_i;
int idx = mol.vertexCount();
i = first_idx;
float max_angle, cur_angle;
float i_angle = 0;
int next_nei = 0;
int point_idx = 0;
pos_i.set(mol.getAtomPos(i).x, mol.getAtomPos(i).y);
while (true)
{
const Vertex& vert = mol.getVertex(i);
if (i != first_idx)
{
v.set(pos_i.x, pos_i.y);
pos_i.set(mol.getAtomPos(i).x, mol.getAtomPos(i).y);
v.sub(pos_i);
i_angle = v.tiltAngle2();
}
else if (point_idx > 0)
break;
sprintf_s(buf, " OUTLINE_POINT(%d, %ff, %ff)", point_idx++, pos_i.x, pos_i.y);
cpp_file.writeStringCR(buf);
max_angle = 0.f;
for (j = vert.neiBegin(); j < vert.neiEnd(); j = vert.neiNext(j))
{
const Vec3f& pos_nei = mol.getAtomPos(vert.neiVertex(j));
v.set(pos_nei.x - pos_i.x, pos_nei.y - pos_i.y);
cur_angle = v.tiltAngle2() - i_angle;
if (cur_angle < 0.f)
cur_angle += 2 * M_PI;
if (max_angle < cur_angle)
{
max_angle = cur_angle;
next_nei = j;
}
}
i = vert.neiVertex(next_nei);
float dist, min_dist = 0.f;
int int_edge;
Vec2f cur_v1 = pos_i;
Vec2f cur_v2(mol.getAtomPos(i).x, mol.getAtomPos(i).y);
while (min_dist < 10000.f)
{
min_dist = 10001.f;
for (j = mol.edgeBegin(); j < mol.edgeEnd(); j = mol.edgeNext(j))
{
const Edge& edge = mol.getEdge(j);
Vec2f cur_v3(mol.getAtomPos(edge.beg).x, mol.getAtomPos(edge.beg).y);
Vec2f cur_v4(mol.getAtomPos(edge.end).x, mol.getAtomPos(edge.end).y);
if (Vec2f::intersection(cur_v1, cur_v2, cur_v3, cur_v4, v))
if ((dist = Vec2f::dist(cur_v1, v)) < min_dist)
{
inter = v;
min_dist = dist;
int_edge = j;
}
}
if (min_dist < 10000.f)
{
sprintf_s(buf, " OUTLINE_POINT(%d, %ff, %ff)", point_idx++, v.x, v.y);
cpp_file.writeStringCR(buf);
const Edge& edge = mol.getEdge(int_edge);
Vec2f cur_v3(mol.getAtomPos(edge.beg).x, mol.getAtomPos(edge.beg).y);
Vec2f cur_v4(mol.getAtomPos(edge.end).x, mol.getAtomPos(edge.end).y);
Vec2f cur_v1v;
Vec2f cur_v3v;
Vec2f cur_v4v;
cur_v1v.diff(cur_v1, inter);
cur_v3v.diff(cur_v3, inter);
cur_v4v.diff(cur_v4, inter);
float angle1 = cur_v1v.tiltAngle2();
float angle3 = cur_v3v.tiltAngle2() - angle1;
float angle4 = cur_v4v.tiltAngle2() - angle1;
if (angle3 < 0)
angle3 += 2 * M_PI;
if (angle4 < 0)
angle4 += 2 * M_PI;
cur_v1 = inter;
if (angle3 > angle4)
{
cur_v2 = cur_v3;
i = edge.beg;
}
else
{
cur_v2 = cur_v4;
i = edge.end;
}
}
}
}
cpp_file.writeStringCR("END_PATTERN()");
}
#include <windows.h>
void main(int argc, char* argv[])
{
WIN32_FIND_DATAA ffd;
HANDLE h_find;
char file_pattern[MAX_PATH];
if (argc != 3)
{
printf("patmake.exe <mol-root> <cpp-output>");
return;
}
if (argv[1][strlen(argv[1]) - 1] == '\\')
argv[1][strlen(argv[1]) - 1] = 0;
sprintf_s(file_pattern, "%s\\*.mol", argv[1]);
h_find = FindFirstFileA(file_pattern, &ffd);
if (h_find == INVALID_HANDLE_VALUE)
{
printf("FindFirstFile failed (%d)\n", GetLastError());
return;
}
else
{
try
{
FileOutput cpp_file(true, argv[2]);
SYSTEMTIME st;
GetSystemTime(&st);
char buf[200];
sprintf_s(buf, " * Added %02d/%02d/%02d %02d:%02d:%02d", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond);
cpp_file.writeStringCR("/*");
cpp_file.writeStringCR(buf);
cpp_file.writeStringCR(" */");
do
{
try
{
convertMolfile(argv[1], ffd.cFileName, cpp_file);
}
catch (Exception& e)
{
printf("Error: %s\n", e.message());
}
} while (FindNextFileA(h_find, &ffd) != 0);
printf("Done.\n");
}
catch (Exception& e)
{
printf("Error: %s\n", e.message());
}
FindClose(h_find);
}
}