001/*
002 *   Entity102_CompositeCurve  -- Entity that represents a composite curve made up of other curve segments.
003 *
004 *   Copyright (C) 2011-2025, Joseph A. Huwaldt. All rights reserved.
005 *   
006 *   This library is free software; you can redistribute it and/or
007 *   modify it under the terms of the GNU Lesser General Public
008 *   License as published by the Free Software Foundation; either
009 *   version 2.1 of the License, or (at your option) any later version.
010 *   
011 *   This library is distributed in the hope that it will be useful,
012 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *   Lesser General Public License for more details.
015 *
016 *   You should have received a copy of the GNU Lesser General Public License
017 *   along with this program; if not, write to the Free Software
018 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
019 *   Or visit:  http://www.gnu.org/licenses/lgpl.html
020 *
021 *   Based on, but heavily modified from, IGESView ( http://ts.nist.gov/Standards/IGES/igesTools.cfm )
022 */
023package geomss.geom.reader.iges;
024
025import geomss.geom.*;
026import geomss.geom.nurbs.CurveUtils;
027import geomss.geom.nurbs.NurbsCurve;
028import jahuwaldt.js.param.Parameter;
029import java.io.IOException;
030import java.io.PrintWriter;
031import java.io.RandomAccessFile;
032import java.util.ArrayList;
033import java.util.List;
034import javax.measure.quantity.Length;
035
036/**
037 * <b><i>COMPOSITE CURVE ENTITY</i></b> - This entity defines an associativity
038 * relationship between an ordered list of curve segments. A composite curve is defined as
039 * an ordered list of entities consisting of a point, connect point and parameterized
040 * curve entities.
041 * 
042 * <p>
043 * This entity, when read from an IGES file, is converted to a single NurbsCurve with the
044 * original segments stored in the list "IGES_102_CCSegs" in the user data of the curve.
045 * This entity type can be written out to an IGES file.</p>
046 *
047 * <p> Modified by: Joseph A. Huwaldt </p>
048 * 
049 * @author Joseph A. Huwaldt, Date: November 16, 2011
050 * @version February 22, 2025
051 */
052public class Entity102_CompositeCurve extends GeomSSEntity {
053
054    protected List<Integer> pointers = new ArrayList();     //  List of entity DE numbers.
055
056    private NurbsCurve curve = null;                        //  The NURBS curve that will represent the composit curve.
057
058    /**
059     * Default constructor.
060     *
061     * @param p  part to which this entity is contained
062     * @param de Directory Entry for this entity
063     */
064    public Entity102_CompositeCurve(Part p, DirEntry de) {
065        super(p, de);
066
067        if (Constants.DEBUG) {
068            System.out.println("Entity102 constructor called");
069        }
070    }
071
072    /**
073     * Create this entity from the specified list of pointers to the curve segment DEs.
074     *
075     * @param part      The Part to which this entity is contained.
076     * @param DEnum     The line count from the start of the Directory Entry Section for
077     *                  this entry (odd number).
078     * @param name      The GeomSS name for this entity or <code>null</code> for none.
079     * @param segDEPtrs A list of pointers to the DE each segment of the curve in order
080     *                  from start to end.
081     */
082    public Entity102_CompositeCurve(Part part, int DEnum, String name, List<Integer> segDEPtrs) {
083        super(part, new DirEntry(102, 0, DEnum, 0, name));
084
085        pointers.addAll(segDEPtrs);
086    }
087
088    /**
089     * Checks to see if the entity is correct. No restrictions are imposed.
090     */
091    @Override
092    public void check() { }
093
094    /**
095     * Read the Parameter Data from the String read in by the superclass.
096     *
097     * @param in input file
098     * @throws java.io.IOException if the parameter could not be read in.
099     */
100    @Override
101    public void read(RandomAccessFile in) throws IOException {
102        super.read(in);
103        String s = getPDString();
104
105        if (Constants.DEBUG) {
106            System.out.println("PD String = \"" + s + "\"");
107        }
108
109        int n = getInt(s);
110        for (int i = 0; i < n; ++i)
111            pointers.add(getInt(s));
112
113        super.read_additional();
114    }
115
116    /**
117     * The GeomSS geometry element is created from the IGES parameters when this method is
118     * called.
119     */
120    @Override
121    void createGeometry() {
122        Part part = getPart();
123
124        //  Loop over all the entities in this association.
125        GeomList<GeomElement> geom = GeomList.newInstance();
126        int n = pointers.size();
127        for (int i = 0; i < n; ++i) {
128            int deNum = pointers.get(i);
129            Entity entity = part.getEntity(deNum);
130
131            if (entity instanceof GeomSSEntity) {
132                //  Found a GeomSS geometry Entity.
133                GeomSSEntity geomEntity = (GeomSSEntity)entity;
134                geomEntity.setUsedInList(true); //  Indicate that the entity is used by this association.
135                GeomElement element = geomEntity.getGeomElement(GTransform.IDENTITY);
136                geom.add(element);
137            }
138        }
139
140        //  Convert all the non-degenerate elements into NURBS curves.
141        Parameter<Length> tol = Parameter.valueOf(Constants.Grain, Constants.unit);
142        GeomList<NurbsCurve> crvSegs = convert2NurbsSegs(geom, tol);
143
144        //  Concatentate all the curve segments together.
145        curve = CurveUtils.connectCurves(crvSegs);
146        GeomList.recycle(crvSegs);
147
148        //  TODO:  Remove unnecessary knots to return the minimal curve that matches the original.
149        curve.putUserData("IGES_102_CCSegs", geom);
150
151    }
152
153    /**
154     * Converts all the non-degenerate Curve elements in the specified geometry list into
155     * NurbsCurves.
156     *
157     * @param crvs The list of geometry elements to be converted.
158     * @param tol  The tolerance for the conversion to NURBS curves.
159     * @return A list of non-degenerate NURBS curve versions of each element in "crvs".
160     */
161    private GeomList<NurbsCurve> convert2NurbsSegs(GeomList<GeomElement> crvs, Parameter<Length> tol) {
162        GeomList<NurbsCurve> nurbsSegs = GeomList.newInstance();
163        for (GeomElement elem : crvs) {
164            if (elem instanceof Curve) {
165                NurbsCurve nurbs = ((Curve)elem).toNurbs(tol);
166                if (!nurbs.isDegenerate(tol))
167                    nurbsSegs.add(nurbs);
168            }
169        }
170        return nurbsSegs;
171    }
172
173    /**
174     * Return a reference to the Transformable GeomElement contained in this IGES Entity.
175     *
176     * @return A reference to the Transformable GeomElement contained in this IGES Entity.
177     */
178    @Override
179    protected Transformable getGeomElement() {
180        return curve;
181    }
182
183    /**
184     * Returns <code>true</code> if the Entity can be written to an exchange file.
185     *
186     * @return true
187     */
188    @Override
189    public boolean canWrite() {
190        return true;
191    }
192
193    /**
194     * Write this entity object's parameter data to the specified PrintWriter.
195     *
196     * @param writer The PrintWriter to write the parameter data for this entity to.
197     * @param PDnum  The starting Parameter Data row index number.
198     * @return The Parameter Data row index number for the next row.
199     * @throws java.io.IOException if the parameter data could not be written.
200     */
201    @Override
202    public int write(PrintWriter writer, int PDnum) throws IOException {
203        int numSegs = pointers.size();
204
205        //  Build up the parameter data string.
206        StringBuilder buffer = new StringBuilder();
207        buffer.append(102);             buffer.append(Constants.Delim);
208        buffer.append(numSegs);         buffer.append(Constants.Delim);
209        buffer.append(pointers.get(0));
210        for (int i = 1; i < numSegs; ++i) {
211            buffer.append(Constants.Delim);
212            buffer.append(pointers.get(i));
213        }
214        buffer.append(Constants.Term);
215
216        //  Write it out.
217        int oldPDnum = PDnum;
218        PDnum = Constants.writeSection(writer, PDnum, Constants.makeSequenceNumber(getDENum()),
219                'P', buffer);
220
221        //  Store the PD line number and line count in the directory entry.
222        getDirectoryEntry().setPDNumber(oldPDnum, PDnum - oldPDnum);
223
224        return PDnum;
225    }
226
227    /**
228     * Dump to String.
229     *
230     * @return String containing the resulting text.
231     */
232    @Override
233    public String toString() {
234        StringBuilder outStr = new StringBuilder(super.toString());
235        outStr.append("\n");
236
237        int n = pointers.size();
238        outStr.append("n  = "); outStr.append(n);   outStr.append("\n");
239
240        for (int i = 0; i < n; i++) {
241            outStr.append("curve(");
242            outStr.append(i);
243            outStr.append(") = ");
244            outStr.append(pointers.get(i));
245            outStr.append("\n");
246        }
247
248        return outStr.toString();
249    }
250
251    /**
252     * Returns a short String describing this Entity object's type.
253     *
254     * @return A short String describing this Entity object's type.
255     */
256    @Override
257    public String getTypeString() {
258        return "Entity102 - Composite Curve";
259    }
260
261}